From e18777c7582d54d227714882e9e79746ce48e002 Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Tue, 5 Oct 2021 09:11:33 +0000 Subject: [PATCH] Refactor the OpenSSL DH usage to use newer APIs OpenSSL 3 deprecates most of the DH* 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/openssldh_link.c | 806 +++++++++++++++++++++++++++++++++------ 1 file changed, 697 insertions(+), 109 deletions(-) diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index 5d2f8b22d7..3703057b17 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -29,7 +29,17 @@ #include #include +#include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif +#include +#include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif +#include #include #include @@ -66,17 +76,30 @@ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" +#define DST_RET(a) \ + { \ + ret = a; \ + goto err; \ + } + static BIGNUM *bn2 = NULL, *bn768 = NULL, *bn1024 = NULL, *bn1536 = NULL; static isc_result_t openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, isc_buffer_t *secret) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dhpub, *dhpriv; const BIGNUM *pub_key = NULL; - int ret; + int secret_len = 0; +#else + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *dhpub, *dhpriv; + size_t secret_len = 0; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ isc_region_t r; unsigned int len; +#if OPENSSL_VERSION_NUMBER < 0x30000000L REQUIRE(pub->keydata.dh != NULL); REQUIRE(priv->keydata.dh != NULL); @@ -84,28 +107,73 @@ openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, dhpriv = priv->keydata.dh; len = DH_size(dhpriv); +#else + REQUIRE(pub->keydata.pkey != NULL); + REQUIRE(priv->keydata.pkey != NULL); + + dhpub = pub->keydata.pkey; + dhpriv = priv->keydata.pkey; + + len = EVP_PKEY_get_size(dhpriv); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + isc_buffer_availableregion(secret, &r); if (r.length < len) { return (ISC_R_NOSPACE); } +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH_get0_key(dhpub, &pub_key, NULL); - ret = DH_compute_key(r.base, pub_key, dhpriv); - if (ret <= 0) { + secret_len = DH_compute_key(r.base, pub_key, dhpriv); + if (secret_len <= 0) { return (dst__openssl_toresult2("DH_compute_key", DST_R_COMPUTESECRETFAILURE)); } - isc_buffer_add(secret, len); +#else + ctx = EVP_PKEY_CTX_new_from_pkey(NULL, dhpriv, NULL); + if (ctx == NULL) { + return (dst__openssl_toresult2("EVP_PKEY_CTX_new_from_pkey", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_derive_init(ctx) != 1) { + EVP_PKEY_CTX_free(ctx); + return (dst__openssl_toresult2("EVP_PKEY_derive_init", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_derive_set_peer(ctx, dhpub) != 1) { + EVP_PKEY_CTX_free(ctx); + return (dst__openssl_toresult2("EVP_PKEY_derive_set_peer", + DST_R_OPENSSLFAILURE)); + } + secret_len = r.length; + if (EVP_PKEY_derive(ctx, r.base, &secret_len) != 1 || secret_len == 0) { + EVP_PKEY_CTX_free(ctx); + return (dst__openssl_toresult2("EVP_PKEY_derive", + DST_R_COMPUTESECRETFAILURE)); + } + EVP_PKEY_CTX_free(ctx); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + + isc_buffer_add(secret, (unsigned int)secret_len); + return (ISC_R_SUCCESS); } static bool openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh1, *dh2; const BIGNUM *pub_key1 = NULL, *pub_key2 = NULL; const BIGNUM *priv_key1 = NULL, *priv_key2 = NULL; const BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL; +#else + EVP_PKEY *pkey1, *pkey2; + BIGNUM *pub_key1 = NULL, *pub_key2 = NULL; + BIGNUM *priv_key1 = NULL, *priv_key2 = NULL; + BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L dh1 = key1->keydata.dh; dh2 = key2->keydata.dh; @@ -119,6 +187,25 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { DH_get0_key(dh2, &pub_key2, &priv_key2); DH_get0_pqg(dh1, &p1, NULL, &g1); DH_get0_pqg(dh2, &p2, NULL, &g2); +#else + pkey1 = key1->keydata.pkey; + pkey2 = key2->keydata.pkey; + + if (pkey1 == NULL && pkey2 == NULL) { + return (true); + } else if (pkey1 == NULL || pkey2 == NULL) { + return (false); + } + + EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_FFC_P, &p1); + EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_FFC_P, &p2); + EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_FFC_G, &g1); + EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_FFC_G, &g2); + EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_PUB_KEY, &pub_key1); + EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_PUB_KEY, &pub_key2); + EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key1); + EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key2); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L*/ if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0 || BN_cmp(pub_key1, pub_key2) != 0) @@ -134,14 +221,48 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { return (false); } } + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (p1 != NULL) { + BN_free(p1); + } + if (p2 != NULL) { + BN_free(p2); + } + if (g1 != NULL) { + BN_free(g1); + } + if (g2 != NULL) { + BN_free(g2); + } + if (pub_key1 != NULL) { + BN_free(pub_key1); + } + if (pub_key2 != NULL) { + BN_free(pub_key2); + } + if (priv_key1 != NULL) { + BN_clear_free(priv_key1); + } + if (priv_key2 != NULL) { + BN_clear_free(priv_key2); + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return (true); } static bool openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh1, *dh2; const BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL; +#else + EVP_PKEY *pkey1, *pkey2; + BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L dh1 = key1->keydata.dh; dh2 = key2->keydata.dh; @@ -153,13 +274,45 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { DH_get0_pqg(dh1, &p1, NULL, &g1); DH_get0_pqg(dh2, &p2, NULL, &g2); +#else + pkey1 = key1->keydata.pkey; + pkey2 = key2->keydata.pkey; + + if (pkey1 == NULL && pkey2 == NULL) { + return (true); + } else if (pkey1 == NULL || pkey2 == NULL) { + return (false); + } + + EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_FFC_P, &p1); + EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_FFC_P, &p2); + EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_FFC_G, &g1); + EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_FFC_G, &g2); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0) { return (false); } + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (p1 != NULL) { + BN_free(p1); + } + if (p2 != NULL) { + BN_free(p2); + } + if (g1 != NULL) { + BN_free(g1); + } + if (g2 != NULL) { + BN_free(g2); + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return (true); } +#if OPENSSL_VERSION_NUMBER < 0x30000000L static int progress_cb(int p, int n, BN_GENCB *cb) { union { @@ -175,25 +328,70 @@ progress_cb(int p, int n, BN_GENCB *cb) { } return (1); } - -static isc_result_t -openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) { - DH *dh = NULL; - BN_GENCB *cb; -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - BN_GENCB _cb; -#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - * defined(LIBRESSL_VERSION_NUMBER) */ +#else +static int +progress_cb(EVP_PKEY_CTX *ctx) { union { void *dptr; void (*fptr)(int); } u; + u.dptr = EVP_PKEY_CTX_get_app_data(ctx); + if (u.fptr != NULL) { + int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + u.fptr(p); + } + return (1); +} +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + +static isc_result_t +openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) { + isc_result_t ret; + union { + void *dptr; + void (*fptr)(int); + } u; + BIGNUM *p = NULL, *g = NULL; +#if OPENSSL_VERSION_NUMBER < 0x30000000L + DH *dh = NULL; + BN_GENCB *cb = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + BN_GENCB _cb; +#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + * defined(LIBRESSL_VERSION_NUMBER) */ +#else + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *param_ctx = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *param_pkey = NULL; + EVP_PKEY *pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + +#if OPENSSL_VERSION_NUMBER < 0x30000000L + dh = DH_new(); + if (dh == NULL) { + DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); + } +#else + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + param_ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (param_ctx == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + if (generator == 0) { + /* + * When `generator` is 0, we have three pre-computed `p` and `g` + * static parameters which we can use. + */ if (key->key_size == 768 || key->key_size == 1024 || key->key_size == 1536) { - BIGNUM *p, *g; - dh = DH_new(); if (key->key_size == 768) { p = BN_dup(bn768); } else if (key->key_size == 1024) { @@ -202,34 +400,51 @@ openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) { p = BN_dup(bn1536); } g = BN_dup(bn2); - if (dh == NULL || p == NULL || g == NULL) { - if (dh != NULL) { - DH_free(dh); - } - if (p != NULL) { - BN_free(p); - } - if (g != NULL) { - BN_free(g); - } - return (dst__openssl_toresult(ISC_R_NOMEMORY)); + if (p == NULL || g == NULL) { + DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); } - DH_set0_pqg(dh, p, NULL, g); +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (DH_set0_pqg(dh, p, NULL, g) != 1) { + DST_RET(dst__openssl_toresult2( + "DH_set0_pqg", DST_R_OPENSSLFAILURE)); + } +#else + if (OSSL_PARAM_BLD_push_uint(bld, + OSSL_PKEY_PARAM_FFC_PBITS, + key->key_size) != 1) + { + DST_RET(dst__openssl_toresult2( + "OSSL_PARAM_BLD_push_uint", + DST_R_OPENSSLFAILURE)); + } + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, + p) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, + g) != 1) + { + DST_RET(dst__openssl_toresult2( + "OSSL_PARAM_BLD_push_BN", + DST_R_OPENSSLFAILURE)); + } + params = OSSL_PARAM_BLD_to_param(bld); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + } else { + /* + * If the requested size is not present in our + * pre-computed set, we will use `generator` 2 to + * generate new parameters. + */ generator = 2; } } if (generator != 0) { - dh = DH_new(); - if (dh == NULL) { - return (dst__openssl_toresult(ISC_R_NOMEMORY)); - } +#if OPENSSL_VERSION_NUMBER < 0x30000000L cb = BN_GENCB_new(); #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) if (cb == NULL) { - DH_free(dh); - return (dst__openssl_toresult(ISC_R_NOMEMORY)); + DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); } #endif /* if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ * !defined(LIBRESSL_VERSION_NUMBER) */ @@ -242,38 +457,178 @@ openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) { if (!DH_generate_parameters_ex(dh, key->key_size, generator, cb)) { - DH_free(dh); - BN_GENCB_free(cb); - return (dst__openssl_toresult2("DH_generate_parameters_" + DST_RET(dst__openssl_toresult2("DH_generate_parameters_" "ex", DST_R_OPENSSLFAILURE)); } - BN_GENCB_free(cb); - cb = NULL; +#else + if (OSSL_PARAM_BLD_push_int(bld, OSSL_PKEY_PARAM_DH_GENERATOR, + generator) != 1) { + DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" + "int", + DST_R_OPENSSLFAILURE)); + } + if (OSSL_PARAM_BLD_push_utf8_string( + bld, OSSL_PKEY_PARAM_FFC_TYPE, "generator", 0) != 1) + { + DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" + "utf8_string", + DST_R_OPENSSLFAILURE)); + } + if (OSSL_PARAM_BLD_push_uint(bld, OSSL_PKEY_PARAM_FFC_PBITS, + key->key_size) != 1) + { + DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" + "uint", + DST_R_OPENSSLFAILURE)); + } + params = OSSL_PARAM_BLD_to_param(bld); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ } +#if OPENSSL_VERSION_NUMBER < 0x30000000L if (DH_generate_key(dh) == 0) { - DH_free(dh); - return (dst__openssl_toresult2("DH_generate_key", + DST_RET(dst__openssl_toresult2("DH_generate_key", DST_R_OPENSSLFAILURE)); } DH_clear_flags(dh, DH_FLAG_CACHE_MONT_P); key->keydata.dh = dh; + dh = NULL; +#else + if (params == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } - return (ISC_R_SUCCESS); + if (generator == 0) { + if (EVP_PKEY_fromdata_init(param_ctx) != 1) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata_init", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_fromdata(param_ctx, ¶m_pkey, + OSSL_KEYMGMT_SELECT_ALL, params) != 1 || + param_pkey == NULL) + { + DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata", + DST_R_OPENSSLFAILURE)); + } + } else { + if (EVP_PKEY_paramgen_init(param_ctx) != 1) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_paramgen_init", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_CTX_set_params(param_ctx, params) != 1) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_" + "params", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_paramgen(param_ctx, ¶m_pkey) != 1 || + param_pkey == NULL) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_paramgen", + DST_R_OPENSSLFAILURE)); + } + } + + /* + * Now `param_pkey` holds the DH parameters (either pre-coumputed or + * newly generated) so we will generate a new public/private key-pair + * using those parameters and put it into `pkey`. + */ + ctx = EVP_PKEY_CTX_new_from_pkey(NULL, param_pkey, NULL); + if (ctx == NULL) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_pkey", + DST_R_OPENSSLFAILURE)); + } + if (callback != NULL) { + u.fptr = callback; + EVP_PKEY_CTX_set_app_data(ctx, u.dptr); + EVP_PKEY_CTX_set_cb(ctx, progress_cb); + } + if (EVP_PKEY_keygen_init(ctx) != 1) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_keygen(ctx, &pkey) != 1 || pkey == NULL) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen", + DST_R_OPENSSLFAILURE)); + } + + key->keydata.pkey = pkey; + pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + + ret = ISC_R_SUCCESS; + +err: +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (dh != NULL) { + DH_free(dh); + } + if (cb != NULL) { + BN_GENCB_free(cb); + } +#else + if (param_pkey != NULL) { + EVP_PKEY_free(param_pkey); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (param_ctx != NULL) { + EVP_PKEY_CTX_free(param_ctx); + } + if (ctx != NULL) { + EVP_PKEY_CTX_free(ctx); + } + if (params != NULL) { + OSSL_PARAM_free(params); + } + if (bld != NULL) { + OSSL_PARAM_BLD_free(bld); + } + if (p != NULL) { + BN_free(p); + } + if (g != NULL) { + BN_free(g); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + + return (ret); } static bool openssldh_isprivate(const dst_key_t *key) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh = key->keydata.dh; const BIGNUM *priv_key = NULL; DH_get0_key(dh, NULL, &priv_key); + return (dh != NULL && priv_key != NULL); +#else + bool ret; + EVP_PKEY *pkey; + BIGNUM *priv_key = NULL; + + pkey = key->keydata.pkey; + if (pkey == NULL) { + return (false); + } + + ret = (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, + &priv_key) == 1 && + priv_key != NULL); + if (priv_key != NULL) { + BN_clear_free(priv_key); + } + + return (ret); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ } static void openssldh_destroy(dst_key_t *key) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh = key->keydata.dh; if (dh == NULL) { @@ -282,6 +637,16 @@ openssldh_destroy(dst_key_t *key) { DH_free(dh); key->keydata.dh = NULL; +#else + EVP_PKEY *pkey = key->keydata.pkey; + + if (pkey == NULL) { + return; + } + + EVP_PKEY_free(pkey); + key->keydata.pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ } static void @@ -307,18 +672,33 @@ uint16_fromregion(isc_region_t *region) { static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh; const BIGNUM *pub_key = NULL, *p = NULL, *g = NULL; +#else + EVP_PKEY *pkey; + BIGNUM *pub_key = NULL, *p = NULL, *g = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ isc_region_t r; uint16_t dnslen, plen, glen, publen; +#if OPENSSL_VERSION_NUMBER < 0x30000000L REQUIRE(key->keydata.dh != NULL); dh = key->keydata.dh; + DH_get0_pqg(dh, &p, NULL, &g); + DH_get0_key(dh, &pub_key, NULL); +#else + REQUIRE(key->keydata.pkey != NULL); + + pkey = key->keydata.pkey; + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ isc_buffer_availableregion(data, &r); - DH_get0_pqg(dh, &p, NULL, &g); if (BN_cmp(g, bn2) == 0 && (BN_cmp(p, bn768) == 0 || BN_cmp(p, bn1024) == 0 || BN_cmp(p, bn1536) == 0)) @@ -329,7 +709,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { plen = BN_num_bytes(p); glen = BN_num_bytes(g); } - DH_get0_key(dh, &pub_key, NULL); + publen = BN_num_bytes(pub_key); dnslen = plen + glen + publen + 6; if (r.length < (unsigned int)dnslen) { @@ -362,13 +742,34 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { isc_buffer_add(data, dnslen); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (p != NULL) { + BN_free(p); + } + if (g != NULL) { + BN_free(g); + } + if (pub_key != NULL) { + BN_free(pub_key); + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return (ISC_R_SUCCESS); } static isc_result_t openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { + isc_result_t ret; +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh; +#else + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ BIGNUM *pub_key = NULL, *p = NULL, *g = NULL; + int key_size; isc_region_t r; uint16_t plen, glen, publen; int special = 0; @@ -378,28 +779,36 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { return (ISC_R_SUCCESS); } +#if OPENSSL_VERSION_NUMBER < 0x30000000L dh = DH_new(); if (dh == NULL) { - return (dst__openssl_toresult(ISC_R_NOMEMORY)); + DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); } DH_clear_flags(dh, DH_FLAG_CACHE_MONT_P); +#else + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (ctx == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ /* * Read the prime length. 1 & 2 are table entries, > 16 means a * prime follows, otherwise an error. */ if (r.length < 2) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } plen = uint16_fromregion(&r); if (plen < 16 && plen != 1 && plen != 2) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } if (r.length < plen) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } if (plen == 1 || plen == 2) { if (plen == 1) { @@ -419,8 +828,7 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { p = BN_dup(bn1536); break; default: - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } } else { p = BN_bin2bn(r.base, plen, NULL); @@ -433,13 +841,11 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { * special, we have a problem. */ if (r.length < 2) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } glen = uint16_fromregion(&r); if (r.length < glen) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } if (special != 0) { if (glen == 0) { @@ -447,46 +853,58 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { } else { g = BN_bin2bn(r.base, glen, NULL); if (g != NULL && BN_cmp(g, bn2) != 0) { - DH_free(dh); - BN_free(g); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } } } else { if (glen == 0) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } g = BN_bin2bn(r.base, glen, NULL); } isc_region_consume(&r, glen); if (p == NULL || g == NULL) { - DH_free(dh); - if (p != NULL) { - BN_free(p); - } - if (g != NULL) { - BN_free(g); - } - return (dst__openssl_toresult(ISC_R_NOMEMORY)); + DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); } - DH_set0_pqg(dh, p, NULL, g); + + key_size = BN_num_bits(p); + +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (DH_set0_pqg(dh, p, NULL, g) != 1) { + DST_RET(dst__openssl_toresult2("DH_set0_pqg", + DST_R_OPENSSLFAILURE)); + } + + /* These are now managed by OpenSSL */ + p = NULL; + g = NULL; +#else + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) != 1) + { + DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", + DST_R_OPENSSLFAILURE)); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ if (r.length < 2) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } publen = uint16_fromregion(&r); if (r.length < publen) { - DH_free(dh); - return (DST_R_INVALIDPUBLICKEY); + DST_RET(DST_R_INVALIDPUBLICKEY); } pub_key = BN_bin2bn(r.base, publen, NULL); if (pub_key == NULL) { - DH_free(dh); - return (dst__openssl_toresult(ISC_R_NOMEMORY)); + DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); } + + isc_region_consume(&r, publen); + + isc_buffer_forward(data, plen + glen + publen + 6); + +#if OPENSSL_VERSION_NUMBER < 0x30000000L #if (LIBRESSL_VERSION_NUMBER >= 0x2070000fL) && \ (LIBRESSL_VERSION_NUMBER <= 0x2070200fL) /* @@ -495,67 +913,141 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { */ dh->pub_key = pub_key; #else /* LIBRESSL_VERSION_NUMBER */ - DH_set0_key(dh, pub_key, NULL); + if (DH_set0_key(dh, pub_key, NULL) != 1) { + DST_RET(dst__openssl_toresult2("DH_set0_key", + DST_R_OPENSSLFAILURE)); + } #endif /* LIBRESSL_VERSION_NUMBER */ - isc_region_consume(&r, publen); - key->key_size = BN_num_bits(p); - - isc_buffer_forward(data, plen + glen + publen + 6); + /* This is now managed by OpenSSL */ + pub_key = NULL; key->keydata.dh = dh; + dh = NULL; +#else + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key) != 1) + { + DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", + DST_R_OPENSSLFAILURE)); + } + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_fromdata_init(ctx) != 1) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata_init", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_fromdata(ctx, &pkey, OSSL_KEYMGMT_SELECT_ALL, params) != + 1 || + pkey == NULL) + { + DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata", + DST_R_OPENSSLFAILURE)); + } - return (ISC_R_SUCCESS); + key->keydata.pkey = pkey; + pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + + key->key_size = (unsigned int)key_size; + + ret = ISC_R_SUCCESS; + +err: +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (dh != NULL) { + DH_free(dh); + } +#else + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (ctx != NULL) { + EVP_PKEY_CTX_free(ctx); + } + if (params != NULL) { + OSSL_PARAM_free(params); + } + if (bld != NULL) { + OSSL_PARAM_BLD_free(bld); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + if (p != NULL) { + BN_free(p); + } + if (g != NULL) { + BN_free(g); + } + if (pub_key != NULL) { + BN_free(pub_key); + } + + return (ret); } static isc_result_t openssldh_tofile(const dst_key_t *key, const char *directory) { - int i; +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh; const BIGNUM *pub_key = NULL, *priv_key = NULL, *p = NULL, *g = NULL; +#else + EVP_PKEY *pkey; + BIGNUM *pub_key = NULL, *priv_key = NULL, *p = NULL, *g = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ dst_private_t priv; - unsigned char *bufs[4]; + unsigned char *bufs[4] = { NULL }; + unsigned short i = 0; isc_result_t result; - if (key->keydata.dh == NULL) { - return (DST_R_NULLKEY); - } - if (key->external) { return (DST_R_EXTERNALKEY); } +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (key->keydata.dh == NULL) { + return (DST_R_NULLKEY); + } + dh = key->keydata.dh; DH_get0_key(dh, &pub_key, &priv_key); DH_get0_pqg(dh, &p, NULL, &g); - - memset(bufs, 0, sizeof(bufs)); - for (i = 0; i < 4; i++) { - bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(p)); +#else + if (key->keydata.pkey == NULL) { + return (DST_R_NULLKEY); } - i = 0; + pkey = key->keydata.pkey; + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ priv.elements[i].tag = TAG_DH_PRIME; priv.elements[i].length = BN_num_bytes(p); + bufs[i] = isc_mem_get(key->mctx, priv.elements[i].length); BN_bn2bin(p, bufs[i]); priv.elements[i].data = bufs[i]; i++; priv.elements[i].tag = TAG_DH_GENERATOR; priv.elements[i].length = BN_num_bytes(g); + bufs[i] = isc_mem_get(key->mctx, priv.elements[i].length); BN_bn2bin(g, bufs[i]); priv.elements[i].data = bufs[i]; i++; priv.elements[i].tag = TAG_DH_PRIVATE; priv.elements[i].length = BN_num_bytes(priv_key); + bufs[i] = isc_mem_get(key->mctx, priv.elements[i].length); BN_bn2bin(priv_key, bufs[i]); priv.elements[i].data = bufs[i]; i++; priv.elements[i].tag = TAG_DH_PUBLIC; priv.elements[i].length = BN_num_bytes(pub_key); + bufs[i] = isc_mem_get(key->mctx, priv.elements[i].length); BN_bn2bin(pub_key, bufs[i]); priv.elements[i].data = bufs[i]; i++; @@ -563,12 +1055,28 @@ openssldh_tofile(const dst_key_t *key, const char *directory) { priv.nelements = i; result = dst__privstruct_writefile(key, &priv, directory); - for (i = 0; i < 4; i++) { - if (bufs[i] == NULL) { - break; + while (i--) { + if (bufs[i] != NULL) { + isc_mem_put(key->mctx, bufs[i], + priv.elements[i].length); } - isc_mem_put(key->mctx, bufs[i], BN_num_bytes(p)); } + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (p != NULL) { + BN_free(p); + } + if (g != NULL) { + BN_free(g); + } + if (pub_key != NULL) { + BN_free(pub_key); + } + if (priv_key != NULL) { + BN_clear_free(priv_key); + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + return (result); } @@ -577,14 +1085,17 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; int i; +#if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh = NULL; +#else + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ BIGNUM *pub_key = NULL, *priv_key = NULL, *p = NULL, *g = NULL; + int key_size = 0; isc_mem_t *mctx; -#define DST_RET(a) \ - { \ - ret = a; \ - goto err; \ - } UNUSED(pub); mctx = key->mctx; @@ -599,12 +1110,24 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { DST_RET(DST_R_EXTERNALKEY); } +#if OPENSSL_VERSION_NUMBER < 0x30000000L dh = DH_new(); if (dh == NULL) { DST_RET(ISC_R_NOMEMORY); } DH_clear_flags(dh, DH_FLAG_CACHE_MONT_P); key->keydata.dh = dh; + dh = NULL; +#else + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (ctx == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ for (i = 0; i < priv.nelements; i++) { BIGNUM *bn; @@ -617,6 +1140,7 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { switch (priv.elements[i].tag) { case TAG_DH_PRIME: p = bn; + key_size = BN_num_bits(p); break; case TAG_DH_GENERATOR: g = bn; @@ -629,14 +1153,75 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { break; } } - dst__privstruct_free(&priv, mctx); - DH_set0_key(dh, pub_key, priv_key); - DH_set0_pqg(dh, p, NULL, g); - key->key_size = BN_num_bits(p); - return (ISC_R_SUCCESS); +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (DH_set0_key(key->keydata.dh, pub_key, priv_key) != 1) { + DST_RET(dst__openssl_toresult2("DH_set0_key", + DST_R_OPENSSLFAILURE)); + } + if (DH_set0_pqg(key->keydata.dh, p, NULL, g) != 1) { + DST_RET(dst__openssl_toresult2("DH_set0_pqg", + DST_R_OPENSSLFAILURE)); + } + + /* These are now managed by OpenSSL */ + pub_key = NULL; + priv_key = NULL; + p = NULL; + g = NULL; +#else + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key) != + 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key) != + 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) != 1) + { + DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", + DST_R_OPENSSLFAILURE)); + } + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_fromdata_init(ctx) != 1) { + DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata_init", + DST_R_OPENSSLFAILURE)); + } + if (EVP_PKEY_fromdata(ctx, &pkey, OSSL_KEYMGMT_SELECT_ALL, params) != + 1 || + pkey == NULL) + { + DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata", + DST_R_OPENSSLFAILURE)); + } + + key->keydata.pkey = pkey; + pkey = NULL; +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + + key->key_size = (unsigned int)key_size; + ret = ISC_R_SUCCESS; err: +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (dh != NULL) { + DH_free(dh); + } +#else + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (ctx != NULL) { + EVP_PKEY_CTX_free(ctx); + } + if (params != NULL) { + OSSL_PARAM_free(params); + } + if (bld != NULL) { + OSSL_PARAM_BLD_free(bld); + } +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ if (p != NULL) { BN_free(p); } @@ -647,11 +1232,14 @@ err: BN_free(pub_key); } if (priv_key != NULL) { - BN_free(priv_key); + BN_clear_free(priv_key); + } + if (ret != ISC_R_SUCCESS) { + openssldh_destroy(key); } - openssldh_destroy(key); dst__privstruct_free(&priv, mctx); isc_safe_memwipe(&priv, sizeof(priv)); + return (ret); }