diff --git a/CHANGES b/CHANGES index a8cf9b21e8..5456bcf7d2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +5959. [security] Fix memory leaks in the DH code when using OpenSSL 3.0.0 + and later versions. The openssldh_compare(), + openssldh_paramcompare(), and openssldh_todns() + functions were affected. (CVE-2022-2906) [GL #3491] + 5958. [security] When an HTTP connection was reused to get statistics from the stats channel, and zlib compression was in use, each successive diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index f0bd64c74c..34bddc1bc5 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -29,6 +29,10 @@ Security Fixes in size past the end of the allocated buffer. This has been fixed. (CVE-2022-2881) :gl:`#3493` +- Memory leaks in code handling Diffie-Hellman (DH) keys were fixed that + could be externally triggered, when using TKEY records in DH mode with + OpenSSL 3.0.0 and later versions. (CVE-2022-2906) :gl:`#3491` + Known Issues ~~~~~~~~~~~~ diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index d5dbc2e889..1a01c2b351 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -165,6 +165,7 @@ openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, static bool openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { + bool ret = true; #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh1, *dh2; const BIGNUM *pub_key1 = NULL, *pub_key2 = NULL; @@ -214,18 +215,17 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0 || BN_cmp(pub_key1, pub_key2) != 0) { - return (false); + DST_RET(false); } if (priv_key1 != NULL || priv_key2 != NULL) { - if (priv_key1 == NULL || priv_key2 == NULL) { - return (false); - } - if (BN_cmp(priv_key1, priv_key2) != 0) { - return (false); + if (priv_key1 == NULL || priv_key2 == NULL || + BN_cmp(priv_key1, priv_key2) != 0) { + DST_RET(false); } } +err: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (p1 != NULL) { BN_free(p1); @@ -253,11 +253,12 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - return (true); + return (ret); } static bool openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { + bool ret = true; #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh1, *dh2; const BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL; @@ -295,9 +296,10 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0) { - return (false); + DST_RET(false); } +err: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (p1 != NULL) { BN_free(p1); @@ -313,7 +315,7 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - return (true); + return (ret); } #if OPENSSL_VERSION_NUMBER < 0x30000000L @@ -675,6 +677,7 @@ uint16_fromregion(isc_region_t *region) { static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { + isc_result_t ret = ISC_R_SUCCESS; #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh; const BIGNUM *pub_key = NULL, *p = NULL, *g = NULL; @@ -716,7 +719,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { publen = BN_num_bytes(pub_key); dnslen = plen + glen + publen + 6; if (r.length < (unsigned int)dnslen) { - return (ISC_R_NOSPACE); + DST_RET(ISC_R_NOSPACE); } uint16_toregion(plen, &r); @@ -745,6 +748,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { isc_buffer_add(data, dnslen); +err: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (p != NULL) { BN_free(p); @@ -757,7 +761,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - return (ISC_R_SUCCESS); + return (ret); } static isc_result_t