From 8d6cf6e34cd3d310acb2e247b326a7d1a67e1ac9 Mon Sep 17 00:00:00 2001 From: wangcheng Date: Sun, 28 Apr 2024 15:03:05 +0800 Subject: [PATCH] fix CVE-2023-5678 CVE-2024-0727 CVE-2024-2511 --- ...ereference-occurs-when-memory-alloca.patch | 36 + ...dd-a-test-for-session-cache-handling.patch | 125 ++ ...dd-a-test-for-session-cache-overflow.patch | 176 +++ ...eger-check-when-using-ASN1_BIT_STRIN.patch | 47 + ...-Fix-Timing-Oracle-in-RSA-decryption.patch | 1209 ++++++----------- ...ub_key-and-DH_generate_key-safer-yet.patch | 130 ++ ...024-0727-fix-pkcs12-decoding-crashes.patch | 111 ++ ...ined-session-cache-growth-in-TLSv1.3.patch | 173 +++ ..._resume-test-for-simultaneous-resump.patch | 152 +++ backport-Fix-EVP_PKEY_asn1_copy.patch | 52 + ...a-possbile-memleak-in-rsa_pub_encode.patch | 66 + ...ossible-memleak-in-eckey_priv_encode.patch | 76 ++ ...andling-in-CMS_EncryptedData_encrypt.patch | 170 +++ ...-PKCS-12-read-error-in-PKCS12_key_ge.patch | 43 + ...port-Fix-stack-corruption-in-ui_read.patch | 64 + ...dening-around-not_resumable-sessions.patch | 39 + ...t-some-error-bits-in-recently-added-.patch | 37 + ..._BN_RSA_DO_UNBLIND-which-was-incorre.patch | 30 + ...s-passwd.c-free-before-error-exiting.patch | 61 + ...Fix-possible-use-after-free-when-OOM.patch | 65 + ...le-ossl_policy_level_add_node-errors.patch | 72 + compat-openssl11.spec | 25 +- 22 files changed, 2186 insertions(+), 773 deletions(-) create mode 100644 backport-A-null-pointer-dereference-occurs-when-memory-alloca.patch create mode 100644 backport-Add-a-test-for-session-cache-handling.patch create mode 100644 backport-Add-a-test-for-session-cache-overflow.patch create mode 100755 backport-Add-negative-integer-check-when-using-ASN1_BIT_STRIN.patch create mode 100644 backport-CVE-2023-5678-Make-DH_check_pub_key-and-DH_generate_key-safer-yet.patch create mode 100644 backport-CVE-2024-0727-fix-pkcs12-decoding-crashes.patch create mode 100644 backport-CVE-2024-2511-Fix-unconstrained-session-cache-growth-in-TLSv1.3.patch create mode 100644 backport-Extend-the-multi_resume-test-for-simultaneous-resump.patch create mode 100644 backport-Fix-EVP_PKEY_asn1_copy.patch create mode 100644 backport-Fix-a-possbile-memleak-in-rsa_pub_encode.patch create mode 100644 backport-Fix-a-possible-memleak-in-eckey_priv_encode.patch create mode 100644 backport-Fix-error-handling-in-CMS_EncryptedData_encrypt.patch create mode 100644 backport-Fix-mem-leaks-on-PKCS-12-read-error-in-PKCS12_key_ge.patch create mode 100755 backport-Fix-stack-corruption-in-ui_read.patch create mode 100644 backport-Hardening-around-not_resumable-sessions.patch create mode 100644 backport-Make-DH_check-set-some-error-bits-in-recently-added-.patch create mode 100644 backport-Re-add-BN_F_OSSL_BN_RSA_DO_UNBLIND-which-was-incorre.patch create mode 100644 backport-apps-passwd.c-free-before-error-exiting.patch create mode 100644 backport-x509-Fix-possible-use-after-free-when-OOM.patch create mode 100644 backport-x509-Handle-ossl_policy_level_add_node-errors.patch diff --git a/backport-A-null-pointer-dereference-occurs-when-memory-alloca.patch b/backport-A-null-pointer-dereference-occurs-when-memory-alloca.patch new file mode 100644 index 0000000..afd87ba --- /dev/null +++ b/backport-A-null-pointer-dereference-occurs-when-memory-alloca.patch @@ -0,0 +1,36 @@ +From a8da305fa3dd6e34ba5aab3978281f652fd12883 Mon Sep 17 00:00:00 2001 +From: yangyangtiantianlonglong +Date: Mon, 31 Jul 2023 07:04:41 -0700 +Subject: [PATCH] A null pointer dereference occurs when memory allocation + fails + +Fixes #21605 + +Reviewed-by: Hugo Landau +Reviewed-by: Matthias St. Pierre +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/21606) +--- + ssl/ssl_sess.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c +index cda6b7cc5b..2a5d21be79 100644 +--- a/ssl/ssl_sess.c ++++ b/ssl/ssl_sess.c +@@ -139,8 +139,11 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) + dest->references = 1; + + dest->lock = CRYPTO_THREAD_lock_new(); +- if (dest->lock == NULL) ++ if (dest->lock == NULL) { ++ OPENSSL_free(dest); ++ dest = NULL; + goto err; ++ } + + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, dest, &dest->ex_data)) + goto err; +-- +2.27.0 + diff --git a/backport-Add-a-test-for-session-cache-handling.patch b/backport-Add-a-test-for-session-cache-handling.patch new file mode 100644 index 0000000..338d31d --- /dev/null +++ b/backport-Add-a-test-for-session-cache-handling.patch @@ -0,0 +1,125 @@ +From 913ac6975162dde9e6f715c7b12869ea32ab8b70 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Mon, 4 Mar 2024 13:45:23 +0000 +Subject: [PATCH] Add a test for session cache handling + +Repeatedly create sessions to be added to the cache and ensure we never +exceed the expected size. + +Related to CVE-2024-2511 + +Reviewed-by: Neil Horman +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/24044) + +(cherry picked from commit 5f5b9e1ca1fad0215f623b8bd4955a2e8101f306) +Signed-off-by: Liu-Ermeng +--- + test/sslapitest.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 91 insertions(+) + +diff --git a/test/sslapitest.c b/test/sslapitest.c +index 5ee982ab06..2992356fdf 100644 +--- a/test/sslapitest.c ++++ b/test/sslapitest.c +@@ -7288,6 +7288,97 @@ static int test_inherit_verify_param(void) + return testresult; + } + ++/* ++ * Test multiple resumptions and cache size handling ++ * Test 0: TLSv1.3 (max_early_data set) ++ * Test 1: TLSv1.3 (SSL_OP_NO_TICKET set) ++ * Test 2: TLSv1.3 (max_early_data and SSL_OP_NO_TICKET set) ++ * Test 3: TLSv1.2 ++ */ ++static int test_multi_resume(int idx) ++{ ++ SSL_CTX *sctx = NULL, *cctx = NULL; ++ SSL *serverssl = NULL, *clientssl = NULL; ++ SSL_SESSION *sess = NULL; ++ int max_version = TLS1_3_VERSION; ++ int i, testresult = 0; ++ ++ if (idx == 3) ++ max_version = TLS1_2_VERSION; ++ ++ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), ++ TLS_client_method(), TLS1_VERSION, ++ max_version, &sctx, &cctx, cert, ++ privkey))) ++ goto end; ++ ++ /* ++ * TLSv1.3 only uses a session cache if either max_early_data > 0 (used for ++ * replay protection), or if SSL_OP_NO_TICKET is in use ++ */ ++ if (idx == 0 || idx == 2) { ++ if (!TEST_true(SSL_CTX_set_max_early_data(sctx, 1024))) ++ goto end; ++ } ++ if (idx == 1 || idx == 2) ++ SSL_CTX_set_options(sctx, SSL_OP_NO_TICKET); ++ ++ SSL_CTX_sess_set_cache_size(sctx, 5); ++ ++ for (i = 0; i < 30; i++) { ++ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, ++ NULL, NULL)) ++ || !TEST_true(SSL_set_session(clientssl, sess))) ++ goto end; ++ ++ /* ++ * Recreate a bug where dynamically changing the max_early_data value ++ * can cause sessions in the session cache which cannot be deleted. ++ */ ++ if ((idx == 0 || idx == 2) && (i % 3) == 2) ++ SSL_set_max_early_data(serverssl, 0); ++ ++ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) ++ goto end; ++ ++ if (sess == NULL || (idx == 0 && (i % 3) == 2)) { ++ if (!TEST_false(SSL_session_reused(clientssl))) ++ goto end; ++ } else { ++ if (!TEST_true(SSL_session_reused(clientssl))) ++ goto end; ++ } ++ SSL_SESSION_free(sess); ++ ++ /* Do a full handshake, followed by two resumptions */ ++ if ((i % 3) == 2) { ++ sess = NULL; ++ } else { ++ if (!TEST_ptr((sess = SSL_get1_session(clientssl)))) ++ goto end; ++ } ++ ++ SSL_shutdown(clientssl); ++ SSL_shutdown(serverssl); ++ SSL_free(serverssl); ++ SSL_free(clientssl); ++ serverssl = clientssl = NULL; ++ } ++ ++ /* We should never exceed the session cache size limit */ ++ if (!TEST_long_le(SSL_CTX_sess_number(sctx), 5)) ++ goto end; ++ ++ testresult = 1; ++ end: ++ SSL_free(serverssl); ++ SSL_free(clientssl); ++ SSL_CTX_free(sctx); ++ SSL_CTX_free(cctx); ++ SSL_SESSION_free(sess); ++ return testresult; ++} ++ + int setup_tests(void) + { + if (!TEST_ptr(certsdir = test_get_argument(0)) +-- +2.33.0 + diff --git a/backport-Add-a-test-for-session-cache-overflow.patch b/backport-Add-a-test-for-session-cache-overflow.patch new file mode 100644 index 0000000..56eaee1 --- /dev/null +++ b/backport-Add-a-test-for-session-cache-overflow.patch @@ -0,0 +1,176 @@ +From 1659dc936a8763a243d09c2a6484eb1f25580ef4 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Fri, 15 Jul 2022 13:26:33 +0100 +Subject: [PATCH] Add a test for session cache overflow + +Test sessions behave as we expect even in the case that an overflow +occurs when adding a new session into the session cache. + +Related to CVE-2024-2511 + +Reviewed-by: Neil Horman +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/24044) + +(cherry picked from commit ddead0935d77ba9b771d632ace61b145d7153f18) +Signed-off-by: Liu-Ermeng +--- + test/sslapitest.c | 130 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 127 insertions(+), 3 deletions(-) + +diff --git a/test/sslapitest.c b/test/sslapitest.c +index 472b1224ca..395b1e5457 100644 +--- a/test/sslapitest.c ++++ b/test/sslapitest.c +@@ -6669,6 +6669,128 @@ static int test_ca_names(int tst) + return testresult; + } + ++/* ++ * Test that a session cache overflow works as expected ++ * Test 0: TLSv1.3, timeout on new session later than old session ++ * Test 1: TLSv1.2, timeout on new session later than old session ++ * Test 2: TLSv1.3, timeout on new session earlier than old session ++ * Test 3: TLSv1.2, timeout on new session earlier than old session ++ */ ++#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) ++static int test_session_cache_overflow(int idx) ++{ ++ SSL_CTX *sctx = NULL, *cctx = NULL; ++ SSL *serverssl = NULL, *clientssl = NULL; ++ int testresult = 0; ++ SSL_SESSION *sess = NULL; ++ ++#ifdef OPENSSL_NO_TLS1_3 ++ /* If no TLSv1.3 available then do nothing in this case */ ++ if (idx % 2 == 0) ++ TEST_info("No TLSv1.3 available"); ++ return 1; ++#endif ++#ifdef OPENSSL_NO_TLS1_2 ++ /* If no TLSv1.2 available then do nothing in this case */ ++ if (idx % 2 == 1) ++ TEST_info("No TLSv1.2 available"); ++ return 1; ++#endif ++ ++ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), ++ TLS_client_method(), TLS1_VERSION, ++ (idx % 2 == 0) ? TLS1_3_VERSION ++ : TLS1_2_VERSION, ++ &sctx, &cctx, cert, privkey)) ++ || !TEST_true(SSL_CTX_set_options(sctx, SSL_OP_NO_TICKET))) ++ goto end; ++ ++ SSL_CTX_sess_set_get_cb(sctx, get_session_cb); ++ get_sess_val = NULL; ++ ++ SSL_CTX_sess_set_cache_size(sctx, 1); ++ ++ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, ++ NULL, NULL))) ++ goto end; ++ ++ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) ++ goto end; ++ ++ if (idx > 1) { ++ sess = SSL_get_session(serverssl); ++ if (!TEST_ptr(sess)) ++ goto end; ++ ++ /* ++ * Cause this session to have a longer timeout than the next session to ++ * be added. ++ */ ++ if (!TEST_true(SSL_SESSION_set_timeout(sess, LONG_MAX / 2))) { ++ sess = NULL; ++ goto end; ++ } ++ sess = NULL; ++ } ++ ++ SSL_shutdown(serverssl); ++ SSL_shutdown(clientssl); ++ SSL_free(serverssl); ++ SSL_free(clientssl); ++ serverssl = clientssl = NULL; ++ ++ /* ++ * Session cache size is 1 and we already populated the cache with a session ++ * so the next connection should cause an overflow. ++ */ ++ ++ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, ++ NULL, NULL))) ++ goto end; ++ ++ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) ++ goto end; ++ ++ /* ++ * The session we just negotiated may have been already removed from the ++ * internal cache - but we will return it anyway from our external cache. ++ */ ++ get_sess_val = SSL_get_session(serverssl); ++ if (!TEST_ptr(get_sess_val)) ++ goto end; ++ sess = SSL_get1_session(clientssl); ++ if (!TEST_ptr(sess)) ++ goto end; ++ ++ SSL_shutdown(serverssl); ++ SSL_shutdown(clientssl); ++ SSL_free(serverssl); ++ SSL_free(clientssl); ++ serverssl = clientssl = NULL; ++ ++ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, ++ NULL, NULL))) ++ goto end; ++ ++ if (!TEST_true(SSL_set_session(clientssl, sess))) ++ goto end; ++ ++ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) ++ goto end; ++ ++ testresult = 1; ++ ++ end: ++ SSL_free(serverssl); ++ SSL_free(clientssl); ++ SSL_CTX_free(sctx); ++ SSL_CTX_free(cctx); ++ SSL_SESSION_free(sess); ++ ++ return testresult; ++} ++#endif /* !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) */ ++ + /* + * Test 0: Client sets servername and server acknowledges it (TLSv1.2) + * Test 1: Client sets servername and server does not acknowledge it (TLSv1.2) +@@ -7357,14 +7479,16 @@ static int test_multi_resume(int idx) + + #if defined(OPENSSL_NO_TLS1_2) + if (idx == 4) +- return TEST_skip("TLSv1.2 is disabled in this build"); ++ TEST_info("TLSv1.2 is disabled in this build"); ++ return 1; + #else + if (idx == 4) + max_version = TLS1_2_VERSION; + #endif +-#if defined(OSSL_NO_USABLE_TLS1_3) ++#if defined(OPENSSL_NO_TLS1_3) + if (idx != 4) +- return TEST_skip("No usable TLSv1.3 in this build"); ++ TEST_info("No usable TLSv1.3 in this build"); ++ return 1; + #endif + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), +-- +2.33.0 + diff --git a/backport-Add-negative-integer-check-when-using-ASN1_BIT_STRIN.patch b/backport-Add-negative-integer-check-when-using-ASN1_BIT_STRIN.patch new file mode 100755 index 0000000..bf4fff4 --- /dev/null +++ b/backport-Add-negative-integer-check-when-using-ASN1_BIT_STRIN.patch @@ -0,0 +1,47 @@ +From 8ddacec11481a37302c19f4454e23299af399f83 Mon Sep 17 00:00:00 2001 +From: mlitre +Date: Mon, 1 May 2023 11:07:21 +0200 +Subject: [PATCH] Add negative integer check when using ASN1_BIT_STRING + +The negative integer check is done to prevent potential overflow. +Fixes #20719. + +CLA: trivial + +Reviewed-by: Tomas Mraz +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/20862) + +(cherry picked from commit 1258a8e4361320cd3cfaf9ede692492ce01034c8) + +--- + crypto/asn1/a_bitstr.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c +index f462dd1073..31a1e11359 100644 +--- a/crypto/asn1/a_bitstr.c ++++ b/crypto/asn1/a_bitstr.c +@@ -148,6 +148,9 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value) + int w, v, iv; + unsigned char *c; + ++ if (n < 0) ++ return 0; ++ + w = n / 8; + v = 1 << (7 - (n & 0x07)); + iv = ~v; +@@ -182,6 +185,9 @@ int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n) + { + int w, v; + ++ if (n < 0) ++ return 0; ++ + w = n / 8; + v = 1 << (7 - (n & 0x07)); + if ((a == NULL) || (a->length < (w + 1)) || (a->data == NULL)) +-- +2.27.0 + diff --git a/backport-CVE-2022-4304-Fix-Timing-Oracle-in-RSA-decryption.patch b/backport-CVE-2022-4304-Fix-Timing-Oracle-in-RSA-decryption.patch index 626bc78..ba4ccd1 100644 --- a/backport-CVE-2022-4304-Fix-Timing-Oracle-in-RSA-decryption.patch +++ b/backport-CVE-2022-4304-Fix-Timing-Oracle-in-RSA-decryption.patch @@ -1,799 +1,464 @@ -From 43d8f88511991533f53680a751e9326999a6a31f Mon Sep 17 00:00:00 2001 -From: Matt Caswell -Date: Fri, 20 Jan 2023 15:26:54 +0000 -Subject: [PATCH] Fix Timing Oracle in RSA decryption +From 3f499b24f3bcd66db022074f7e8b4f6ee266a3ae Mon Sep 17 00:00:00 2001 +From: Bernd Edlinger +Date: Mon, 13 Feb 2023 17:46:41 +0100 +Subject: [PATCH] Alternative fix for CVE-2022-4304 -A timing based side channel exists in the OpenSSL RSA Decryption -implementation which could be sufficient to recover a plaintext across -a network in a Bleichenbacher style attack. To achieve a successful -decryption an attacker would have to be able to send a very large number -of trial messages for decryption. The vulnerability affects all RSA -padding modes: PKCS#1 v1.5, RSA-OEAP and RSASVE. +NOTE: This patch replaces the original patch for +CVE-2022-4304 (43d8f88511991533f53680a751e9326999a6a31f). -Patch written by Dmitry Belyavsky and Hubert Kario +This is about a timing leak in the topmost limb +of the internal result of RSA_private_decrypt, +before the padding check. -CVE-2022-4304 +There are in fact at least three bugs together that +caused the timing leak: -Reviewed-by: Dmitry Belyavskiy +First and probably most important is the fact that +the blinding did not use the constant time code path +at all when the RSA object was used for a private +decrypt, due to the fact that the Montgomery context +rsa->_method_mod_n was not set up early enough in +rsa_ossl_private_decrypt, when BN_BLINDING_create_param +needed it, and that was persisted as blinding->m_ctx, +although the RSA object creates the Montgomery context +just a bit later. + +Then the infamous bn_correct_top was used on the +secret value right after the blinding was removed. + +And finally the function BN_bn2binpad did not use +the constant-time code path since the BN_FLG_CONSTTIME +was not set on the secret value. + +In order to address the first problem, this patch +makes sure that the rsa->_method_mod_n is initialized +right before the blinding context. + +And to fix the second problem, we add a new utility +function bn_correct_top_consttime, a const-time +variant of bn_correct_top. + +Together with the fact, that BN_bn2binpad is already +constant time if the flag BN_FLG_CONSTTIME is set, +this should eliminate the timing oracle completely. + +In addition the no-asm variant may also have +branches that depend on secret values, because the last +invocation of bn_sub_words in bn_from_montgomery_word +had branches when the function is compiled by certain +gcc compiler versions, due to the clumsy coding style. + +So additionally this patch stream-lined the no-asm +C-code in order to avoid branches where possible and +improve the resulting code quality. + +Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/20284) + --- - crypto/bn/bn_blind.c | 14 - - crypto/bn/bn_err.c | 2 + - crypto/bn/bn_local.h | 14 + - crypto/bn/build.info | 3 +- - crypto/bn/rsa_sup_mul.c | 614 ++++++++++++++++++++++++++++++++++++++++ - crypto/err/openssl.txt | 3 +- - crypto/rsa/rsa_ossl.c | 17 +- - include/crypto/bn.h | 5 + - include/openssl/bnerr.h | 1 + - 9 files changed, 653 insertions(+), 20 deletions(-) - create mode 100644 crypto/bn/rsa_sup_mul.c + CHANGES | 10 ++++ + crypto/bn/bn_asm.c | 106 +++++++++++++++++++++++------------------- + crypto/bn/bn_blind.c | 3 +- + crypto/bn/bn_lib.c | 22 +++++++++ + crypto/bn/bn_local.h | 26 +++++------ + crypto/rsa/rsa_ossl.c | 13 +++--- + 6 files changed, 111 insertions(+), 69 deletions(-) -diff --git a/crypto/bn/bn_blind.c b/crypto/bn/bn_blind.c -index 76fc7ebcff..6e9d239321 100644 ---- a/crypto/bn/bn_blind.c -+++ b/crypto/bn/bn_blind.c -@@ -13,20 +13,6 @@ +diff --git a/crypto/bn/bn_asm.c b/crypto/bn/bn_asm.c +index 4d83a8cf11..177558c647 100644 +--- a/crypto/bn/bn_asm.c ++++ b/crypto/bn/bn_asm.c +@@ -381,25 +381,33 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + #ifndef OPENSSL_SMALL_FOOTPRINT + while (n & ~3) { + t1 = a[0]; +- t2 = b[0]; +- r[0] = (t1 - t2 - c) & BN_MASK2; +- if (t1 != t2) +- c = (t1 < t2); ++ t2 = (t1 - c) & BN_MASK2; ++ c = (t2 > t1); ++ t1 = b[0]; ++ t1 = (t2 - t1) & BN_MASK2; ++ r[0] = t1; ++ c += (t1 > t2); + t1 = a[1]; +- t2 = b[1]; +- r[1] = (t1 - t2 - c) & BN_MASK2; +- if (t1 != t2) +- c = (t1 < t2); ++ t2 = (t1 - c) & BN_MASK2; ++ c = (t2 > t1); ++ t1 = b[1]; ++ t1 = (t2 - t1) & BN_MASK2; ++ r[1] = t1; ++ c += (t1 > t2); + t1 = a[2]; +- t2 = b[2]; +- r[2] = (t1 - t2 - c) & BN_MASK2; +- if (t1 != t2) +- c = (t1 < t2); ++ t2 = (t1 - c) & BN_MASK2; ++ c = (t2 > t1); ++ t1 = b[2]; ++ t1 = (t2 - t1) & BN_MASK2; ++ r[2] = t1; ++ c += (t1 > t2); + t1 = a[3]; +- t2 = b[3]; +- r[3] = (t1 - t2 - c) & BN_MASK2; +- if (t1 != t2) +- c = (t1 < t2); ++ t2 = (t1 - c) & BN_MASK2; ++ c = (t2 > t1); ++ t1 = b[3]; ++ t1 = (t2 - t1) & BN_MASK2; ++ r[3] = t1; ++ c += (t1 > t2); + a += 4; + b += 4; + r += 4; +@@ -408,10 +416,12 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + #endif + while (n) { + t1 = a[0]; +- t2 = b[0]; +- r[0] = (t1 - t2 - c) & BN_MASK2; +- if (t1 != t2) +- c = (t1 < t2); ++ t2 = (t1 - c) & BN_MASK2; ++ c = (t2 > t1); ++ t1 = b[0]; ++ t1 = (t2 - t1) & BN_MASK2; ++ r[0] = t1; ++ c += (t1 > t2); + a++; + b++; + r++; +@@ -446,7 +456,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ +- c1 = (c1+hi)&BN_MASK2; if (c1 -+#include -+#include -+#include -+#include -+#include -+#include -+#include "internal/numbers.h" -+#include "internal/constant_time.h" -+#include "bn_local.h" -+ -+# if BN_BYTES == 8 -+typedef uint64_t limb_t; -+# if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 -+/* nonstandard; implemented by gcc on 64-bit platforms */ -+typedef __uint128_t limb2_t; -+# define HAVE_LIMB2_T -+# endif -+# define LIMB_BIT_SIZE 64 -+# define LIMB_BYTE_SIZE 8 -+# elif BN_BYTES == 4 -+typedef uint32_t limb_t; -+typedef uint64_t limb2_t; -+# define LIMB_BIT_SIZE 32 -+# define LIMB_BYTE_SIZE 4 -+# define HAVE_LIMB2_T -+# else -+# error "Not supported" -+# endif -+ -+/* -+ * For multiplication we're using schoolbook multiplication, -+ * so if we have two numbers, each with 6 "digits" (words) -+ * the multiplication is calculated as follows: -+ * A B C D E F -+ * x I J K L M N -+ * -------------- -+ * N*F -+ * N*E -+ * N*D -+ * N*C -+ * N*B -+ * N*A -+ * M*F -+ * M*E -+ * M*D -+ * M*C -+ * M*B -+ * M*A -+ * L*F -+ * L*E -+ * L*D -+ * L*C -+ * L*B -+ * L*A -+ * K*F -+ * K*E -+ * K*D -+ * K*C -+ * K*B -+ * K*A -+ * J*F -+ * J*E -+ * J*D -+ * J*C -+ * J*B -+ * J*A -+ * I*F -+ * I*E -+ * I*D -+ * I*C -+ * I*B -+ * + I*A -+ * ========================== -+ * N*B N*D N*F -+ * + N*A N*C N*E -+ * + M*B M*D M*F -+ * + M*A M*C M*E -+ * + L*B L*D L*F -+ * + L*A L*C L*E -+ * + K*B K*D K*F -+ * + K*A K*C K*E -+ * + J*B J*D J*F -+ * + J*A J*C J*E -+ * + I*B I*D I*F -+ * + I*A I*C I*E -+ * -+ * 1+1 1+3 1+5 -+ * 1+0 1+2 1+4 -+ * 0+1 0+3 0+5 -+ * 0+0 0+2 0+4 -+ * -+ * 0 1 2 3 4 5 6 -+ * which requires n^2 multiplications and 2n full length additions -+ * as we can keep every other result of limb multiplication in two separate -+ * limbs -+ */ -+ -+#if defined HAVE_LIMB2_T -+static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) -+{ -+ limb2_t t; -+ /* -+ * this is idiomatic code to tell compiler to use the native mul -+ * those three lines will actually compile to single instruction -+ */ -+ -+ t = (limb2_t)a * b; -+ *hi = t >> LIMB_BIT_SIZE; -+ *lo = (limb_t)t; -+} -+#elif (BN_BYTES == 8) && (defined _MSC_VER) -+/* https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-170 */ -+#pragma intrinsic(_umul128) -+static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) -+{ -+ *lo = _umul128(a, b, hi); -+} -+#else -+/* -+ * if the compiler doesn't have either a 128bit data type nor a "return -+ * high 64 bits of multiplication" -+ */ -+static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) -+{ -+ limb_t a_low = (limb_t)(uint32_t)a; -+ limb_t a_hi = a >> 32; -+ limb_t b_low = (limb_t)(uint32_t)b; -+ limb_t b_hi = b >> 32; -+ -+ limb_t p0 = a_low * b_low; -+ limb_t p1 = a_low * b_hi; -+ limb_t p2 = a_hi * b_low; -+ limb_t p3 = a_hi * b_hi; -+ -+ uint32_t cy = (uint32_t)(((p0 >> 32) + (uint32_t)p1 + (uint32_t)p2) >> 32); -+ -+ *lo = p0 + (p1 << 32) + (p2 << 32); -+ *hi = p3 + (p1 >> 32) + (p2 >> 32) + cy; -+} -+#endif -+ -+/* add two limbs with carry in, return carry out */ -+static ossl_inline limb_t _add_limb(limb_t *ret, limb_t a, limb_t b, limb_t carry) -+{ -+ limb_t carry1, carry2, t; -+ /* -+ * `c = a + b; if (c < a)` is idiomatic code that makes compilers -+ * use add with carry on assembly level -+ */ -+ -+ *ret = a + carry; -+ if (*ret < a) -+ carry1 = 1; -+ else -+ carry1 = 0; -+ -+ t = *ret; -+ *ret = t + b; -+ if (*ret < t) -+ carry2 = 1; -+ else -+ carry2 = 0; -+ -+ return carry1 + carry2; -+} -+ -+/* -+ * add two numbers of the same size, return overflow -+ * -+ * add a to b, place result in ret; all arrays need to be n limbs long -+ * return overflow from addition (0 or 1) -+ */ -+static ossl_inline limb_t add(limb_t *ret, limb_t *a, limb_t *b, size_t n) -+{ -+ limb_t c = 0; -+ ossl_ssize_t i; -+ -+ for(i = n - 1; i > -1; i--) -+ c = _add_limb(&ret[i], a[i], b[i], c); -+ -+ return c; -+} -+ -+/* -+ * return number of limbs necessary for temporary values -+ * when multiplying numbers n limbs large -+ */ -+static ossl_inline size_t mul_limb_numb(size_t n) -+{ -+ return 2 * n * 2; -+} -+ -+/* -+ * multiply two numbers of the same size -+ * -+ * multiply a by b, place result in ret; a and b need to be n limbs long -+ * ret needs to be 2*n limbs long, tmp needs to be mul_limb_numb(n) limbs -+ * long -+ */ -+static void limb_mul(limb_t *ret, limb_t *a, limb_t *b, size_t n, limb_t *tmp) -+{ -+ limb_t *r_odd, *r_even; -+ size_t i, j, k; -+ -+ r_odd = tmp; -+ r_even = &tmp[2 * n]; -+ -+ memset(ret, 0, 2 * n * sizeof(limb_t)); -+ -+ for (i = 0; i < n; i++) { -+ for (k = 0; k < i + n + 1; k++) { -+ r_even[k] = 0; -+ r_odd[k] = 0; -+ } -+ for (j = 0; j < n; j++) { -+ /* -+ * place results from even and odd limbs in separate arrays so that -+ * we don't have to calculate overflow every time we get individual -+ * limb multiplication result -+ */ -+ if (j % 2 == 0) -+ _mul_limb(&r_even[i + j], &r_even[i + j + 1], a[i], b[j]); -+ else -+ _mul_limb(&r_odd[i + j], &r_odd[i + j + 1], a[i], b[j]); -+ } -+ /* -+ * skip the least significant limbs when adding multiples of -+ * more significant limbs (they're zero anyway) -+ */ -+ add(ret, ret, r_even, n + i + 1); -+ add(ret, ret, r_odd, n + i + 1); -+ } -+} -+ -+/* modifies the value in place by performing a right shift by one bit */ -+static ossl_inline void rshift1(limb_t *val, size_t n) -+{ -+ limb_t shift_in = 0, shift_out = 0; -+ size_t i; -+ -+ for (i = 0; i < n; i++) { -+ shift_out = val[i] & 1; -+ val[i] = shift_in << (LIMB_BIT_SIZE - 1) | (val[i] >> 1); -+ shift_in = shift_out; -+ } -+} -+ -+/* extend the LSB of flag to all bits of limb */ -+static ossl_inline limb_t mk_mask(limb_t flag) -+{ -+ flag |= flag << 1; -+ flag |= flag << 2; -+ flag |= flag << 4; -+ flag |= flag << 8; -+ flag |= flag << 16; -+#if (LIMB_BYTE_SIZE == 8) -+ flag |= flag << 32; -+#endif -+ return flag; -+} -+ -+/* -+ * copy from either a or b to ret based on flag -+ * when flag == 0, then copies from b -+ * when flag == 1, then copies from a -+ */ -+static ossl_inline void cselect(limb_t flag, limb_t *ret, limb_t *a, limb_t *b, size_t n) -+{ -+ /* -+ * would be more efficient with non volatile mask, but then gcc -+ * generates code with jumps -+ */ -+ volatile limb_t mask; -+ size_t i; -+ -+ mask = mk_mask(flag); -+ for (i = 0; i < n; i++) { -+#if (LIMB_BYTE_SIZE == 8) -+ ret[i] = constant_time_select_64(mask, a[i], b[i]); -+#else -+ ret[i] = constant_time_select_32(mask, a[i], b[i]); -+#endif -+ } -+} -+ -+static limb_t _sub_limb(limb_t *ret, limb_t a, limb_t b, limb_t borrow) -+{ -+ limb_t borrow1, borrow2, t; -+ /* -+ * while it doesn't look constant-time, this is idiomatic code -+ * to tell compilers to use the carry bit from subtraction -+ */ -+ -+ *ret = a - borrow; -+ if (*ret > a) -+ borrow1 = 1; -+ else -+ borrow1 = 0; -+ -+ t = *ret; -+ *ret = t - b; -+ if (*ret > t) -+ borrow2 = 1; -+ else -+ borrow2 = 0; -+ -+ return borrow1 + borrow2; -+} -+ -+/* -+ * place the result of a - b into ret, return the borrow bit. -+ * All arrays need to be n limbs long -+ */ -+static limb_t sub(limb_t *ret, limb_t *a, limb_t *b, size_t n) -+{ -+ limb_t borrow = 0; -+ ossl_ssize_t i; -+ -+ for (i = n - 1; i > -1; i--) -+ borrow = _sub_limb(&ret[i], a[i], b[i], borrow); -+ -+ return borrow; -+} -+ -+/* return the number of limbs necessary to allocate for the mod() tmp operand */ -+static ossl_inline size_t mod_limb_numb(size_t anum, size_t modnum) -+{ -+ return (anum + modnum) * 3; -+} -+ -+/* -+ * calculate a % mod, place the result in ret -+ * size of a is defined by anum, size of ret and mod is modnum, -+ * size of tmp is returned by mod_limb_numb() -+ */ -+static void mod(limb_t *ret, limb_t *a, size_t anum, limb_t *mod, -+ size_t modnum, limb_t *tmp) -+{ -+ limb_t *atmp, *modtmp, *rettmp; -+ limb_t res; -+ size_t i; -+ -+ memset(tmp, 0, mod_limb_numb(anum, modnum) * LIMB_BYTE_SIZE); -+ -+ atmp = tmp; -+ modtmp = &tmp[anum + modnum]; -+ rettmp = &tmp[(anum + modnum) * 2]; -+ -+ for (i = modnum; i top = (int)(rtop & ~mask) | (ntop & mask); + n->flags |= (BN_FLG_FIXED_TOP & ~mask); + } +- ret = BN_mod_mul_montgomery(n, n, r, b->m_ctx, ctx); ++ ret = bn_mul_mont_fixed_top(n, n, r, b->m_ctx, ctx); ++ bn_correct_top_consttime(n); + } else { + ret = BN_mod_mul(n, n, r, b->mod, ctx); + } +diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c +index eb4a31849b..fe6fb0e40f 100644 +--- a/crypto/bn/bn_lib.c ++++ b/crypto/bn/bn_lib.c +@@ -1001,6 +1001,28 @@ BIGNUM *bn_wexpand(BIGNUM *a, int words) + return (words <= a->dmax) ? a : bn_expand2(a, words); + } + ++void bn_correct_top_consttime(BIGNUM *a) +{ -+ limb_t carry, v; -+ limb_t *res, *rp, *tmp2; -+ ossl_ssize_t i; -+ -+ res = tmp; -+ /* -+ * for intermediate result we need an integer twice as long as modulus -+ * but keep the input in the least significant limbs -+ */ -+ memset(res, 0, sizeof(limb_t) * (modnum * 2)); -+ memcpy(&res[modnum * 2 - anum], a, sizeof(limb_t) * anum); -+ rp = &res[modnum]; -+ tmp2 = &res[modnum * 2]; -+ -+ carry = 0; -+ -+ /* add multiples of the modulus to the value until R divides it cleanly */ -+ for (i = modnum; i > 0; i--, rp--) { -+ v = _mul_add_limb(rp, mod, modnum, rp[modnum - 1] * ni0, tmp2); -+ v = v + carry + rp[-1]; -+ carry |= (v != rp[-1]); -+ carry &= (v <= rp[-1]); -+ rp[-1] = v; ++ int j, atop; ++ BN_ULONG limb; ++ unsigned int mask; ++ ++ for (j = 0, atop = 0; j < a->dmax; j++) { ++ limb = a->d[j]; ++ limb |= 0 - limb; ++ limb >>= BN_BITS2 - 1; ++ limb = 0 - limb; ++ mask = (unsigned int)limb; ++ mask &= constant_time_msb(j - a->top); ++ atop = constant_time_select_int(mask, j + 1, atop); + } + -+ /* perform the final reduction by mod... */ -+ carry -= sub(ret, rp, mod, modnum); -+ -+ /* ...conditionally */ -+ cselect(carry, ret, rp, ret, modnum); ++ mask = constant_time_eq_int(atop, 0); ++ a->top = atop; ++ a->neg = constant_time_select_int(mask, 0, a->neg); ++ a->flags &= ~BN_FLG_FIXED_TOP; +} + -+/* allocated buffer should be freed afterwards */ -+static void BN_to_limb(const BIGNUM *bn, limb_t *buf, size_t limbs) -+{ -+ int i; -+ int real_limbs = (BN_num_bytes(bn) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; -+ limb_t *ptr = buf + (limbs - real_limbs); -+ -+ for (i = 0; i < real_limbs; i++) -+ ptr[i] = bn->d[real_limbs - i - 1]; -+} -+ -+#if LIMB_BYTE_SIZE == 8 -+static ossl_inline uint64_t be64(uint64_t host) -+{ -+ const union { -+ long one; -+ char little; -+ } is_endian = { 1 }; -+ -+ if (is_endian.little) { -+ uint64_t big = 0; -+ -+ big |= (host & 0xff00000000000000) >> 56; -+ big |= (host & 0x00ff000000000000) >> 40; -+ big |= (host & 0x0000ff0000000000) >> 24; -+ big |= (host & 0x000000ff00000000) >> 8; -+ big |= (host & 0x00000000ff000000) << 8; -+ big |= (host & 0x0000000000ff0000) << 24; -+ big |= (host & 0x000000000000ff00) << 40; -+ big |= (host & 0x00000000000000ff) << 56; -+ return big; -+ } else { -+ return host; -+ } -+} -+ -+#else -+/* Not all platforms have htobe32(). */ -+static ossl_inline uint32_t be32(uint32_t host) -+{ -+ const union { -+ long one; -+ char little; -+ } is_endian = { 1 }; -+ -+ if (is_endian.little) { -+ uint32_t big = 0; -+ -+ big |= (host & 0xff000000) >> 24; -+ big |= (host & 0x00ff0000) >> 8; -+ big |= (host & 0x0000ff00) << 8; -+ big |= (host & 0x000000ff) << 24; -+ return big; -+ } else { -+ return host; -+ } -+} -+#endif -+ -+/* -+ * We assume that intermediate, possible_arg2, blinding, and ctx are used -+ * similar to BN_BLINDING_invert_ex() arguments. -+ * to_mod is RSA modulus. -+ * buf and num is the serialization buffer and its length. -+ * -+ * Here we use classic/Montgomery multiplication and modulo. After the calculation finished -+ * we serialize the new structure instead of BIGNUMs taking endianness into account. -+ */ -+int ossl_bn_rsa_do_unblind(const BIGNUM *intermediate, -+ const BN_BLINDING *blinding, -+ const BIGNUM *possible_arg2, -+ const BIGNUM *to_mod, BN_CTX *ctx, -+ unsigned char *buf, int num) -+{ -+ limb_t *l_im = NULL, *l_mul = NULL, *l_mod = NULL; -+ limb_t *l_ret = NULL, *l_tmp = NULL, l_buf; -+ size_t l_im_count = 0, l_mul_count = 0, l_size = 0, l_mod_count = 0; -+ size_t l_tmp_count = 0; -+ int ret = 0; -+ size_t i; -+ unsigned char *tmp; -+ const BIGNUM *arg1 = intermediate; -+ const BIGNUM *arg2 = (possible_arg2 == NULL) ? blinding->Ai : possible_arg2; -+ -+ l_im_count = (BN_num_bytes(arg1) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; -+ l_mul_count = (BN_num_bytes(arg2) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; -+ l_mod_count = (BN_num_bytes(to_mod) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; -+ -+ l_size = l_im_count > l_mul_count ? l_im_count : l_mul_count; -+ l_im = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); -+ l_mul = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); -+ l_mod = OPENSSL_zalloc(l_mod_count * LIMB_BYTE_SIZE); -+ -+ if ((l_im == NULL) || (l_mul == NULL) || (l_mod == NULL)) -+ goto err; -+ -+ BN_to_limb(arg1, l_im, l_size); -+ BN_to_limb(arg2, l_mul, l_size); -+ BN_to_limb(to_mod, l_mod, l_mod_count); -+ -+ l_ret = OPENSSL_malloc(2 * l_size * LIMB_BYTE_SIZE); -+ -+ if (blinding->m_ctx != NULL) { -+ l_tmp_count = mul_limb_numb(l_size) > mod_montgomery_limb_numb(l_mod_count) ? -+ mul_limb_numb(l_size) : mod_montgomery_limb_numb(l_mod_count); -+ l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); -+ } else { -+ l_tmp_count = mul_limb_numb(l_size) > mod_limb_numb(2 * l_size, l_mod_count) ? -+ mul_limb_numb(l_size) : mod_limb_numb(2 * l_size, l_mod_count); -+ l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); -+ } -+ -+ if ((l_ret == NULL) || (l_tmp == NULL)) -+ goto err; -+ -+ if (blinding->m_ctx != NULL) { -+ limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); -+ mod_montgomery(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, -+ blinding->m_ctx->n0[0], l_tmp); -+ } else { -+ limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); -+ mod(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, l_tmp); -+ } -+ -+ /* modulus size in bytes can be equal to num but after limbs conversion it becomes bigger */ -+ if (num < BN_num_bytes(to_mod)) { -+ BNerr(BN_F_OSSL_BN_RSA_DO_UNBLIND, ERR_R_PASSED_INVALID_ARGUMENT); -+ goto err; -+ } -+ -+ memset(buf, 0, num); -+ tmp = buf + num - BN_num_bytes(to_mod); -+ for (i = 0; i < l_mod_count; i++) { -+#if LIMB_BYTE_SIZE == 8 -+ l_buf = be64(l_ret[i]); -+#else -+ l_buf = be32(l_ret[i]); -+#endif -+ if (i == 0) { -+ int delta = LIMB_BYTE_SIZE - ((l_mod_count * LIMB_BYTE_SIZE) - num); -+ -+ memcpy(tmp, ((char *)&l_buf) + LIMB_BYTE_SIZE - delta, delta); -+ tmp += delta; -+ } else { -+ memcpy(tmp, &l_buf, LIMB_BYTE_SIZE); -+ tmp += LIMB_BYTE_SIZE; -+ } -+ } -+ ret = num; -+ -+ err: -+ OPENSSL_free(l_im); -+ OPENSSL_free(l_mul); -+ OPENSSL_free(l_mod); -+ OPENSSL_free(l_tmp); -+ OPENSSL_free(l_ret); -+ -+ return ret; -+} -diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt -index 9f91a4a811..ba3a46d5b9 100644 ---- a/crypto/err/openssl.txt -+++ b/crypto/err/openssl.txt -@@ -232,6 +232,7 @@ BN_F_BN_RSHIFT:146:BN_rshift - BN_F_BN_SET_WORDS:144:bn_set_words - BN_F_BN_STACK_PUSH:148:BN_STACK_push - BN_F_BN_USUB:115:BN_usub -+BN_F_OSSL_BN_RSA_DO_UNBLIND:151:ossl_bn_rsa_do_unblind - BUF_F_BUF_MEM_GROW:100:BUF_MEM_grow - BUF_F_BUF_MEM_GROW_CLEAN:105:BUF_MEM_grow_clean - BUF_F_BUF_MEM_NEW:101:BUF_MEM_new + void bn_correct_top(BIGNUM *a) + { + BN_ULONG *ftl; +diff --git a/crypto/bn/bn_local.h b/crypto/bn/bn_local.h +index ee6342b60c..818e34348e 100644 +--- a/crypto/bn/bn_local.h ++++ b/crypto/bn/bn_local.h +@@ -515,10 +515,10 @@ unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b, + ret = (r); \ + BN_UMULT_LOHI(low,high,w,tmp); \ + ret += (c); \ +- (c) = (ret<(c))?1:0; \ ++ (c) = (ret<(c)); \ + (c) += high; \ + ret += low; \ +- (c) += (ret>(BN_BITS4-1); \ + m =(m&BN_MASK2l)<<(BN_BITS4+1); \ +- l=(l+m)&BN_MASK2; if (l < m) h++; \ ++ l=(l+m)&BN_MASK2; h += (l < m); \ + (lo)=l; \ + (ho)=h; \ + } +@@ -623,9 +623,9 @@ unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b, + mul64(l,h,(bl),(bh)); \ + \ + /* non-multiply part */ \ +- l=(l+(c))&BN_MASK2; if (l < (c)) h++; \ ++ l=(l+(c))&BN_MASK2; h += (l < (c)); \ + (c)=(r); \ +- l=(l+(c))&BN_MASK2; if (l < (c)) h++; \ ++ l=(l+(c))&BN_MASK2; h += (l < (c)); \ + (c)=h&BN_MASK2; \ + (r)=l; \ + } +@@ -639,7 +639,7 @@ unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b, + mul64(l,h,(bl),(bh)); \ + \ + /* non-multiply part */ \ +- l+=(c); if ((l&BN_MASK2) < (c)) h++; \ ++ l+=(c); h += ((l&BN_MASK2) < (c)); \ + (c)=h&BN_MASK2; \ + (r)=l&BN_MASK2; \ + } +@@ -669,7 +669,7 @@ BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int cl, int dl); + int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + const BN_ULONG *np, const BN_ULONG *n0, int num); +- ++void bn_correct_top_consttime(BIGNUM *a); + BIGNUM *int_bn_mod_inverse(BIGNUM *in, + const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx, + int *noinv); diff --git a/crypto/rsa/rsa_ossl.c b/crypto/rsa/rsa_ossl.c -index b52a66f6a6..6c3c0cf78d 100644 +index 53cf2d03c9..cf5a10ab43 100644 --- a/crypto/rsa/rsa_ossl.c +++ b/crypto/rsa/rsa_ossl.c -@@ -465,11 +465,20 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, - BN_free(d); +@@ -226,6 +226,7 @@ static int rsa_blinding_invert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind, + * will only read the modulus from BN_BLINDING. In both cases it's safe + * to access the blinding without a lock. + */ ++ BN_set_flags(f, BN_FLG_CONSTTIME); + return BN_BLINDING_invert_ex(f, unblind, b, ctx); + } + +@@ -412,6 +413,11 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, + goto err; } -- if (blinding) -- if (!rsa_blinding_invert(blinding, ret, unblind, ctx)) -+ if (blinding) { -+ /* -+ * ossl_bn_rsa_do_unblind() combines blinding inversion and -+ * 0-padded BN BE serialization -+ */ -+ j = ossl_bn_rsa_do_unblind(ret, blinding, unblind, rsa->n, ctx, -+ buf, num); -+ if (j == 0) ++ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) ++ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock, ++ rsa->n, ctx)) ++ goto err; ++ + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_get_blinding(rsa, &local_blinding, ctx); + if (blinding == NULL) { +@@ -449,13 +455,6 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, goto err; + } + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - -- j = BN_bn2binpad(ret, buf, num); -+ } else { -+ j = BN_bn2binpad(ret, buf, num); -+ if (j < 0) -+ goto err; -+ } - - switch (padding) { - case RSA_PKCS1_PADDING: -diff --git a/include/crypto/bn.h b/include/crypto/bn.h -index 60afda1dad..b5f36fb25a 100644 ---- a/include/crypto/bn.h -+++ b/include/crypto/bn.h -@@ -86,5 +86,10 @@ int bn_lshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n); - int bn_rshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n); - int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, - const BIGNUM *d, BN_CTX *ctx); -+int ossl_bn_rsa_do_unblind(const BIGNUM *intermediate, -+ const BN_BLINDING *blinding, -+ const BIGNUM *possible_arg2, -+ const BIGNUM *to_mod, BN_CTX *ctx, -+ unsigned char *buf, int num); - - #endif -diff --git a/include/openssl/bnerr.h b/include/openssl/bnerr.h -index 9f3c7cfaab..a0752cea52 100644 ---- a/include/openssl/bnerr.h -+++ b/include/openssl/bnerr.h -@@ -72,6 +72,7 @@ int ERR_load_BN_strings(void); - # define BN_F_BN_SET_WORDS 144 - # define BN_F_BN_STACK_PUSH 148 - # define BN_F_BN_USUB 115 -+# define BN_F_OSSL_BN_RSA_DO_UNBLIND 151 - - /* - * BN reason codes. +- if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) +- if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock, +- rsa->n, ctx)) { +- BN_free(d); +- goto err; +- } + if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx, + rsa->_method_mod_n)) { + BN_free(d); -- -2.17.1 +2.27.0 + diff --git a/backport-CVE-2023-5678-Make-DH_check_pub_key-and-DH_generate_key-safer-yet.patch b/backport-CVE-2023-5678-Make-DH_check_pub_key-and-DH_generate_key-safer-yet.patch new file mode 100644 index 0000000..b349d64 --- /dev/null +++ b/backport-CVE-2023-5678-Make-DH_check_pub_key-and-DH_generate_key-safer-yet.patch @@ -0,0 +1,130 @@ +From 58589a46204c0dfca58906d6e66cf610caa11d88 Mon Sep 17 00:00:00 2001 +From: lanming1120 +Date: Tue, 7 Nov 2023 14:42:28 +0800 +Subject: [PATCH] Make DH_check_pub_key() and DH_generate_key() safer yet + +Signed-off-by: lanming1120 +--- + crypto/dh/dh_check.c | 13 +++++++++++++ + crypto/dh/dh_err.c | 1 + + crypto/dh/dh_key.c | 12 ++++++++++++ + crypto/err/openssl.txt | 1 + + include/openssl/dh.h | 5 +++-- + include/openssl/dherr.h | 1 + + 6 files changed, 31 insertions(+), 2 deletions(-) + +diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c +index ae1b03bc92..779cfbcd91 100644 +--- a/crypto/dh/dh_check.c ++++ b/crypto/dh/dh_check.c +@@ -198,6 +198,19 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) + BN_CTX *ctx = NULL; + + *ret = 0; ++ ++ /* Don't do any checks at all with an excessively large modulus */ ++ if (BN_num_bits(dh->p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { ++ DHerr(DH_F_DH_CHECK_EX, DH_R_MODULUS_TOO_LARGE); ++ *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_PUBKEY_INVALID; ++ return 0; ++ } ++ ++ if (dh->q != NULL && BN_ucmp(dh->p, dh->q) < 0) { ++ *ret |= DH_CHECK_INVALID_Q_VALUE | DH_CHECK_PUBKEY_INVALID; ++ return 1; ++ } ++ + ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; +diff --git a/crypto/dh/dh_err.c b/crypto/dh/dh_err.c +index 92800d3fcc..b3b1e7a706 100644 +--- a/crypto/dh/dh_err.c ++++ b/crypto/dh/dh_err.c +@@ -82,6 +82,7 @@ static const ERR_STRING_DATA DH_str_reasons[] = { + {ERR_PACK(ERR_LIB_DH, 0, DH_R_PARAMETER_ENCODING_ERROR), + "parameter encoding error"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_PEER_KEY_ERROR), "peer key error"}, ++ {ERR_PACK(ERR_LIB_DH, 0, DH_R_Q_TOO_LARGE), "q too large"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_SHARED_INFO_ERROR), "shared info error"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_UNABLE_TO_CHECK_GENERATOR), + "unable to check generator"}, +diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c +index 117f2fa883..4c4c4b9874 100644 +--- a/crypto/dh/dh_key.c ++++ b/crypto/dh/dh_key.c +@@ -109,6 +109,12 @@ static int generate_key(DH *dh) + } + #endif + ++ if (dh->q != NULL ++ && BN_num_bits(dh->q) > OPENSSL_DH_MAX_MODULUS_BITS) { ++ DHerr(DH_F_GENERATE_KEY, DH_R_Q_TOO_LARGE); ++ return 0; ++ } ++ + if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { + DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_LARGE); + return 0; +@@ -202,6 +208,12 @@ static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) + int ret = -1; + int check_result; + ++ if (dh->q != NULL ++ && BN_num_bits(dh->q) > OPENSSL_DH_MAX_MODULUS_BITS) { ++ DHerr(DH_F_COMPUTE_KEY, DH_R_Q_TOO_LARGE); ++ goto err; ++ } ++ + if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { + DHerr(DH_F_COMPUTE_KEY, DH_R_MODULUS_TOO_LARGE); + goto err; +diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt +index c111822eac..56d4093ada 100644 +--- a/crypto/err/openssl.txt ++++ b/crypto/err/openssl.txt +@@ -2139,6 +2139,7 @@ DH_R_NO_PARAMETERS_SET:107:no parameters set + DH_R_NO_PRIVATE_VALUE:100:no private value + DH_R_PARAMETER_ENCODING_ERROR:105:parameter encoding error + DH_R_PEER_KEY_ERROR:111:peer key error ++DH_R_Q_TOO_LARGE:130:q too large + DH_R_SHARED_INFO_ERROR:113:shared info error + DH_R_UNABLE_TO_CHECK_GENERATOR:121:unable to check generator + DSA_R_BAD_Q_VALUE:102:bad q value +diff --git a/include/openssl/dh.h b/include/openssl/dh.h +index 6c6ff3636a..7509f4fc3e 100644 +--- a/include/openssl/dh.h ++++ b/include/openssl/dh.h +@@ -71,14 +71,15 @@ DECLARE_ASN1_ITEM(DHparams) + /* #define DH_GENERATOR_3 3 */ + # define DH_GENERATOR_5 5 + +-/* DH_check error codes */ ++/* DH_check error codes, some of them shared with DH_check_pub_key */ + # define DH_CHECK_P_NOT_PRIME 0x01 + # define DH_CHECK_P_NOT_SAFE_PRIME 0x02 + # define DH_UNABLE_TO_CHECK_GENERATOR 0x04 + # define DH_NOT_SUITABLE_GENERATOR 0x08 + # define DH_CHECK_Q_NOT_PRIME 0x10 +-# define DH_CHECK_INVALID_Q_VALUE 0x20 ++# define DH_CHECK_INVALID_Q_VALUE 0x20 /* +DH_check_pub_key */ + # define DH_CHECK_INVALID_J_VALUE 0x40 ++# define DH_MODULUS_TOO_LARGE 0x100 + + /* DH_check_pub_key error codes */ + # define DH_CHECK_PUBKEY_TOO_SMALL 0x01 +diff --git a/include/openssl/dherr.h b/include/openssl/dherr.h +index 528c819856..d66c35aa8e 100644 +--- a/include/openssl/dherr.h ++++ b/include/openssl/dherr.h +@@ -82,6 +82,7 @@ int ERR_load_DH_strings(void); + # define DH_R_NO_PRIVATE_VALUE 100 + # define DH_R_PARAMETER_ENCODING_ERROR 105 + # define DH_R_PEER_KEY_ERROR 111 ++# define DH_R_Q_TOO_LARGE 130 + # define DH_R_SHARED_INFO_ERROR 113 + # define DH_R_UNABLE_TO_CHECK_GENERATOR 121 + +-- +2.33.0 + diff --git a/backport-CVE-2024-0727-fix-pkcs12-decoding-crashes.patch b/backport-CVE-2024-0727-fix-pkcs12-decoding-crashes.patch new file mode 100644 index 0000000..2af98d8 --- /dev/null +++ b/backport-CVE-2024-0727-fix-pkcs12-decoding-crashes.patch @@ -0,0 +1,111 @@ +From 09015a582baa980dc04f635504b16fe95dc3790b Mon Sep 17 00:00:00 2001 +From: liwei +Date: Fri, 26 Jan 2024 18:45:28 +0800 +Subject: [PATCH] fix CVE-2024-0727 + +Add NULL checks where ContentInfo data can be NULL + +--- + crypto/pkcs12/p12_add.c | 16 ++++++++++++++++ + crypto/pkcs12/p12_mutl.c | 5 +++++ + crypto/pkcs12/p12_npas.c | 5 +++-- + crypto/pkcs7/pk7_mime.c | 8 ++++++-- + 4 files changed, 30 insertions(+), 4 deletions(-) + +diff --git a/crypto/pkcs12/p12_add.c b/crypto/pkcs12/p12_add.c +index af184c86af..9b40e5384e 100644 +--- a/crypto/pkcs12/p12_add.c ++++ b/crypto/pkcs12/p12_add.c +@@ -76,6 +76,12 @@ STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7) + PKCS12_R_CONTENT_TYPE_NOT_DATA); + return NULL; + } ++ ++ if (p7->d.data == NULL) { ++ PKCS12err(PKCS12_F_PKCS12_UNPACK_P7DATA, PKCS12_R_DECODE_ERROR); ++ return NULL; ++ } ++ + return ASN1_item_unpack(p7->d.data, ASN1_ITEM_rptr(PKCS12_SAFEBAGS)); + } + +@@ -132,6 +138,11 @@ STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass, + { + if (!PKCS7_type_is_encrypted(p7)) + return NULL; ++ ++ if (p7->d.encrypted == NULL) { ++ return NULL; ++ } ++ + return PKCS12_item_decrypt_d2i(p7->d.encrypted->enc_data->algorithm, + ASN1_ITEM_rptr(PKCS12_SAFEBAGS), + pass, passlen, +@@ -159,6 +170,11 @@ STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12) + PKCS12_R_CONTENT_TYPE_NOT_DATA); + return NULL; + } ++ if (p12->authsafes->d.data == NULL) { ++ PKCS12err(PKCS12_F_PKCS12_UNPACK_AUTHSAFES, PKCS12_R_DECODE_ERROR); ++ return NULL; ++ } ++ + return ASN1_item_unpack(p12->authsafes->d.data, + ASN1_ITEM_rptr(PKCS12_AUTHSAFES)); + } +diff --git a/crypto/pkcs12/p12_mutl.c b/crypto/pkcs12/p12_mutl.c +index 3658003fe5..766c9c1e9d 100644 +--- a/crypto/pkcs12/p12_mutl.c ++++ b/crypto/pkcs12/p12_mutl.c +@@ -93,6 +93,11 @@ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + return 0; + } + ++ if (p12->authsafes->d.data == NULL) { ++ PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_DECODE_ERROR); ++ return 0; ++ } ++ + salt = p12->mac->salt->data; + saltlen = p12->mac->salt->length; + if (!p12->mac->iter) +diff --git a/crypto/pkcs12/p12_npas.c b/crypto/pkcs12/p12_npas.c +index 0334289a89..130337638d 100644 +--- a/crypto/pkcs12/p12_npas.c ++++ b/crypto/pkcs12/p12_npas.c +@@ -78,8 +78,9 @@ static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass) + bags = PKCS12_unpack_p7data(p7); + } else if (bagnid == NID_pkcs7_encrypted) { + bags = PKCS12_unpack_p7encdata(p7, oldpass, -1); +- if (!alg_get(p7->d.encrypted->enc_data->algorithm, +- &pbe_nid, &pbe_iter, &pbe_saltlen)) ++ if (p7->d.encrypted == NULL ++ || !alg_get(p7->d.encrypted->enc_data->algorithm, ++ &pbe_nid, &pbe_iter, &pbe_saltlen)) + goto err; + } else { + continue; +diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c +index 19e6868148..b457108c94 100644 +--- a/crypto/pkcs7/pk7_mime.c ++++ b/crypto/pkcs7/pk7_mime.c +@@ -30,10 +30,14 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags) + { + STACK_OF(X509_ALGOR) *mdalgs; + int ctype_nid = OBJ_obj2nid(p7->type); +- if (ctype_nid == NID_pkcs7_signed) ++ ++ if (ctype_nid == NID_pkcs7_signed) { ++ if (p7->d.sign == NULL) ++ return 0; + mdalgs = p7->d.sign->md_algs; +- else ++ } else { + mdalgs = NULL; ++ } + + flags ^= SMIME_OLDMIME; + +-- +2.28.0.1 + diff --git a/backport-CVE-2024-2511-Fix-unconstrained-session-cache-growth-in-TLSv1.3.patch b/backport-CVE-2024-2511-Fix-unconstrained-session-cache-growth-in-TLSv1.3.patch new file mode 100644 index 0000000..c74d682 --- /dev/null +++ b/backport-CVE-2024-2511-Fix-unconstrained-session-cache-growth-in-TLSv1.3.patch @@ -0,0 +1,173 @@ +From 722e734a9265530db1a41a4604d21c03b1ba1733 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Tue, 5 Mar 2024 15:43:53 +0000 +Subject: [PATCH] Fix unconstrained session cache growth in TLSv1.3 + +In TLSv1.3 we create a new session object for each ticket that we send. +We do this by duplicating the original session. If SSL_OP_NO_TICKET is in +use then the new session will be added to the session cache. However, if +early data is not in use (and therefore anti-replay protection is being +used), then multiple threads could be resuming from the same session +simultaneously. If this happens and a problem occurs on one of the threads, +then the original session object could be marked as not_resumable. When we +duplicate the session object this not_resumable status gets copied into the +new session object. The new session object is then added to the session +cache even though it is not_resumable. + +Subsequently, another bug means that the session_id_length is set to 0 for +sessions that are marked as not_resumable - even though that session is +still in the cache. Once this happens the session can never be removed from +the cache. When that object gets to be the session cache tail object the +cache never shrinks again and grows indefinitely. + +CVE-2024-2511 + +Reviewed-by: Neil Horman +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/24044) + +(cherry picked from commit 7e4d731b1c07201ad9374c1cd9ac5263bdf35bce) +Signed-off-by: Liu-Ermeng +--- + include/openssl/sslerr.h | 4 ++-- + ssl/ssl_err.c | 5 +++-- + ssl/ssl_lib.c | 5 +++-- + ssl/ssl_sess.c | 30 +++++++++++++++++++++++------- + ssl/statem/statem_srvr.c | 5 ++--- + 5 files changed, 33 insertions(+), 16 deletions(-) + +diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h +index aa5f56a482..3e99ffc27f 100644 +--- a/include/openssl/sslerr.h ++++ b/include/openssl/sslerr.h +@@ -1,6 +1,6 @@ + /* + * Generated by util/mkerr.pl DO NOT EDIT +- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. ++ * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy +@@ -224,7 +224,7 @@ int ERR_load_SSL_strings(void); + # define SSL_F_SSL_RENEGOTIATE_ABBREVIATED 546 + # define SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT 320 + # define SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT 321 +-# define SSL_F_SSL_SESSION_DUP 348 ++# define SSL_F_SSL_SESSION_DUP_INTERN 668 + # define SSL_F_SSL_SESSION_NEW 189 + # define SSL_F_SSL_SESSION_PRINT_FP 190 + # define SSL_F_SSL_SESSION_SET1_ID 423 +diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c +index 5a7c42a88c..c4144bb8b4 100644 +--- a/ssl/ssl_err.c ++++ b/ssl/ssl_err.c +@@ -1,6 +1,6 @@ + /* + * Generated by util/mkerr.pl DO NOT EDIT +- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. ++ * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy +@@ -325,7 +325,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { + "SSL_renegotiate_abbreviated"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, 0), ""}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, 0), ""}, +- {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_DUP, 0), "ssl_session_dup"}, ++ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_DUP_INTERN, 0), ++ "ssl_session_dup_intern"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_NEW, 0), "SSL_SESSION_new"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_PRINT_FP, 0), + "SSL_SESSION_print_fp"}, +diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c +index 618549a2ca..2a44960fac 100644 +--- a/ssl/ssl_lib.c ++++ b/ssl/ssl_lib.c +@@ -3541,9 +3541,10 @@ void ssl_update_cache(SSL *s, int mode) + + /* + * If the session_id_length is 0, we are not supposed to cache it, and it +- * would be rather hard to do anyway :-) ++ * would be rather hard to do anyway :-). Also if the session has already ++ * been marked as not_resumable we should not cache it for later reuse. + */ +- if (s->session->session_id_length == 0) ++ if (s->session->session_id_length == 0 || s->session->not_resumable) + return; + + /* +diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c +index 1b4c85b60c..28affe0a26 100644 +--- a/ssl/ssl_sess.c ++++ b/ssl/ssl_sess.c +@@ -94,16 +94,11 @@ SSL_SESSION *SSL_SESSION_new(void) + return ss; + } + +-SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *src) +-{ +- return ssl_session_dup(src, 1); +-} +- + /* + * Create a new SSL_SESSION and duplicate the contents of |src| into it. If + * ticket == 0 then no ticket information is duplicated, otherwise it is. + */ +-SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) ++static SSL_SESSION *ssl_session_dup_intern(SSL_SESSION *src, int ticket) + { + SSL_SESSION *dest; + +@@ -221,11 +216,32 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) + + return dest; + err: +- SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE); ++ SSLerr(SSL_F_SSL_SESSION_DUP_INTERN, ERR_R_MALLOC_FAILURE); + SSL_SESSION_free(dest); + return NULL; + } + ++SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *src) ++{ ++ return ssl_session_dup_intern(src, 1); ++} ++ ++/* ++ * Used internally when duplicating a session which might be already shared. ++ * We will have resumed the original session. Subsequently we might have marked ++ * it as non-resumable (e.g. in another thread) - but this copy should be ok to ++ * resume from. ++ */ ++SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) ++{ ++ SSL_SESSION *sess = ssl_session_dup_intern(src, ticket); ++ ++ if (sess != NULL) ++ sess->not_resumable = 0; ++ ++ return sess; ++} ++ + const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) + { + if (len) +diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c +index 1b3b8002ee..d242e98024 100644 +--- a/ssl/statem/statem_srvr.c ++++ b/ssl/statem/statem_srvr.c +@@ -2418,9 +2418,8 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) + * so the following won't overwrite an ID that we're supposed + * to send back. + */ +- if (s->session->not_resumable || +- (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) +- && !s->hit)) ++ if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) ++ && !s->hit) + s->session->session_id_length = 0; + + if (usetls13) { +-- +2.33.0 + diff --git a/backport-Extend-the-multi_resume-test-for-simultaneous-resump.patch b/backport-Extend-the-multi_resume-test-for-simultaneous-resump.patch new file mode 100644 index 0000000..c74edca --- /dev/null +++ b/backport-Extend-the-multi_resume-test-for-simultaneous-resump.patch @@ -0,0 +1,152 @@ +From cf1f5d212c9d30d2a1996b7426cf8483205e8491 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Tue, 5 Mar 2024 15:35:51 +0000 +Subject: [PATCH] Extend the multi_resume test for simultaneous resumptions + +Test what happens if the same session gets resumed multiple times at the +same time - and one of them gets marked as not_resumable. + +Related to CVE-2024-2511 + +Reviewed-by: Neil Horman +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/24044) + +(cherry picked from commit 031b11a4054c972a5e2f07dfa81ce1842453253e) +Signed-off-by: Liu-Ermeng +--- + test/sslapitest.c | 87 ++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 84 insertions(+), 3 deletions(-) + +diff --git a/test/sslapitest.c b/test/sslapitest.c +index 2992356fdf..472b1224ca 100644 +--- a/test/sslapitest.c ++++ b/test/sslapitest.c +@@ -7288,12 +7288,63 @@ static int test_inherit_verify_param(void) + return testresult; + } + ++struct resume_servername_cb_data { ++ int i; ++ SSL_CTX *cctx; ++ SSL_CTX *sctx; ++ SSL_SESSION *sess; ++ int recurse; ++}; ++ ++/* ++ * Servername callback. We use it here to run another complete handshake using ++ * the same session - and mark the session as not_resuamble at the end ++ */ ++static int resume_servername_cb(SSL *s, int *ad, void *arg) ++{ ++ struct resume_servername_cb_data *cbdata = arg; ++ SSL *serverssl = NULL, *clientssl = NULL; ++ int ret = SSL_TLSEXT_ERR_ALERT_FATAL; ++ ++ if (cbdata->recurse) ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ ++ if ((cbdata->i % 3) != 1) ++ return SSL_TLSEXT_ERR_OK; ++ ++ cbdata->recurse = 1; ++ ++ if (!TEST_true(create_ssl_objects(cbdata->sctx, cbdata->cctx, &serverssl, ++ &clientssl, NULL, NULL)) ++ || !TEST_true(SSL_set_session(clientssl, cbdata->sess))) ++ goto end; ++ ++ ERR_set_mark(); ++ /* ++ * We expect this to fail - because the servername cb will fail. This will ++ * mark the session as not_resumable. ++ */ ++ if (!TEST_false(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) { ++ ERR_clear_last_mark(); ++ goto end; ++ } ++ ERR_pop_to_mark(); ++ ++ ret = SSL_TLSEXT_ERR_OK; ++ end: ++ SSL_free(serverssl); ++ SSL_free(clientssl); ++ cbdata->recurse = 0; ++ return ret; ++} ++ + /* + * Test multiple resumptions and cache size handling + * Test 0: TLSv1.3 (max_early_data set) + * Test 1: TLSv1.3 (SSL_OP_NO_TICKET set) + * Test 2: TLSv1.3 (max_early_data and SSL_OP_NO_TICKET set) +- * Test 3: TLSv1.2 ++ * Test 3: TLSv1.3 (SSL_OP_NO_TICKET, simultaneous resumes) ++ * Test 4: TLSv1.2 + */ + static int test_multi_resume(int idx) + { +@@ -7302,9 +7353,19 @@ static int test_multi_resume(int idx) + SSL_SESSION *sess = NULL; + int max_version = TLS1_3_VERSION; + int i, testresult = 0; ++ struct resume_servername_cb_data cbdata; + +- if (idx == 3) ++#if defined(OPENSSL_NO_TLS1_2) ++ if (idx == 4) ++ return TEST_skip("TLSv1.2 is disabled in this build"); ++#else ++ if (idx == 4) + max_version = TLS1_2_VERSION; ++#endif ++#if defined(OSSL_NO_USABLE_TLS1_3) ++ if (idx != 4) ++ return TEST_skip("No usable TLSv1.3 in this build"); ++#endif + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), + TLS_client_method(), TLS1_VERSION, +@@ -7320,17 +7381,37 @@ static int test_multi_resume(int idx) + if (!TEST_true(SSL_CTX_set_max_early_data(sctx, 1024))) + goto end; + } +- if (idx == 1 || idx == 2) ++ if (idx == 1 || idx == 2 || idx == 3) + SSL_CTX_set_options(sctx, SSL_OP_NO_TICKET); + + SSL_CTX_sess_set_cache_size(sctx, 5); + ++ if (idx == 3) { ++ SSL_CTX_set_tlsext_servername_callback(sctx, resume_servername_cb); ++ SSL_CTX_set_tlsext_servername_arg(sctx, &cbdata); ++ cbdata.cctx = cctx; ++ cbdata.sctx = sctx; ++ cbdata.recurse = 0; ++ } ++ + for (i = 0; i < 30; i++) { + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + || !TEST_true(SSL_set_session(clientssl, sess))) + goto end; + ++ /* ++ * Check simultaneous resumes. We pause the connection part way through ++ * the handshake by (mis)using the servername_cb. The pause occurs after ++ * session resumption has already occurred, but before any session ++ * tickets have been issued. While paused we run another complete ++ * handshake resuming the same session. ++ */ ++ if (idx == 3) { ++ cbdata.i = i; ++ cbdata.sess = sess; ++ } ++ + /* + * Recreate a bug where dynamically changing the max_early_data value + * can cause sessions in the session cache which cannot be deleted. +-- +2.33.0 + diff --git a/backport-Fix-EVP_PKEY_asn1_copy.patch b/backport-Fix-EVP_PKEY_asn1_copy.patch new file mode 100644 index 0000000..ccfe909 --- /dev/null +++ b/backport-Fix-EVP_PKEY_asn1_copy.patch @@ -0,0 +1,52 @@ +From 47793328424b4d61956eb7c06d601680c233987d Mon Sep 17 00:00:00 2001 +From: hangze +Date: Thu, 3 Aug 2023 03:38:29 +0000 +Subject: [PATCH] Fix EVP_PKEY_asn1_copy + +Add the copy of the omitted ASN1 public key method and +other members. + +Reviewed-by: Bernd Edlinger +Reviewed-by: Dmitry Belyavskiy +(Merged from https://github.com/openssl/openssl/pull/21125) +--- + crypto/asn1/ameth_lib.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/crypto/asn1/ameth_lib.c b/crypto/asn1/ameth_lib.c +index 5e8c3ed1d5..228dbef40d 100644 +--- a/crypto/asn1/ameth_lib.c ++++ b/crypto/asn1/ameth_lib.c +@@ -264,6 +264,7 @@ void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst, + + dst->pkey_size = src->pkey_size; + dst->pkey_bits = src->pkey_bits; ++ dst->pkey_security_bits = src->pkey_security_bits; + + dst->param_decode = src->param_decode; + dst->param_encode = src->param_encode; +@@ -271,6 +272,7 @@ void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst, + dst->param_copy = src->param_copy; + dst->param_cmp = src->param_cmp; + dst->param_print = src->param_print; ++ dst->sig_print = src->sig_print; + + dst->pkey_free = src->pkey_free; + dst->pkey_ctrl = src->pkey_ctrl; +@@ -281,6 +283,13 @@ void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst, + dst->siginf_set = src->siginf_set; + + dst->pkey_check = src->pkey_check; ++ dst->pkey_public_check = src->pkey_public_check; ++ dst->pkey_param_check = src->pkey_param_check; ++ ++ dst->set_priv_key = src->set_priv_key; ++ dst->set_pub_key = src->set_pub_key; ++ dst->get_priv_key = src->get_priv_key; ++ dst->get_pub_key = src->get_pub_key; + + } + +-- +2.33.0 + diff --git a/backport-Fix-a-possbile-memleak-in-rsa_pub_encode.patch b/backport-Fix-a-possbile-memleak-in-rsa_pub_encode.patch new file mode 100644 index 0000000..a71ea61 --- /dev/null +++ b/backport-Fix-a-possbile-memleak-in-rsa_pub_encode.patch @@ -0,0 +1,66 @@ +From b13ef5e90a1d9c73f6c548ab5557a939a09744e0 Mon Sep 17 00:00:00 2001 +From: Bernd Edlinger +Date: Thu, 7 Sep 2023 19:22:25 +0200 +Subject: [PATCH] Fix a possbile memleak in rsa_pub_encode + +That seems to be only an issue for RSA-PSS with parameters. +Spotted by code review, so it looks like there is no test coverage for this. + +Reviewed-by: Tomas Mraz +Reviewed-by: Hugo Landau +(Merged from https://github.com/openssl/openssl/pull/22007) +--- + crypto/rsa/rsa_ameth.c | 5 ++++- + test/recipes/15-test_rsapss.t | 10 +++++++++- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c +index 2c9c46ea53..63efd93798 100644 +--- a/crypto/rsa/rsa_ameth.c ++++ b/crypto/rsa/rsa_ameth.c +@@ -82,13 +82,16 @@ static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) + if (!rsa_param_encode(pkey, &str, &strtype)) + return 0; + penclen = i2d_RSAPublicKey(pkey->pkey.rsa, &penc); +- if (penclen <= 0) ++ if (penclen <= 0) { ++ ASN1_STRING_free(str); + return 0; ++ } + if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id), + strtype, str, penc, penclen)) + return 1; + + OPENSSL_free(penc); ++ ASN1_STRING_free(str); + return 0; + } + +diff --git a/test/recipes/15-test_rsapss.t b/test/recipes/15-test_rsapss.t +index 65ec6f3d75..61c13b6a49 100644 +--- a/test/recipes/15-test_rsapss.t ++++ b/test/recipes/15-test_rsapss.t +@@ -16,7 +16,7 @@ use OpenSSL::Test::Utils; + + setup("test_rsapss"); + +-plan tests => 5; ++plan tests => 7; + + #using test/testrsa.pem which happens to be a 512 bit RSA + ok(run(app(['openssl', 'dgst', '-sign', srctop_file('test', 'testrsa.pem'), '-sha1', +@@ -47,3 +47,11 @@ ok(run(app(['openssl', 'dgst', '-prverify', srctop_file('test', 'testrsa.pem'), + srctop_file('test', 'testrsa.pem')])), + "openssl dgst -prverify"); + unlink 'testrsapss.sig'; ++ ++ok(run(app(['openssl', 'genpkey', '-algorithm', 'RSA-PSS', '-pkeyopt', 'rsa_keygen_bits:1024', ++ '-pkeyopt', 'rsa_pss_keygen_md:SHA256', '-pkeyopt', 'rsa_pss_keygen_saltlen:10', ++ '-out', 'testrsapss.pem'])), ++ "openssl genpkey RSA-PSS with pss parameters"); ++ok(run(app(['openssl', 'pkey', '-in', 'testrsapss.pem', '-pubout', '-text'])), ++ "openssl pkey, execute rsa_pub_encode with pss parameters"); ++unlink 'testrsapss.pem'; +-- +2.33.0 + diff --git a/backport-Fix-a-possible-memleak-in-eckey_priv_encode.patch b/backport-Fix-a-possible-memleak-in-eckey_priv_encode.patch new file mode 100644 index 0000000..619c51d --- /dev/null +++ b/backport-Fix-a-possible-memleak-in-eckey_priv_encode.patch @@ -0,0 +1,76 @@ +From 7c51c0e56a0f21912f4504c7a06c21eb4bc43c85 Mon Sep 17 00:00:00 2001 +From: Bernd Edlinger +Date: Thu, 7 Sep 2023 17:38:50 +0200 +Subject: [PATCH] Fix a possible memleak in eckey_priv_encode + +Additionally use OPENSSL_clear_free on the private +key data in case of error. + +Reviewed-by: Tomas Mraz +Reviewed-by: Hugo Landau +(Merged from https://github.com/openssl/openssl/pull/22007) +--- + crypto/ec/ec_ameth.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c +index 5098bd7a66..c48b7cb754 100644 +--- a/crypto/ec/ec_ameth.c ++++ b/crypto/ec/ec_ameth.c +@@ -38,7 +38,6 @@ static int eckey_param2type(int *pptype, void **ppval, const EC_KEY *ec_key) + ASN1_OBJECT *asn1obj = OBJ_nid2obj(nid); + + if (asn1obj == NULL || OBJ_length(asn1obj) == 0) { +- ASN1_OBJECT_free(asn1obj); + ECerr(EC_F_ECKEY_PARAM2TYPE, EC_R_MISSING_OID); + return 0; + } +@@ -98,9 +97,7 @@ static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) + ptype, pval, penc, penclen)) + return 1; + err: +- if (ptype == V_ASN1_OBJECT) +- ASN1_OBJECT_free(pval); +- else ++ if (ptype == V_ASN1_SEQUENCE) + ASN1_STRING_free(pval); + OPENSSL_free(penc); + return 0; +@@ -256,24 +253,32 @@ static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) + + eplen = i2d_ECPrivateKey(&ec_key, NULL); + if (!eplen) { ++ if (ptype == V_ASN1_SEQUENCE) ++ ASN1_STRING_free(pval); + ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB); + return 0; + } + ep = OPENSSL_malloc(eplen); + if (ep == NULL) { ++ if (ptype == V_ASN1_SEQUENCE) ++ ASN1_STRING_free(pval); + ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); + return 0; + } + p = ep; + if (!i2d_ECPrivateKey(&ec_key, &p)) { +- OPENSSL_free(ep); ++ OPENSSL_clear_free(ep, eplen); ++ if (ptype == V_ASN1_SEQUENCE) ++ ASN1_STRING_free(pval); + ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB); + return 0; + } + + if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), 0, + ptype, pval, ep, eplen)) { +- OPENSSL_free(ep); ++ OPENSSL_clear_free(ep, eplen); ++ if (ptype == V_ASN1_SEQUENCE) ++ ASN1_STRING_free(pval); + return 0; + } + +-- +2.33.0 + diff --git a/backport-Fix-error-handling-in-CMS_EncryptedData_encrypt.patch b/backport-Fix-error-handling-in-CMS_EncryptedData_encrypt.patch new file mode 100644 index 0000000..46e79f6 --- /dev/null +++ b/backport-Fix-error-handling-in-CMS_EncryptedData_encrypt.patch @@ -0,0 +1,170 @@ +From 13dd772f61d149628a768d987828aa6dbc72fb31 Mon Sep 17 00:00:00 2001 +From: Bernd Edlinger +Date: Thu, 7 Sep 2023 18:05:44 +0200 +Subject: [PATCH] Fix error handling in CMS_EncryptedData_encrypt + +That caused several memory leaks in case of error. +Also when the CMS object that is created by CMS_EncryptedData_encrypt +is not used in the normal way, but instead just deleted +by CMS_ContentInfo_free some memory was lost. + +Fixes #21985 + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/22008) +--- + crypto/cms/cms_asn1.c | 15 +++++++++++++-- + crypto/cms/cms_local.h | 1 + + crypto/cms/cms_sd.c | 14 +++++++++++++- + crypto/cms/cms_smime.c | 3 ++- + test/recipes/80-test_cms.t | 7 +++++++ + 7 files changed, 36 insertions(+), 4 deletions(-) + +diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c +index 08069d72a2..d006ada998 100644 +--- a/crypto/cms/cms_asn1.c ++++ b/crypto/cms/cms_asn1.c +@@ -51,6 +51,7 @@ static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + EVP_PKEY_free(si->pkey); + X509_free(si->signer); + EVP_MD_CTX_free(si->mctx); ++ EVP_PKEY_CTX_free(si->pctx); + } + return 1; + } +@@ -89,11 +90,21 @@ ASN1_SEQUENCE(CMS_OriginatorInfo) = { + ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, crls, CMS_RevocationInfoChoice, 1) + } static_ASN1_SEQUENCE_END(CMS_OriginatorInfo) + +-ASN1_NDEF_SEQUENCE(CMS_EncryptedContentInfo) = { ++static int cms_ec_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ CMS_EncryptedContentInfo *ec = (CMS_EncryptedContentInfo *)*pval; ++ ++ if (operation == ASN1_OP_FREE_POST) ++ OPENSSL_clear_free(ec->key, ec->keylen); ++ return 1; ++} ++ ++ASN1_NDEF_SEQUENCE_cb(CMS_EncryptedContentInfo, cms_ec_cb) = { + ASN1_SIMPLE(CMS_EncryptedContentInfo, contentType, ASN1_OBJECT), + ASN1_SIMPLE(CMS_EncryptedContentInfo, contentEncryptionAlgorithm, X509_ALGOR), + ASN1_IMP_OPT(CMS_EncryptedContentInfo, encryptedContent, ASN1_OCTET_STRING_NDEF, 0) +-} static_ASN1_NDEF_SEQUENCE_END(CMS_EncryptedContentInfo) ++} ASN1_NDEF_SEQUENCE_END_cb(CMS_EncryptedContentInfo, CMS_EncryptedContentInfo) + + ASN1_SEQUENCE(CMS_KeyTransRecipientInfo) = { + ASN1_EMBED(CMS_KeyTransRecipientInfo, version, INT32), +diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h +index a0ce4448f6..b275bddf75 100644 +--- a/crypto/cms/cms_local.h ++++ b/crypto/cms/cms_local.h +@@ -342,6 +342,7 @@ struct CMS_Receipt_st { + + DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo) + DECLARE_ASN1_ITEM(CMS_SignerInfo) ++DECLARE_ASN1_ITEM(CMS_EncryptedContentInfo) + DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber) + DECLARE_ASN1_ITEM(CMS_Attributes_Sign) + DECLARE_ASN1_ITEM(CMS_Attributes_Verify) +diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c +index 3f2a782565..708b443704 100644 +--- a/crypto/cms/cms_sd.c ++++ b/crypto/cms/cms_sd.c +@@ -375,6 +375,8 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, + } else if (EVP_DigestSignInit(si->mctx, &si->pctx, md, NULL, pk) <= + 0) + goto err; ++ else ++ EVP_MD_CTX_set_flags(si->mctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX); + } + + if (!sd->signerInfos) +@@ -600,6 +602,7 @@ static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms, + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + pctx = si->pctx; ++ si->pctx = NULL; + if (!EVP_DigestFinal_ex(mctx, md, &mdlen)) + goto err; + siglen = EVP_PKEY_size(si->pkey); +@@ -680,6 +683,7 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si) + EVP_MD_CTX_reset(mctx); + if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0) + goto err; ++ EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX); + si->pctx = pctx; + } + +@@ -745,8 +749,13 @@ int CMS_SignerInfo_verify(CMS_SignerInfo *si) + return -1; + } + mctx = si->mctx; ++ if (si->pctx != NULL) { ++ EVP_PKEY_CTX_free(si->pctx); ++ si->pctx = NULL; ++ } + if (EVP_DigestVerifyInit(mctx, &si->pctx, md, NULL, si->pkey) <= 0) + goto err; ++ EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX); + + if (!cms_sd_asn1_ctrl(si, 1)) + goto err; +@@ -859,8 +868,11 @@ int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain) + if (EVP_PKEY_CTX_set_signature_md(pkctx, md) <= 0) + goto err; + si->pctx = pkctx; +- if (!cms_sd_asn1_ctrl(si, 1)) ++ if (!cms_sd_asn1_ctrl(si, 1)) { ++ si->pctx = NULL; + goto err; ++ } ++ si->pctx = NULL; + r = EVP_PKEY_verify(pkctx, si->signature->data, + si->signature->length, mval, mlen); + if (r <= 0) { +diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c +index 6e7dbc4da1..8f3a9fbaeb 100644 +--- a/crypto/cms/cms_smime.c ++++ b/crypto/cms/cms_smime.c +@@ -211,7 +211,7 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, + if (cms == NULL) + return NULL; + if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) +- return NULL; ++ goto err; + + if (!(flags & CMS_DETACHED)) + CMS_set_detached(cms, 0); +@@ -220,6 +220,7 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, + || CMS_final(cms, in, NULL, flags)) + return cms; + ++ err: + CMS_ContentInfo_free(cms); + return NULL; + } + +diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t +index adb60e1436..544d4466b5 100644 +--- a/test/recipes/80-test_cms.t ++++ b/test/recipes/80-test_cms.t +@@ -288,6 +288,13 @@ my @smime_cms_tests = ( + "-secretkey", "000102030405060708090A0B0C0D0E0F", "-out", "smtst.txt" ] + ], + ++ [ "encrypted content test streaming PEM format -noout, 128 bit AES key", ++ [ "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM", ++ "-aes128", "-secretkey", "000102030405060708090A0B0C0D0E0F", ++ "-stream", "-noout" ], ++ [ "-help" ] ++ ], ++ + ); + + my @smime_cms_comp_tests = ( +-- +2.33.0 + diff --git a/backport-Fix-mem-leaks-on-PKCS-12-read-error-in-PKCS12_key_ge.patch b/backport-Fix-mem-leaks-on-PKCS-12-read-error-in-PKCS12_key_ge.patch new file mode 100644 index 0000000..42f8fb7 --- /dev/null +++ b/backport-Fix-mem-leaks-on-PKCS-12-read-error-in-PKCS12_key_ge.patch @@ -0,0 +1,43 @@ +From ed4faae00cdab23244704660c099e41ec64f5dc0 Mon Sep 17 00:00:00 2001 +From: "Dr. David von Oheimb" +Date: Wed, 12 Aug 2020 17:37:50 +0200 +Subject: [PATCH] Fix mem leaks on PKCS#12 read error in + PKCS12_key_gen_{asc,utf8} + +Reviewed-by: Richard Levitte +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/12639) +--- + crypto/pkcs12/p12_key.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/crypto/pkcs12/p12_key.c b/crypto/pkcs12/p12_key.c +index a40ae4cbe8..bbe212d125 100644 +--- a/crypto/pkcs12/p12_key.c ++++ b/crypto/pkcs12/p12_key.c +@@ -44,10 +44,8 @@ int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt, + } + ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen, + id, iter, n, out, md_type); +- if (ret <= 0) +- return 0; + OPENSSL_clear_free(unipass, uniplen); +- return ret; ++ return ret > 0; + } + + int PKCS12_key_gen_utf8(const char *pass, int passlen, unsigned char *salt, +@@ -67,10 +65,8 @@ int PKCS12_key_gen_utf8(const char *pass, int passlen, unsigned char *salt, + } + ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen, + id, iter, n, out, md_type); +- if (ret <= 0) +- return 0; + OPENSSL_clear_free(unipass, uniplen); +- return ret; ++ return ret > 0; + } + + int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, +-- +2.27.0 diff --git a/backport-Fix-stack-corruption-in-ui_read.patch b/backport-Fix-stack-corruption-in-ui_read.patch new file mode 100755 index 0000000..cbe986a --- /dev/null +++ b/backport-Fix-stack-corruption-in-ui_read.patch @@ -0,0 +1,64 @@ +From 0f90c4de9f58070a423003ec6b34ef1a9a670ec9 Mon Sep 17 00:00:00 2001 +From: Bernd Edlinger +Date: Sat, 13 May 2023 09:04:18 +0200 +Subject: [PATCH] Fix stack corruption in ui_read + +This is an alternative to #20893 + +Additionally this fixes also a possible issue in UI_UTIL_read_pw: + +When UI_new returns NULL, the result code would still be zero +as if UI_UTIL_read_pw succeeded, but the password buffer is left +uninitialized, with subsequent possible stack corruption or worse. + +Reviewed-by: Richard Levitte +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/20957) + +(cherry picked from commit a64c48cff88e032cf9513578493c4536df725a22) + +--- + crypto/ui/ui_lib.c | 4 ++++ + crypto/ui/ui_util.c | 4 +--- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/crypto/ui/ui_lib.c b/crypto/ui/ui_lib.c +index 49cc45057c..daf11c7a0d 100644 +--- a/crypto/ui/ui_lib.c ++++ b/crypto/ui/ui_lib.c +@@ -529,6 +529,10 @@ int UI_process(UI *ui) + ok = 0; + break; + } ++ } else { ++ ui->flags &= ~UI_FLAG_REDOABLE; ++ ok = -2; ++ goto err; + } + } + +diff --git a/crypto/ui/ui_util.c b/crypto/ui/ui_util.c +index 32a3c4e38d..e582252da6 100644 +--- a/crypto/ui/ui_util.c ++++ b/crypto/ui/ui_util.c +@@ -32,7 +32,7 @@ int UI_UTIL_read_pw_string(char *buf, int length, const char *prompt, + int UI_UTIL_read_pw(char *buf, char *buff, int size, const char *prompt, + int verify) + { +- int ok = 0; ++ int ok = -2; + UI *ui; + + if (size < 1) +@@ -47,8 +47,6 @@ int UI_UTIL_read_pw(char *buf, char *buff, int size, const char *prompt, + ok = UI_process(ui); + UI_free(ui); + } +- if (ok > 0) +- ok = 0; + return ok; + } + +-- +2.27.0 + diff --git a/backport-Hardening-around-not_resumable-sessions.patch b/backport-Hardening-around-not_resumable-sessions.patch new file mode 100644 index 0000000..9c19c3a --- /dev/null +++ b/backport-Hardening-around-not_resumable-sessions.patch @@ -0,0 +1,39 @@ +From 9b79e20ed347f90ed23bfc8e5be2259231fd0a34 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Fri, 15 Mar 2024 17:58:42 +0000 +Subject: [PATCH] Hardening around not_resumable sessions + +Make sure we can't inadvertently use a not_resumable session + +Related to CVE-2024-2511 + +Reviewed-by: Neil Horman +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/24044) + +(cherry picked from commit c342f4b8bd2d0b375b0e22337057c2eab47d9b96) +Signed-off-by: Liu-Ermeng +--- + ssl/ssl_sess.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c +index 28affe0a26..5cc816b0fc 100644 +--- a/ssl/ssl_sess.c ++++ b/ssl/ssl_sess.c +@@ -471,6 +471,12 @@ SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id, + ret = s->session_ctx->get_session_cb(s, sess_id, sess_id_len, ©); + + if (ret != NULL) { ++ if (ret->not_resumable) { ++ /* If its not resumable then ignore this session */ ++ if (!copy) ++ SSL_SESSION_free(ret); ++ return NULL; ++ } + tsan_counter(&s->session_ctx->stats.sess_cb_hit); + + /* +-- +2.33.0 + diff --git a/backport-Make-DH_check-set-some-error-bits-in-recently-added-.patch b/backport-Make-DH_check-set-some-error-bits-in-recently-added-.patch new file mode 100644 index 0000000..271c481 --- /dev/null +++ b/backport-Make-DH_check-set-some-error-bits-in-recently-added-.patch @@ -0,0 +1,37 @@ +From eec805ee71356c06f9a86192fa06507c3bb92b09 Mon Sep 17 00:00:00 2001 +From: Bernd Edlinger +Date: Sun, 23 Jul 2023 14:27:54 +0200 +Subject: [PATCH] Make DH_check set some error bits in recently added error + +The pre-existing error cases where DH_check returned zero +are not related to the dh params in any way, but are only +triggered by out-of-memory errors, therefore having *ret +set to zero feels right, but since the new error case is +triggered by too large p values that is something different. +On the other hand some callers of this function might not +be prepared to handle the return value correctly but only +rely on *ret. Therefore we set some error bits in *ret as +additional safety measure. + +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/21533) +--- + crypto/dh/dh_check.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c +index e5f9dd5030..2001d2e7cb 100644 +--- a/crypto/dh/dh_check.c ++++ b/crypto/dh/dh_check.c +@@ -104,6 +104,7 @@ int DH_check(const DH *dh, int *ret) + /* Don't do any checks at all with an excessively large modulus */ + if (BN_num_bits(dh->p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { + DHerr(DH_F_DH_CHECK, DH_R_MODULUS_TOO_LARGE); ++ *ret = DH_CHECK_P_NOT_PRIME; + return 0; + } + +-- +2.27.0 + diff --git a/backport-Re-add-BN_F_OSSL_BN_RSA_DO_UNBLIND-which-was-incorre.patch b/backport-Re-add-BN_F_OSSL_BN_RSA_DO_UNBLIND-which-was-incorre.patch new file mode 100644 index 0000000..983e1fa --- /dev/null +++ b/backport-Re-add-BN_F_OSSL_BN_RSA_DO_UNBLIND-which-was-incorre.patch @@ -0,0 +1,30 @@ +From 8daa2616bbe6f7994e0cdd796d3280118c51d8d8 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Thu, 20 Apr 2023 10:24:38 +0200 +Subject: [PATCH] Re-add BN_F_OSSL_BN_RSA_DO_UNBLIND which was incorrectly + removed + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Matt Caswell +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/20784) + +--- + include/openssl/bnerr.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/openssl/bnerr.h b/include/openssl/bnerr.h +index a703efc92b..5c83777f9f 100644 +--- a/include/openssl/bnerr.h ++++ b/include/openssl/bnerr.h +@@ -72,6 +72,7 @@ int ERR_load_BN_strings(void); + # define BN_F_BN_SET_WORDS 144 + # define BN_F_BN_STACK_PUSH 148 + # define BN_F_BN_USUB 115 ++# define BN_F_OSSL_BN_RSA_DO_UNBLIND 151 + + /* + * BN reason codes. +-- +2.27.0 + diff --git a/backport-apps-passwd.c-free-before-error-exiting.patch b/backport-apps-passwd.c-free-before-error-exiting.patch new file mode 100644 index 0000000..7c9e7cd --- /dev/null +++ b/backport-apps-passwd.c-free-before-error-exiting.patch @@ -0,0 +1,61 @@ +From dd05385e36582f34e691b1350dd7daf74df5cc90 Mon Sep 17 00:00:00 2001 +From: Peiwei Hu +Date: Tue, 4 Jan 2022 09:10:32 +0800 +Subject: [PATCH] apps/passwd.c: free before error exiting + +use goto instead of returning directly while error handling + +Signed-off-by: Peiwei Hu + +Reviewed-by: Ben Kaduk +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/17404) + +(cherry picked from commit ea4d16bc60dee53feb71997c1e78379eeb69b7ac) +--- + apps/passwd.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/apps/passwd.c b/apps/passwd.c +index d741d05335..2a4199d080 100644 +--- a/apps/passwd.c ++++ b/apps/passwd.c +@@ -407,7 +407,7 @@ static char *md5crypt(const char *passwd, const char *magic, const char *salt) + n >>= 1; + } + if (!EVP_DigestFinal_ex(md, buf, NULL)) +- return NULL; ++ goto err; + + for (i = 0; i < 1000; i++) { + if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL)) +@@ -633,7 +633,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) + n >>= 1; + } + if (!EVP_DigestFinal_ex(md, buf, NULL)) +- return NULL; ++ goto err; + + /* P sequence */ + if (!EVP_DigestInit_ex(md2, sha, NULL)) +@@ -644,7 +644,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) + goto err; + + if (!EVP_DigestFinal_ex(md2, temp_buf, NULL)) +- return NULL; ++ goto err; + + if ((p_bytes = OPENSSL_zalloc(passwd_len)) == NULL) + goto err; +@@ -661,7 +661,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) + goto err; + + if (!EVP_DigestFinal_ex(md2, temp_buf, NULL)) +- return NULL; ++ goto err; + + if ((s_bytes = OPENSSL_zalloc(salt_len)) == NULL) + goto err; +-- +2.33.0 diff --git a/backport-x509-Fix-possible-use-after-free-when-OOM.patch b/backport-x509-Fix-possible-use-after-free-when-OOM.patch new file mode 100644 index 0000000..f6b47c8 --- /dev/null +++ b/backport-x509-Fix-possible-use-after-free-when-OOM.patch @@ -0,0 +1,65 @@ +From b1cc84e82d41ab669bf804ea519f5332c48a3d77 Mon Sep 17 00:00:00 2001 +From: Clemens Lang +Date: Wed, 24 May 2023 12:22:25 +0200 +Subject: [PATCH] x509: Fix possible use-after-free when OOM + +ossl_policy_level_add_node() first adds the new node to the level->nodes +stack, and then attempts to add extra data if extra_data is true. If +memory allocation or adding the extra data to tree->extra_data fails, +the allocated node (that has already been added to the level->nodes +stack) is freed using ossl_policy_node_free(), which leads to +a potential use after free. + +Additionally, the tree's node count and the parent's child count would +not be updated, despite the new node being added. + +Fix this by either performing the function's purpose completely, or not +at all by reverting the changes on error. + +Signed-off-by: Clemens Lang + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Matt Caswell +Reviewed-by: Bernd Edlinger +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/21066) +--- + crypto/x509v3/pcy_node.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/crypto/x509v3/pcy_node.c b/crypto/x509v3/pcy_node.c +index d574fb9d66..c6c01cbb39 100644 +--- a/crypto/x509v3/pcy_node.c ++++ b/crypto/x509v3/pcy_node.c +@@ -100,11 +100,11 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + tree->extra_data = sk_X509_POLICY_DATA_new_null(); + if (tree->extra_data == NULL){ + X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE); +- goto node_error; ++ goto extra_data_error; + } + if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) { + X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE); +- goto node_error; ++ goto extra_data_error; + } + } + +@@ -114,6 +114,14 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + + return node; + ++ extra_data_error: ++ if (level != NULL) { ++ if (level->anyPolicy == node) ++ level->anyPolicy = NULL; ++ else ++ (void) sk_X509_POLICY_NODE_pop(level->nodes); ++ } ++ + node_error: + policy_node_free(node); + return NULL; +-- +2.33.0 + diff --git a/backport-x509-Handle-ossl_policy_level_add_node-errors.patch b/backport-x509-Handle-ossl_policy_level_add_node-errors.patch new file mode 100644 index 0000000..c594262 --- /dev/null +++ b/backport-x509-Handle-ossl_policy_level_add_node-errors.patch @@ -0,0 +1,72 @@ +From 3cc6933555a0c66328ec659b5bb86c57b6402e1e Mon Sep 17 00:00:00 2001 +From: Clemens Lang +Date: Wed, 24 May 2023 13:12:54 +0200 +Subject: [PATCH] x509: Handle ossl_policy_level_add_node errors + +The invocation of ossl_policy_level_add_node in tree_calculate_user_set +did not have any error handling. Add it to prevent a memory leak for the +allocated extra policy data. + +Also add error handling to sk_X509_POLICY_NODE_push to ensure that if +a new node was allocated, but could not be added to the stack, it is +freed correctly. + +Fix error handling if tree->user_policies cannot be allocated by +returning 0, indicating failure, rather than 1. + +Signed-off-by: Clemens Lang + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Matt Caswell +Reviewed-by: Bernd Edlinger +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/21066) +--- + crypto/x509v3/pcy_tree.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c +index 6c7fd35405..3c504e82c6 100644 +--- a/crypto/x509v3/pcy_tree.c ++++ b/crypto/x509v3/pcy_tree.c +@@ -25,6 +25,8 @@ + # define OPENSSL_POLICY_TREE_NODES_MAX 1000 + #endif + ++static void exnode_free(X509_POLICY_NODE *node); ++ + /* + * Enable this to print out the complete policy tree at various point during + * evaluation. +@@ -572,15 +574,24 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree, + extra->qualifier_set = anyPolicy->data->qualifier_set; + extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS + | POLICY_DATA_FLAG_EXTRA_NODE; +- node = level_add_node(NULL, extra, anyPolicy->parent, tree, 1); ++ node = level_add_node(NULL, extra, anyPolicy->parent, ++ tree, 1); ++ if (node == NULL) { ++ policy_data_free(extra); ++ return 0; ++ } + } + if (!tree->user_policies) { + tree->user_policies = sk_X509_POLICY_NODE_new_null(); +- if (!tree->user_policies) +- return 1; ++ if (!tree->user_policies) { ++ exnode_free(node); ++ return 0; ++ } + } +- if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) ++ if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) { ++ exnode_free(node); + return 0; ++ } + } + return 1; + } +-- +2.33.0 + diff --git a/compat-openssl11.spec b/compat-openssl11.spec index c7828a0..2ce1b37 100644 --- a/compat-openssl11.spec +++ b/compat-openssl11.spec @@ -1,7 +1,7 @@ %define soversion 1.1 Name: compat-openssl11 Version: 1.1.1m -Release: 9 +Release: 10 Epoch: 1 Summary: Cryptography and SSL/TLS Toolkit License: OpenSSL and SSLeay @@ -113,6 +113,26 @@ Patch102: backport-CVE-2023-3446-Fix-DH_check-excessive-time-with-over-sized- Patch103: backport-update-expired-certificates-for-sm2.patch Patch104: backport-CVE-2023-3817.patch Patch105: backport-CVE-2023-3817-testcase.patch +Patch106: backport-A-null-pointer-dereference-occurs-when-memory-alloca.patch +Patch107: backport-Make-DH_check-set-some-error-bits-in-recently-added-.patch +Patch108: backport-CVE-2023-5678-Make-DH_check_pub_key-and-DH_generate_key-safer-yet.patch +Patch109: backport-Add-negative-integer-check-when-using-ASN1_BIT_STRIN.patch +Patch110: backport-Fix-stack-corruption-in-ui_read.patch +Patch111: backport-Re-add-BN_F_OSSL_BN_RSA_DO_UNBLIND-which-was-incorre.patch +Patch112: backport-x509-Fix-possible-use-after-free-when-OOM.patch +Patch113: backport-x509-Handle-ossl_policy_level_add_node-errors.patch +Patch114: backport-Fix-a-possbile-memleak-in-rsa_pub_encode.patch +Patch115: backport-Fix-a-possible-memleak-in-eckey_priv_encode.patch +Patch116: backport-Fix-error-handling-in-CMS_EncryptedData_encrypt.patch +Patch117: backport-Fix-EVP_PKEY_asn1_copy.patch +Patch118: backport-CVE-2024-0727-fix-pkcs12-decoding-crashes.patch +Patch119: backport-apps-passwd.c-free-before-error-exiting.patch +Patch120: backport-Fix-mem-leaks-on-PKCS-12-read-error-in-PKCS12_key_ge.patch +Patch121: backport-CVE-2024-2511-Fix-unconstrained-session-cache-growth-in-TLSv1.3.patch +Patch122: backport-Add-a-test-for-session-cache-handling.patch +Patch123: backport-Extend-the-multi_resume-test-for-simultaneous-resump.patch +Patch124: backport-Hardening-around-not_resumable-sessions.patch +Patch125: backport-Add-a-test-for-session-cache-overflow.patch BuildRequires: gcc perl make lksctp-tools-devel coreutils util-linux zlib-devel @@ -239,6 +259,9 @@ make test || : %ldconfig_scriptlets libs %changelog +* Mon Apr 22 2023 wangcheng - 1:1.1.1m-10 +- fix CVE-2023-5678 CVE-2024-0727 CVE-2024-2511 + * Thu Oct 12 2023 fangxiuning - 1:1.1.1m-9 - fix some CVEs -- Gitee