Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package openssl-3 for openSUSE:Factory checked in at 2026-04-11 22:24:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openssl-3 (Old) and /work/SRC/openSUSE:Factory/.openssl-3.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openssl-3" Sat Apr 11 22:24:40 2026 rev:49 rq:1345575 version:3.5.3 Changes: -------- --- /work/SRC/openSUSE:Factory/openssl-3/openssl-3.changes 2026-03-01 22:13:37.655011059 +0100 +++ /work/SRC/openSUSE:Factory/.openssl-3.new.21863/openssl-3.changes 2026-04-11 22:29:23.519796211 +0200 @@ -1,0 +2,41 @@ +Tue Apr 7 20:16:04 UTC 2026 - Lucas Mulling <[email protected]> + +- Adapt spec file for immutability via systemd-tmpfiles (jsc#PED-14813) +- Fix check %{suse_version} > 1600 (jsc#PED-15816) + +------------------------------------------------------------------- +Thu Mar 26 11:28:38 UTC 2026 - Pedro Monreal <[email protected]> + +- Security fixes: + * CVE-2026-28387: Potential use-after-free in DANE client code + (bsc#1260441) + * CVE-2026-28388: NULL Pointer Dereference When Processing a + Delta (bsc#1260442) + * CVE-2026-28389: Possible NULL dereference when processing CMS + KeyAgreeRecipientInfo (bsc#1260443) + * CVE-2026-31789: Heap buffer overflow in hexadecimal conversion + (bsc#1260444) + * CVE-2026-31790: Incorrect failure handling in RSA KEM RSASVE + encapsulation (bsc#1260445) + * CVE-2026-28390: NULL pointer dereference during processing of a crafted CMS + EnvelopedData message with KeyTransportRecipientInfo (bsc#1261678) + * Add patches: openssl-CVE-2026-28387.patch + openssl-CVE-2026-28388.patch openssl-CVE-2026-28388-tests.patch + openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch + openssl-CVE-2026-31790.patch openssl-CVE-2026-31790-tests.patch + openssl-CVE-2026-28390.patch +- Fix NULL pointer dereference when processing an OCSP response + * Add patch openssl-NULL-pointer-dereference-in-ocsp_find_signer_sk.patch + +------------------------------------------------------------------- +Sun Mar 22 20:33:24 UTC 2026 - Lucas Mulling <[email protected]> + +- Security fix: + * CVE-2026-2673: TLS 1.3 servers may choose unexpected key agreement group (bsc#1259652) + Added patch openssl-CVE-2026-2673.patch + Added patch openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch + Added patch openssl-Add-array-memory-allocation-routines.patch +- Remove showciphers.c in favor of openssl ciphers +- Use %ldconfig_scriptlets + +------------------------------------------------------------------- Old: ---- showciphers.c New: ---- openssl-Add-array-memory-allocation-routines.patch openssl-CVE-2026-2673.patch openssl-CVE-2026-28387.patch openssl-CVE-2026-28388-tests.patch openssl-CVE-2026-28388.patch openssl-CVE-2026-28389.patch openssl-CVE-2026-28390.patch openssl-CVE-2026-31789.patch openssl-CVE-2026-31790-tests.patch openssl-CVE-2026-31790.patch openssl-NULL-pointer-dereference-in-ocsp_find_signer_sk.patch openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch ----------(New B)---------- New: Added patch openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch Added patch openssl-Add-array-memory-allocation-routines.patch - Remove showciphers.c in favor of openssl ciphers New: * CVE-2026-2673: TLS 1.3 servers may choose unexpected key agreement group (bsc#1259652) Added patch openssl-CVE-2026-2673.patch Added patch openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch New: EnvelopedData message with KeyTransportRecipientInfo (bsc#1261678) * Add patches: openssl-CVE-2026-28387.patch openssl-CVE-2026-28388.patch openssl-CVE-2026-28388-tests.patch New: * Add patches: openssl-CVE-2026-28387.patch openssl-CVE-2026-28388.patch openssl-CVE-2026-28388-tests.patch openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch New: * Add patches: openssl-CVE-2026-28387.patch openssl-CVE-2026-28388.patch openssl-CVE-2026-28388-tests.patch openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch New: openssl-CVE-2026-28388.patch openssl-CVE-2026-28388-tests.patch openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch openssl-CVE-2026-31790.patch openssl-CVE-2026-31790-tests.patch New: openssl-CVE-2026-31790.patch openssl-CVE-2026-31790-tests.patch openssl-CVE-2026-28390.patch - Fix NULL pointer dereference when processing an OCSP response New: openssl-CVE-2026-28388.patch openssl-CVE-2026-28388-tests.patch openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch openssl-CVE-2026-31790.patch openssl-CVE-2026-31790-tests.patch New: openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch openssl-CVE-2026-31790.patch openssl-CVE-2026-31790-tests.patch openssl-CVE-2026-28390.patch New: openssl-CVE-2026-28389.patch openssl-CVE-2026-31789.patch openssl-CVE-2026-31790.patch openssl-CVE-2026-31790-tests.patch openssl-CVE-2026-28390.patch New:- Fix NULL pointer dereference when processing an OCSP response * Add patch openssl-NULL-pointer-dereference-in-ocsp_find_signer_sk.patch New: Added patch openssl-CVE-2026-2673.patch Added patch openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch Added patch openssl-Add-array-memory-allocation-routines.patch ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openssl-3.spec ++++++ --- /var/tmp/diff_new_pack.ZLIKCp/_old 2026-04-11 22:29:25.051858872 +0200 +++ /var/tmp/diff_new_pack.ZLIKCp/_new 2026-04-11 22:29:25.055859036 +0200 @@ -30,7 +30,7 @@ %global sle_needs_crypto_policies 1 %endif -%if 0%{?suse_version} > 1600 +%if 0%{?suse_version} >= 1699 %global openssl_test_flags HARNESS_JOBS=${RPM_BUILD_NCPUS} %endif @@ -51,8 +51,7 @@ # to get mtime of file: Source3: %{name}.changes Source4: baselibs.conf -Source5: showciphers.c -Source6: openssl-TESTS-Disable-default-provider-crypto-policies.patch +Source5: openssl-TESTS-Disable-default-provider-crypto-policies.patch # PATCH-FIX-OPENSUSE: Do not install html docs as it takes ages Patch1: openssl-no-html-docs.patch Patch2: openssl-truststore.patch @@ -157,7 +156,26 @@ Patch61: openssl-CVE-2025-11187.patch # PATCH-FIX-UPSTREAM bsc#1256831 CVE-2025-15468: NULL dereference in SSL_CIPHER_find() function on unknown cipher ID Patch62: openssl-CVE-2025-15468.patch - +# PATCH-FIX_UPSTREAM bsc#1259652 CVE-2026-2673: TLS 1.3 servers may choose unexpected key agreement group +Patch63: openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch +Patch64: openssl-Add-array-memory-allocation-routines.patch +Patch65: openssl-CVE-2026-2673.patch +# PATCH-FIX-UPSTREAM CVE-2026-28387: Potential use-after-free in DANE client code (bsc#1260441) +Patch66: openssl-CVE-2026-28387.patch +# PATCH-FIX-UPSTREAM CVE-2026-28388: NULL Pointer Dereference When Processing a Delta (bsc#1260442) +Patch67: openssl-CVE-2026-28388.patch +Patch68: openssl-CVE-2026-28388-tests.patch +# PATCH-FIX-UPSTREAM CVE-2026-28389: Possible NULL dereference when processing CMS KeyAgreeRecipientInfo (bsc#1260443) +Patch69: openssl-CVE-2026-28389.patch +# PATCH-FIX-UPSTREAM CVE-2026-31789: Heap buffer overflow in hexadecimal conversion (bsc#1260444) +Patch70: openssl-CVE-2026-31789.patch +# PATCH-FIX-UPSTREAM CVE-2026-31790: Incorrect failure handling in RSA KEM RSASVE encapsulation (bsc#1260445) +Patch71: openssl-CVE-2026-31790.patch +Patch72: openssl-CVE-2026-31790-tests.patch +# PATCH-FIX-UPSTREAM: NULL pointer dereference when processing an OCSP response +Patch73: openssl-NULL-pointer-dereference-in-ocsp_find_signer_sk.patch +# PATCH-FIX-UPSTREAM CVE-2026-28390: NULL pointer dereference during processing of a crafted CMS EnvelopedData message with KeyTransportRecipientInfo (bsc#1261678) +Patch74: openssl-CVE-2026-28390.patch # ulp-macros is available according to SUSE version. %if 0%{?sle_version} >= 150400 || 0%{?suse_version} >= 1540 BuildRequires: ulp-macros @@ -304,7 +322,7 @@ %check # Relax the crypto-policies requirements and disable the default # provider for the test suite regression tests -patch -p1 < %{SOURCE6} +patch -p1 < %{SOURCE5} export OPENSSL_SYSTEM_CIPHERS_OVERRIDE=xyz_nonexistent_file export MALLOC_CHECK_=3 export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) @@ -334,8 +352,8 @@ %{nil} # show ciphers -gcc -o showciphers %{optflags} -I%{buildroot}%{_includedir} %{SOURCE5} -L%{buildroot}%{_libdir} -lssl -lcrypto -LD_LIBRARY_PATH=%{buildroot}%{_libdir} ./showciphers +OPENSSL_CONF=/dev/null LD_LIBRARY_PATH=. apps/openssl ciphers +OPENSSL_CONF=/dev/null LD_LIBRARY_PATH=. apps/openssl ciphers -s %install %{?pack_ipa_dumps} @@ -363,10 +381,6 @@ # Make a copy of the default openssl.cnf file cp %{buildroot}%{ssletcdir}/openssl.cnf %{buildroot}%{ssletcdir}/openssl-orig.cnf -# Create openssl ca-certificates dir required by nodejs regression tests [bsc#1207484] -mkdir -p %{buildroot}%{_localstatedir}/lib/ca-certificates/openssl -install -d -m 555 %{buildroot}%{_localstatedir}/lib/ca-certificates/openssl - # Remove the fipsmodule.cnf because FIPS module is loaded automatically in FIPS mode rm -f %{buildroot}%{ssletcdir}/fipsmodule.cnf @@ -388,12 +402,16 @@ # Do not install demo scripts executable under /usr/share/doc find demos -type f -perm /111 -exec chmod 644 {} + -# Place showciphers.c for %%doc macro -cp %{SOURCE5} . - # Compute the FIPS hmac using the brp-50-generate-fips-hmac script export BRP_FIPSHMAC_FILES="%{buildroot}%{_libdir}/libssl.so.%{sover} %{buildroot}%{_libdir}/libcrypto.so.%{sover}" +# Install tmpfiles.d and define the configuration for immutable mode (jsc#PED-14813) +install -d %{buildroot}%{_tmpfilesdir} +cat > %{buildroot}%{_tmpfilesdir}/%{_rname}-%{sover}.conf <<EOF +d /var/lib/ca-certificates/ 0755 root root - - +d /var/lib/ca-certificates/openssl/ 0555 root root - - +EOF + %post -p "/bin/bash" if [ "$1" -gt 1 ] ; then # Check if the packaged default config file for openssl-3, called openssl.cnf, @@ -407,10 +425,12 @@ fi fi -%pre - -%post -n libopenssl3 -p /sbin/ldconfig +%post -n libopenssl3 +%tmpfiles_create %{_tmpfilesdir}/%{_rname}-%{sover}.conf +/sbin/ldconfig +%end %postun -n libopenssl3 -p /sbin/ldconfig +%end %files -n libopenssl3 %license LICENSE.txt @@ -430,8 +450,9 @@ %config (noreplace) %{ssletcdir}/ct_log_list.cnf %dir %{_datadir}/ssl %{_datadir}/ssl/misc -%dir %{_localstatedir}/lib/ca-certificates/ -%dir %{_localstatedir}/lib/ca-certificates/openssl +%{_tmpfilesdir}/%{_rname}-%{sover}.conf +%ghost %attr(0755,root,root) %dir %{_localstatedir}/lib/ca-certificates/ +%ghost %attr(0555,root,root) %dir %{_localstatedir}/lib/ca-certificates/openssl %files -n libopenssl-3-fips-provider %{_libdir}/ossl-modules/fips.so @@ -452,7 +473,6 @@ %files doc %doc README.md %doc doc/html/* doc/HOWTO/* demos -%doc showciphers.c %{_mandir}/man3/* %files ++++++ openssl-Add-array-memory-allocation-routines.patch ++++++ >From fa9b7b930e3e59f5b30de0e8a6755bfaafdd5c49 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov <[email protected]> Date: Thu, 17 Jul 2025 03:32:02 +0200 Subject: [PATCH] Add array memory allocation routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Such routines allow alleviating the need to perform explicit integer overflow check during allocation size calculation and generally make the allocations more semantic (as they signify that a collection of NUM items, each occupying SIZE bytes is being allocated), which paves the road for additional correctness checks in the future. Signed-off-by: Eugene Syromiatnikov <[email protected]> Reviewed-by: Saša Nedvědický <[email protected]> Reviewed-by: Matt Caswell <[email protected]> Reviewed-by: Paul Dale <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from https://github.com/openssl/openssl/pull/28059) Signed-off-by: Lucas Mulling <[email protected]> --- crypto/array_alloc.c | 94 ++++++++++++++++++++++++++++++ crypto/build.info | 2 +- doc/man3/OPENSSL_malloc.pod | 52 ++++++++++++++--- doc/man3/OPENSSL_secure_malloc.pod | 34 +++++++++-- include/internal/mem_alloc_utils.h | 37 +++++++++++- include/openssl/crypto.h.in | 31 ++++++++++ util/libcrypto.num | 7 +++ util/other.syms | 7 +++ 8 files changed, 249 insertions(+), 15 deletions(-) create mode 100644 crypto/array_alloc.c Index: openssl-3.5.3/crypto/array_alloc.c =================================================================== --- /dev/null +++ openssl-3.5.3/crypto/array_alloc.c @@ -0,0 +1,94 @@ +/* + * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file provides implementation of various array allocation routines that + * perform integer overflow checking for size calculation. + */ + +#include "internal/mem_alloc_utils.h" +#include <openssl/crypto.h> + +void *CRYPTO_malloc_array(size_t num, size_t size, const char *file, int line) +{ + size_t bytes; + + if (ossl_unlikely(!ossl_size_mul(num, size, &bytes, file, line))) + return NULL; + + return CRYPTO_malloc(bytes, file, line); +} + +void *CRYPTO_calloc(size_t num, size_t size, const char *file, int line) +{ + size_t bytes; + + if (ossl_unlikely(!ossl_size_mul(num, size, &bytes, file, line))) + return NULL; + + return CRYPTO_zalloc(bytes, file, line); +} + +void *CRYPTO_aligned_alloc_array(size_t num, size_t size, size_t align, + void **freeptr, const char *file, int line) +{ + size_t bytes; + + if (ossl_unlikely(!ossl_size_mul(num, size, &bytes, file, line))) { + *freeptr = NULL; + + return NULL; + } + + return CRYPTO_aligned_alloc(bytes, align, freeptr, file, line); +} + +void *CRYPTO_realloc_array(void *addr, size_t num, size_t size, + const char *file, int line) +{ + size_t bytes; + + if (ossl_unlikely(!ossl_size_mul(num, size, &bytes, file, line))) + return NULL; + + return CRYPTO_realloc(addr, bytes, file, line); +} + +void *CRYPTO_clear_realloc_array(void *addr, size_t old_num, size_t num, + size_t size, const char *file, int line) +{ + size_t old_bytes, bytes = 0; + + if (ossl_unlikely(!ossl_size_mul(old_num, size, &old_bytes, file, line) + || !ossl_size_mul(num, size, &bytes, file, line))) + return NULL; + + return CRYPTO_clear_realloc(addr, old_bytes, bytes, file, line); +} + +void *CRYPTO_secure_malloc_array(size_t num, size_t size, + const char *file, int line) +{ + size_t bytes; + + if (ossl_unlikely(!ossl_size_mul(num, size, &bytes, file, line))) + return NULL; + + return CRYPTO_secure_malloc(bytes, file, line); +} + +void *CRYPTO_secure_calloc(size_t num, size_t size, const char *file, int line) +{ + size_t bytes; + + if (ossl_unlikely(!ossl_size_mul(num, size, &bytes, file, line))) + return NULL; + + return CRYPTO_secure_zalloc(bytes, file, line); +} Index: openssl-3.5.3/crypto/build.info =================================================================== --- openssl-3.5.3.orig/crypto/build.info +++ openssl-3.5.3/crypto/build.info @@ -100,7 +100,7 @@ $UTIL_COMMON=\ threads_pthread.c threads_win.c threads_none.c initthread.c \ context.c sparse_array.c asn1_dsa.c packet.c param_build.c \ param_build_set.c der_writer.c threads_lib.c params_dup.c \ - time.c params_idx.c + time.c params_idx.c array_alloc.c SOURCE[../libcrypto]=$UTIL_COMMON \ mem.c mem_sec.c \ Index: openssl-3.5.3/doc/man3/OPENSSL_malloc.pod =================================================================== --- openssl-3.5.3.orig/doc/man3/OPENSSL_malloc.pod +++ openssl-3.5.3/doc/man3/OPENSSL_malloc.pod @@ -4,14 +4,19 @@ OPENSSL_malloc_init, OPENSSL_malloc, OPENSSL_aligned_alloc, OPENSSL_zalloc, OPENSSL_realloc, -OPENSSL_free, OPENSSL_clear_realloc, OPENSSL_clear_free, OPENSSL_cleanse, -CRYPTO_malloc, CRYPTO_aligned_alloc, CRYPTO_zalloc, CRYPTO_realloc, CRYPTO_free, +OPENSSL_malloc_array, OPENSSL_aligned_alloc_array, OPENSSL_calloc, +OPENSSL_realloc_array, OPENSSL_free, +OPENSSL_clear_realloc, OPENSSL_clear_realloc_array, +OPENSSL_clear_free, OPENSSL_cleanse, +CRYPTO_malloc, CRYPTO_aligned_alloc, CRYPTO_zalloc, +CRYPTO_malloc_array, CRYPTO_aligned_alloc_array, CRYPTO_calloc, +CRYPTO_realloc, CRYPTO_realloc_array, CRYPTO_free, OPENSSL_strdup, OPENSSL_strndup, OPENSSL_memdup, OPENSSL_strlcpy, OPENSSL_strlcat, OPENSSL_strtoul, CRYPTO_strdup, CRYPTO_strndup, OPENSSL_mem_debug_push, OPENSSL_mem_debug_pop, CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop, -CRYPTO_clear_realloc, CRYPTO_clear_free, +CRYPTO_clear_realloc, CRYPTO_clear_realloc_array, CRYPTO_clear_free, CRYPTO_malloc_fn, CRYPTO_realloc_fn, CRYPTO_free_fn, CRYPTO_get_mem_functions, CRYPTO_set_mem_functions, CRYPTO_get_alloc_counts, @@ -31,6 +36,11 @@ OPENSSL_MALLOC_FD void *OPENSSL_aligned_alloc(size_t num, size_t alignment, void **freeptr); void *OPENSSL_zalloc(size_t num); void *OPENSSL_realloc(void *addr, size_t num); + void *OPENSSL_malloc_array(size_t num, size_t size); + void *OPENSSL_aligned_alloc_array(size_t num, size_t size, size_t alignment, + void **freeptr); + void *OPENSSL_calloc(size_t num, size_t size); + void *OPENSSL_realloc_array(void *addr, size_t num, size_t size); void OPENSSL_free(void *addr); char *OPENSSL_strdup(const char *str); char *OPENSSL_strndup(const char *str, size_t s); @@ -39,20 +49,30 @@ OPENSSL_MALLOC_FD int OPENSSL_strtoul(char *src, char **endptr, int base, unsigned long *num); void *OPENSSL_memdup(void *data, size_t s); void *OPENSSL_clear_realloc(void *p, size_t old_len, size_t num); + void *OPENSSL_clear_realloc_array(void *p, size_t old_len, size_t num, + size_t size); void OPENSSL_clear_free(void *str, size_t num); void OPENSSL_cleanse(void *ptr, size_t len); void *CRYPTO_malloc(size_t num, const char *file, int line); - void *CRYPTO_aligned_alloc(size_t num, size_t align, void **freeptr, + void *CRYPTO_aligned_alloc(size_t num, size_t align, void **freeptr, const char *file, int line); void *CRYPTO_zalloc(size_t num, const char *file, int line); void *CRYPTO_realloc(void *p, size_t num, const char *file, int line); - void CRYPTO_free(void *str, const char *, int); + void *CRYPTO_malloc_array(size_t num, size_t size, const char *file, int line); + void *CRYPTO_aligned_alloc_array(size_t num, size_t size, size_t align, + void **freeptr, const char *file, int line); + void *CRYPTO_calloc(size_t num, size_t size, const char *file, int line); + void *CRYPTO_realloc_array(void *p, size_t num, size_t size, + const char *file, int line); + void CRYPTO_free(void *str, const char *file, int line); char *CRYPTO_strdup(const char *p, const char *file, int line); char *CRYPTO_strndup(const char *p, size_t num, const char *file, int line); void *CRYPTO_clear_realloc(void *p, size_t old_len, size_t num, const char *file, int line); - void CRYPTO_clear_free(void *str, size_t num, const char *, int); + void *CRYPTO_clear_realloc_array(void *p, size_t old_len, size_t num, + size_t size, const char *file, int line); + void CRYPTO_clear_free(void *str, size_t num, const char *file, int line); typedef void *(*CRYPTO_malloc_fn)(size_t num, const char *file, int line); typedef void *(*CRYPTO_realloc_fn)(void *addr, size_t num, const char *file, @@ -120,6 +140,15 @@ The old buffer is filled with zero's by before ultimately calling OPENSSL_free(). If the argument to OPENSSL_free() is NULL, nothing is done. +OPENSSL_malloc_array(), OPENSSL_calloc(), OPENSSL_aligned_alloc_array(), +OPENSSL_realloc_array(), and OPENSSL_clear_realloc_array() are variants +of OPENSSL_malloc(), OPENSSL_zalloc(), OPENSSL_aligned_alloc(), +OPENSSL_realloc(), and OPENSSL_clear_realloc(), respectively, that accept +an additional parameter, B<size>, which enables memory allocation +operations for an array of B<num> members B<size> bytes each; +these functions return an error if multiplication of B<num> and B<size> +leads to an integer overflow, thus preventing allocations of an incorrect size. + OPENSSL_cleanse() fills B<ptr> of size B<len> with a string of 0's. Use OPENSSL_cleanse() with care if the memory is a mapping of a file. If the storage controller uses write compression, then it's possible @@ -195,9 +224,12 @@ CRYPTO_free(), CRYPTO_clear_free() and C return no value. OPENSSL_malloc(), OPENSSL_aligned_alloc(), OPENSSL_zalloc(), OPENSSL_realloc(), -OPENSSL_clear_realloc(), +OPENSSL_malloc_array(), OPENSSL_aligned_alloc_array(), OPENSSL_calloc(), +OPENSSL_realloc_array(), +OPENSSL_clear_realloc(), OPENSSL_clear_realloc_array(), CRYPTO_malloc(), CRYPTO_zalloc(), CRYPTO_realloc(), -CRYPTO_clear_realloc(), +CRYPTO_malloc_array(), CRYPTO_calloc(), CRYPTO_realloc_array(), +CRYPTO_clear_realloc(), CRYPTO_clear_realloc_array(), OPENSSL_strdup(), and OPENSSL_strndup() return a pointer to allocated memory or NULL on error. @@ -251,6 +283,10 @@ The memory-leak checking has been deprec clang's memory and leak sanitizer. OPENSSL_aligned_alloc(), CRYPTO_aligned_alloc(), OPENSSL_strtoul() were added in OpenSSL 3.4. +OPENSSL_malloc_array(), OPENSSL_calloc(), OPENSSL_aligned_alloc_array(), +OPENSSL_realloc_array(), OPENSSL_clear_realloc_array(), CRYPTO_malloc_array(), +CRYPTO_calloc(), CRYPTO_aligned_alloc_array(), CRYPTO_realloc_array(), +CRYPTO_clear_realloc_array() were added in OpenSSL 3.6. =head1 COPYRIGHT Index: openssl-3.5.3/doc/man3/OPENSSL_secure_malloc.pod =================================================================== --- openssl-3.5.3.orig/doc/man3/OPENSSL_secure_malloc.pod +++ openssl-3.5.3/doc/man3/OPENSSL_secure_malloc.pod @@ -4,8 +4,9 @@ CRYPTO_secure_malloc_init, CRYPTO_secure_malloc_initialized, CRYPTO_secure_malloc_done, OPENSSL_secure_malloc, CRYPTO_secure_malloc, -OPENSSL_secure_zalloc, CRYPTO_secure_zalloc, OPENSSL_secure_free, -CRYPTO_secure_free, OPENSSL_secure_clear_free, +OPENSSL_secure_zalloc, CRYPTO_secure_zalloc, OPENSSL_secure_malloc_array, +CRYPTO_secure_malloc_array, OPENSSL_secure_calloc, CRYPTO_secure_calloc, +OPENSSL_secure_free, CRYPTO_secure_free, OPENSSL_secure_clear_free, CRYPTO_secure_clear_free, OPENSSL_secure_actual_size, CRYPTO_secure_allocated, CRYPTO_secure_used - secure heap storage @@ -26,6 +27,14 @@ CRYPTO_secure_used - secure heap storage void *OPENSSL_secure_zalloc(size_t num); void *CRYPTO_secure_zalloc(size_t num, const char *file, int line); + void *OPENSSL_secure_malloc_array(size_t num, size_t size); + void *CRYPTO_secure_malloc_array(size_t num, size_t size, + const char *file, int line); + + void *OPENSSL_secure_calloc(size_t num, size_t size); + void *CRYPTO_secure_calloc(size_t num, size_t size, + const char *file, int line); + void OPENSSL_secure_free(void* ptr); void CRYPTO_secure_free(void *ptr, const char *, int); @@ -80,6 +89,15 @@ OPENSSL_secure_zalloc() and CRYPTO_secur OPENSSL_secure_malloc() and CRYPTO_secure_malloc(), respectively, except that they call memset() to zero the memory before returning. +OPENSSL_secure_malloc_array(), CRYPTO_secure_malloc_array(), +OPENSSL_secure_calloc(), and CRYPTO_secure_calloc() are variants +of OPENSSL_secure_malloc(), CRYPTO_secure_malloc(), +OPENSSL_secure_zalloc(), and CRYPTO_secure_zalloc(), respectively, that accept +an additional parameter, B<size>, which enables memory allocation +operations for an array of B<num> members B<size> bytes each; +these functions return an error if multiplication of B<num> and B<size> +leads to an integer overflow, thus preventing allocations of an incorrect size. + OPENSSL_secure_free() releases the memory at C<ptr> back to the heap. It must be called with a value previously obtained from OPENSSL_secure_malloc(). @@ -116,9 +134,11 @@ CRYPTO_secure_malloc_initialized() retur available (that is, if CRYPTO_secure_malloc_init() has been called, but CRYPTO_secure_malloc_done() has not been called or failed) or 0 if not. -OPENSSL_secure_malloc() and OPENSSL_secure_zalloc() return a pointer into -the secure heap of the requested size, or C<NULL> if memory could not be -allocated. +OPENSSL_secure_malloc(), CRYPTO_secure_malloc(), OPENSSL_secure_zalloc(), +CRYPTO_secure_zalloc(), OPENSSL_secure_malloc_array(), +CRYPTO_secure_malloc_array(), OPENSSL_secure_calloc(), and CRYPTO_secure_calloc() +return a pointer into the secure heap of the requested size, +or C<NULL> if memory could not be allocated. CRYPTO_secure_allocated() returns 1 if the pointer is in the secure heap, or 0 if not. @@ -138,6 +158,10 @@ The OPENSSL_secure_clear_free() function The second argument to CRYPTO_secure_malloc_init() was changed from an B<int> to a B<size_t> in OpenSSL 3.0. +The OPENSSL_secure_malloc_array(), CRYPTO_secure_malloc_array(), +OPENSSL_secure_calloc(), and CRYPTO_secure_calloc() functions were added +in OpenSSL 3.6. + =head1 COPYRIGHT Copyright 2015-2025 The OpenSSL Project Authors. All Rights Reserved. Index: openssl-3.5.3/include/internal/mem_alloc_utils.h =================================================================== --- openssl-3.5.3.orig/include/internal/mem_alloc_utils.h +++ openssl-3.5.3/include/internal/mem_alloc_utils.h @@ -14,11 +14,18 @@ #ifndef OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H # define OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H +# include <limits.h> +# include <stdbool.h> +# include <stdint.h> + # include "internal/common.h" +# include "internal/safe_math.h" # include <openssl/cryptoerr.h> # include <openssl/err.h> +OSSL_SAFE_MATH_UNSIGNED(size_t, size_t) + /* * A helper routine to report memory allocation errors. * Similar to the ERR_raise() macro, but accepts explicit file/line arguments, @@ -41,10 +48,38 @@ ossl_report_alloc_err_ex(const char * co } /* Report a memory allocation failure. */ -static inline void +static ossl_inline ossl_unused void ossl_report_alloc_err(const char * const file, const int line) { ossl_report_alloc_err_ex(file, line, ERR_R_MALLOC_FAILURE); } +/* Report an integer overflow during allocation size calculation. */ +static ossl_inline ossl_unused void +ossl_report_alloc_err_of(const char * const file, const int line) +{ + ossl_report_alloc_err_ex(file, line, CRYPTO_R_INTEGER_OVERFLOW); +} + +/* + * Check the result of num and size multiplication for overflow + * and set error if it is the case; return true if there was no overflow, + * false if there was. + */ +static ossl_inline ossl_unused bool +ossl_size_mul(const size_t num, const size_t size, size_t *bytes, + const char * const file, const int line) +{ + int err = 0; + *bytes = safe_mul_size_t(num, size, &err); + + if (ossl_unlikely(err != 0)) { + ossl_report_alloc_err_of(file, line); + + return false; + } + + return true; +} + #endif /* OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H */ Index: openssl-3.5.3/include/openssl/crypto.h.in =================================================================== --- openssl-3.5.3.orig/include/openssl/crypto.h.in +++ openssl-3.5.3/include/openssl/crypto.h.in @@ -103,13 +103,25 @@ int CRYPTO_atomic_store(uint64_t *dst, u CRYPTO_malloc(num, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_zalloc(num) \ CRYPTO_zalloc(num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_malloc_array(num, size) \ + CRYPTO_malloc_array(num, size, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_calloc(num, size) \ + CRYPTO_calloc(num, size, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_aligned_alloc(num, alignment, freeptr) \ CRYPTO_aligned_alloc(num, alignment, freeptr, \ OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_aligned_alloc_array(num, size, alignment, freeptr) \ + CRYPTO_aligned_alloc_array(num, size, alignment, freeptr, \ + OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_realloc(addr, num) \ CRYPTO_realloc(addr, num, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_clear_realloc(addr, old_num, num) \ CRYPTO_clear_realloc(addr, old_num, num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_realloc_array(addr, num, size) \ + CRYPTO_realloc_array(addr, num, size, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_clear_realloc_array(addr, old_num, num, size) \ + CRYPTO_clear_realloc_array(addr, old_num, num, size, \ + OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_clear_free(addr, num) \ CRYPTO_clear_free(addr, num, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_free(addr) \ @@ -124,6 +136,10 @@ int CRYPTO_atomic_store(uint64_t *dst, u CRYPTO_secure_malloc(num, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_secure_zalloc(num) \ CRYPTO_secure_zalloc(num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_secure_malloc_array(num, size) \ + CRYPTO_secure_malloc_array(num, size, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_secure_calloc(num, size) \ + CRYPTO_secure_calloc(num, size, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_secure_free(addr) \ CRYPTO_secure_free(addr, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_secure_clear_free(addr, num) \ @@ -332,9 +348,16 @@ void CRYPTO_get_mem_functions(CRYPTO_mal OSSL_CRYPTO_ALLOC void *CRYPTO_malloc(size_t num, const char *file, int line); OSSL_CRYPTO_ALLOC void *CRYPTO_zalloc(size_t num, const char *file, int line); +OSSL_CRYPTO_ALLOC void *CRYPTO_malloc_array(size_t num, size_t size, + const char *file, int line); +OSSL_CRYPTO_ALLOC void *CRYPTO_calloc(size_t num, size_t size, + const char *file, int line); OSSL_CRYPTO_ALLOC void *CRYPTO_aligned_alloc(size_t num, size_t align, void **freeptr, const char *file, int line); +OSSL_CRYPTO_ALLOC void *CRYPTO_aligned_alloc_array(size_t num, size_t size, + size_t align, void **freeptr, + const char *file, int line); void *CRYPTO_memdup(const void *str, size_t siz, const char *file, int line); char *CRYPTO_strdup(const char *str, const char *file, int line); char *CRYPTO_strndup(const char *str, size_t s, const char *file, int line); @@ -343,11 +366,19 @@ void CRYPTO_clear_free(void *ptr, size_t void *CRYPTO_realloc(void *addr, size_t num, const char *file, int line); void *CRYPTO_clear_realloc(void *addr, size_t old_num, size_t num, const char *file, int line); +void *CRYPTO_realloc_array(void *addr, size_t num, size_t size, + const char *file, int line); +void *CRYPTO_clear_realloc_array(void *addr, size_t old_num, size_t num, + size_t size, const char *file, int line); int CRYPTO_secure_malloc_init(size_t sz, size_t minsize); int CRYPTO_secure_malloc_done(void); OSSL_CRYPTO_ALLOC void *CRYPTO_secure_malloc(size_t num, const char *file, int line); OSSL_CRYPTO_ALLOC void *CRYPTO_secure_zalloc(size_t num, const char *file, int line); +OSSL_CRYPTO_ALLOC void *CRYPTO_secure_malloc_array(size_t num, size_t size, + const char *file, int line); +OSSL_CRYPTO_ALLOC void *CRYPTO_secure_calloc(size_t num, size_t size, + const char *file, int line); void CRYPTO_secure_free(void *ptr, const char *file, int line); void CRYPTO_secure_clear_free(void *ptr, size_t num, const char *file, int line); Index: openssl-3.5.3/util/libcrypto.num =================================================================== --- openssl-3.5.3.orig/util/libcrypto.num +++ openssl-3.5.3/util/libcrypto.num @@ -5927,3 +5927,10 @@ OSSL_AA_DIST_POINT_it PEM_ASN1_write_bio_ctx 6054 3_5_0 EXIST::FUNCTION: ossl_ctx_legacy_digest_signatures_allowed ? 3_0_1 EXIST::FUNCTION: ossl_ctx_legacy_digest_signatures_allowed_set ? 3_0_1 EXIST::FUNCTION: +CRYPTO_malloc_array ? 3_5_0 EXIST::FUNCTION: +CRYPTO_calloc ? 3_5_0 EXIST::FUNCTION: +CRYPTO_aligned_alloc_array ? 3_5_0 EXIST::FUNCTION: +CRYPTO_realloc_array ? 3_5_0 EXIST::FUNCTION: +CRYPTO_clear_realloc_array ? 3_5_0 EXIST::FUNCTION: +CRYPTO_secure_malloc_array ? 3_5_0 EXIST::FUNCTION: +CRYPTO_secure_calloc ? 3_5_0 EXIST::FUNCTION: Index: openssl-3.5.3/util/other.syms =================================================================== --- openssl-3.5.3.orig/util/other.syms +++ openssl-3.5.3/util/other.syms @@ -426,21 +426,28 @@ OPENSSL_VERSION_BUILD_METADATA OPENSSL_VERSION_PRE_RELEASE_STR define OPENSSL_VERSION_BUILD_METADATA_STR define OPENSSL_VERSION_TEXT define +OPENSSL_calloc define OPENSSL_clear_free define OPENSSL_clear_realloc define +OPENSSL_clear_realloc_array define OPENSSL_free define OPENSSL_malloc define +OPENSSL_malloc_array define OPENSSL_aligned_alloc define +OPENSSL_aligned_alloc_array define OPENSSL_malloc_init define OPENSSL_mem_debug_pop define deprecated 3.0.0 OPENSSL_mem_debug_push define deprecated 3.0.0 OPENSSL_memdup define OPENSSL_no_config define deprecated 1.1.0 OPENSSL_realloc define +OPENSSL_realloc_array define OPENSSL_secure_actual_size define OPENSSL_secure_clear_free define OPENSSL_secure_free define +OPENSSL_secure_calloc define OPENSSL_secure_malloc define +OPENSSL_secure_malloc_array define OPENSSL_secure_zalloc define OPENSSL_strdup define OPENSSL_strndup define ++++++ openssl-CVE-2026-2673.patch ++++++ >From 9efd7e9e98a98aaade8121bac8f1e53208c3af33 Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni <[email protected]> Date: Sun, 15 Feb 2026 22:50:09 +1100 Subject: [PATCH] Fix group tuple handling in DEFAULT expansion Also fine-tune docs and add tests. Fixes: #30109 Fixes: CVE-2026-2673 Reviewed-by: Tim Hudson <[email protected]> Reviewed-by: Matt Caswell <[email protected]> Reviewed-by: Tomas Mraz <[email protected]> MergeDate: Wed Feb 25 11:08:03 2026 (Merged from https://github.com/openssl/openssl/pull/30113) --- doc/man3/SSL_CTX_set1_curves.pod | 123 +++++++++++++++------- ssl/t1_lib.c | 171 ++++++++++++++++--------------- test/tls13groupselection_test.c | 65 +++++++++++- 3 files changed, 235 insertions(+), 124 deletions(-) Index: openssl-3.5.3/doc/man3/SSL_CTX_set1_curves.pod =================================================================== --- openssl-3.5.3.orig/doc/man3/SSL_CTX_set1_curves.pod +++ openssl-3.5.3/doc/man3/SSL_CTX_set1_curves.pod @@ -40,13 +40,13 @@ SSL_get1_curves, SSL_get_shared_curve, S For all of the functions below that set the supported groups there must be at least one group in the list. A number of these functions identify groups via a -unique integer NID value. However, support for some groups may be added by -external providers. In this case there will be no NID assigned for the group. +unique integer B<NID> value. However, support for some groups may be added by +external providers. In this case there will be no B<NID> assigned for the group. When setting such groups applications should use the "list" form of these functions (i.e. SSL_CTX_set1_groups_list() and SSL_set1_groups_list()). SSL_CTX_set1_groups() sets the supported groups for B<ctx> to B<glistlen> -groups in the array B<glist>. The array consist of all NIDs of supported groups. +groups in the array B<glist>. The array consist of all B<NIDs> of supported groups. The supported groups for B<TLSv1.3> include: B<NID_X9_62_prime256v1>, B<NID_secp384r1>, @@ -73,20 +73,27 @@ B<SSL_OP_CIPHER_SERVER_PREFERENCE> is se array determines the selected group. Otherwise, the order is ignored and the client's order determines the selection. -For a TLS 1.3 server, the groups determine the selected group, but -selection is more complex. A TLS 1.3 client sends both a group list as well as a -predicted subset of groups. Choosing a group outside the predicted subset incurs -an extra roundtrip. However, in some situations, the most preferred group may -not be predicted. OpenSSL considers all supported groups in I<clist> to be comparable -in security and prioritizes avoiding roundtrips above either client or server -preference order. If an application uses an external provider to extend OpenSSL -with, e.g., a post-quantum algorithm, this behavior may allow a network attacker -to downgrade connections to a weaker algorithm. It is therefore recommended -to use SSL_CTX_set1_groups_list() with the ability to specify group tuples. +For a TLS 1.3 server, the groups determine the selected group, but selection is +more complex. +A TLS 1.3 client sends both a group list and predicted keyshares for a subset +of groups. +A server choosing a group outside the client's predicted subset incurs an extra +roundtrip. +However, in some situations, the most preferred group may not be predicted. + +When groups are specified via SSL_CTX_set1_groups() as a list of B<NID> +values, OpenSSL considers all supported groups in I<clist> to be comparable in +security and prioritises avoiding roundtrips above either client or server +preference order. +If an application uses an external provider to extend OpenSSL with, e.g., a +post-quantum algorithm, this behavior may allow a network attacker to downgrade +connections to a weaker algorithm. +It is therefore recommended to use SSL_CTX_set1_groups_list() instead, making +it possible to specify group tuples as described below. SSL_CTX_set1_groups_list() sets the supported groups for B<ctx> to string I<list>. In contrast to SSL_CTX_set1_groups(), the names of the -groups, rather than their NIDs, are used. +groups, rather than their B<NIDs>, are used. The commands below list the available groups for TLS 1.2 and TLS 1.3, respectively: @@ -102,30 +109,72 @@ The preferred group names are those defi L<IANA|https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8>. The I<list> can be used to define several group tuples of comparable security -levels, and can specify which key shares should be sent by a client. -The specified list elements can optionally be ignored, if not implemented +levels, and can specify which predicted key shares should be sent by a client. +Group tuples are used by OpenSSL TLS servers to decide whether to request a +stronger keyshare than those predicted by sending a Hello Retry Request +(B<HRR>) even if some of the predicted groups are supported. +OpenSSL clients ignore tuple boundaries, and pay attenion only to the overall +order of I<list> elements and which groups are selected as predicted keyshares +as described below. + +The specified list elements can optionally be ignored if not implemented (listing unknown groups otherwise results in error). -It is also possible to specify the built-in default set of groups, and to explicitly -remove a group from that list. +It is also possible to specify the built-in default set of groups, and to +explicitly remove a group from that list. -In its simplest form, the string I<list> is just a colon separated list -of group names, for example "P-521:P-384:P-256:X25519:ffdhe2048". The first -group listed will also be used for the B<key_share> sent by a client in a -TLSv1.3 B<ClientHello>. For servers note the discussion above. The list should -be in order of preference with the most preferred group first. - -Group tuples of comparable security are defined by separating them from each -other by a tuple separator C</>. Keyshares to be sent by a client are specified -by prepending a C<*> to the group name, while any C<*> will be ignored by a -server. The following string I<list> for example defines three tuples when -used on the server-side, and triggers the generation of three key shares -when used on the client-side: P-521:*P-256/*P-384/*X25519:P-384:ffdhe2048. - -If a group name is preceded with the C<?> character, it will be ignored if an -implementation is missing. If a group name is preceded with the C<-> character, it -will be removed from the list of groups if present (including not sending a -key share for this group), ignored otherwise. The pseudo group name -C<DEFAULT> can be used to select the OpenSSL built-in default list of groups. +In its simplest legacy form, the string I<list> is just a colon separated list +of group names, for example "P-521:P-384:P-256:X25519:ffdhe2048". +The first group listed will in this case be used as the sole predicted +B<key_share> sent by a client in a TLSv1.3 B<ClientHello>. +The list should be in order of preference with the most preferred group first. + +A more expressive syntax supports definition of group tuples of comparable +security by separating them from each other with C</> characters. + +The predicted keyshares to be sent by clients can be explicitly specified by +adding a C<*> prefix to the associated group name. +These C<*> prefixes are ignored by servers. + +If a group name is prefixed with the C<?> character, it will be ignored if an +implementation is missing. +Otherwise, listing an unknown group name will cause a failure to parse the +I<list>. +Note that whether a group is known or not may depend on the OpenSSL version, +how OpenSSL was compiled and/or which providers are loaded. +Make sure you have the correct spelling of the group name and when in doubt +prefix it with a C<?> to handle configurations in which it might nevertheless +be unknown. + +If a group name is prefixed with the C<-> character, it will be removed from +the list of groups specified up to that point. +It can be added again if specified later. +Removal of groups that have not been included earlier in the list is silently +ignored. + +The pseudo group name C<DEFAULT> can be used to select the OpenSSL built-in +default list of groups. +Prepending one or more groups to C<DEFAULT> using only C<:> separators prepends those +groups to the built-in default list's first tuple. +Additional tuples can be prepended by use of the C</> separator. +Appending a set of groups to C<DEFAULT> using only C<:> separators appends those +groups to the built-in default list's last tuple. +Additional tuples can be appended by use of the C</> separator. + +The B<DEFAULT> list selects B<X25519MLKEM768> as one of the predicted keyshares. +In rare cases this can lead to failures or timeouts because the resulting +larger TLS Client Hello message may no longer fit in a single TCP segment and +firewall software may erroneously disrupt the TLS handshake. +If this is an issue or concern, prepending C<?X25519MLKEM768:> without a C<*> +prefix leads to its occurrence in the default list to be ignored as a duplicate, +and along with that also the keyshare prediction. +The group will then only be selected by servers that specifically expect it, +after a Hello Retry Request (HRR). +Servers that specifically prefer B<X25519MLKEM768>, are much less likely to be +found behind problematic firewalls. + +The following string I<list> for example defines three tuples when used on the +server-side, and triggers the generation of three key shares when used on the +client-side: P-521:*P-256/*P-384/*X25519:P-384:ffdhe2048. For a TLS 1.3 client, all the groups in the string I<list> are added to the supported groups extension of a C<ClientHello>, in the order in which they are listed, Index: openssl-3.5.3/ssl/t1_lib.c =================================================================== --- openssl-3.5.3.orig/ssl/t1_lib.c +++ openssl-3.5.3/ssl/t1_lib.c @@ -213,7 +213,7 @@ static const uint16_t suiteb_curves[] = /* Group list string of the built-in pseudo group DEFAULT_SUITE_B */ #define SUITE_B_GROUP_NAME "DEFAULT_SUITE_B" -#define SUITE_B_GROUP_LIST "secp256r1:secp384r1", +#define SUITE_B_GROUP_LIST "?secp256r1:?secp384r1", struct provider_ctx_data_st { SSL_CTX *ctx; @@ -1239,8 +1239,8 @@ typedef struct { size_t ksidcnt; /* Number of key shares */ uint16_t *ksid_arr; /* The IDs of the key share groups (flat list) */ /* Variable to keep state between execution of callback or helper functions */ - size_t tuple_mode; /* Keeps track whether tuple_cb called from 'the top' or from gid_cb */ - int ignore_unknown_default; /* Flag such that unknown groups for DEFAULT[_XYZ] are ignored */ + int inner; /* Are we expanding a DEFAULT list */ + int first; /* First tuple of possibly nested expansion? */ } gid_cb_st; /* Forward declaration of tuple callback function */ @@ -1315,16 +1315,16 @@ static int gid_cb(const char *elem, int for (i = 0; i < OSSL_NELEM(default_group_strings); i++) { if ((size_t)len == (strlen(default_group_strings[i].list_name)) && OPENSSL_strncasecmp(default_group_strings[i].list_name, elem, len) == 0) { + int saved_first; + /* * We're asked to insert an entire list of groups from a * DEFAULT[_XYZ] 'pseudo group' which we do by * recursively calling this function (indirectly via * CONF_parse_list and tuple_cb); essentially, we treat a DEFAULT * group string like a tuple which is appended to the current tuple - * rather then starting a new tuple. Variable tuple_mode is the flag which - * controls append tuple vs start new tuple. + * rather then starting a new tuple. */ - if (ignore_unknown || remove_group) return -1; /* removal or ignore not allowed here -> syntax error */ @@ -1349,15 +1349,18 @@ static int gid_cb(const char *elem, int strlen(default_group_strings[i].group_string)); restored_default_group_string[strlen(default_group_strings[i].group_string) + restored_prefix_index] = '\0'; - /* We execute the recursive call */ - garg->ignore_unknown_default = 1; /* We ignore unknown groups for DEFAULT_XYZ */ - /* we enforce group mode (= append tuple) for DEFAULT_XYZ group lists */ - garg->tuple_mode = 0; + /* + * Append first tuple of result to current tuple, and don't + * terminate the last tuple until we return to a top-level + * tuple_cb. + */ + saved_first = garg->first; + garg->inner = garg->first = 1; /* We use the tuple_cb callback to process the pseudo group tuple */ retval = CONF_parse_list(restored_default_group_string, TUPLE_DELIMITER_CHARACTER, 1, tuple_cb, garg); - garg->tuple_mode = 1; /* next call to tuple_cb will again start new tuple */ - garg->ignore_unknown_default = 0; /* reset to original value */ + garg->inner = 0; + garg->first = saved_first; /* We don't need the \0-terminated string anymore */ OPENSSL_free(restored_default_group_string); @@ -1377,9 +1380,6 @@ static int gid_cb(const char *elem, int if (len == 0) return -1; /* Seems we have prefxes without a group name -> syntax error */ - if (garg->ignore_unknown_default == 1) /* Always ignore unknown groups for DEFAULT[_XYZ] */ - ignore_unknown = 1; - /* Memory management in case more groups are present compared to initial allocation */ if (garg->gidcnt == garg->gidmax) { uint16_t *tmp = @@ -1455,51 +1455,48 @@ static int gid_cb(const char *elem, int } /* Remove group (and keyshare) from anywhere in the list if present, ignore if not present */ if (remove_group) { - /* Is the current group specified anywhere in the entire list so far? */ - found_group = 0; - for (i = 0; i < garg->gidcnt; i++) - if (garg->gid_arr[i] == gid) { - found_group = 1; + size_t n; /* tuple size */ + + j = 0; /* tuple index */ + k = 0; /* keyshare index */ + n = garg->tuplcnt_arr[j]; + + for (i = 0; i < garg->gidcnt; ++i) { + if (garg->gid_arr[i] == gid) break; - } - /* The group to remove is at position i in the list of (zero indexed) groups */ - if (found_group) { - /* We remove that group from its position (which is at i)... */ - for (j = i; j < (garg->gidcnt - 1); j++) - garg->gid_arr[j] = garg->gid_arr[j + 1]; /* ...shift remaining groups left ... */ - garg->gidcnt--; /* ..and update the book keeping for the number of groups */ + /* Skip keyshare slots associated with groups prior to that removed */ + if (k < garg->ksidcnt && garg->gid_arr[i] == garg->ksid_arr[k]) + ++k; + /* Skip to next tuple? */ + if (j < garg->tplcnt && --n == 0) + n = garg->tuplcnt_arr[++j]; + } - /* - * We also must update the number of groups either in a previous tuple (which we - * must identify and check whether it becomes empty due to the deletion) or in - * the current tuple, pending where the deleted group resides - */ - k = 0; - for (j = 0; j < garg->tplcnt; j++) { - k += garg->tuplcnt_arr[j]; - /* Remark: i is zero-indexed, k is one-indexed */ - if (k > i) { /* remove from one of the previous tuples */ - garg->tuplcnt_arr[j]--; - break; /* We took care not to have group duplicates, hence we can stop here */ - } - } - if (k <= i) /* remove from current tuple */ - garg->tuplcnt_arr[j]--; + /* Nothing to remove? */ + if (i >= garg->gidcnt) + goto done; - /* We also remove the group from the list of keyshares (if present) */ - found_group = 0; - for (i = 0; i < garg->ksidcnt; i++) - if (garg->ksid_arr[i] == gid) { - found_group = 1; - break; - } - if (found_group) { - /* Found, hence we remove that keyshare from its position (which is at i)... */ - for (j = i; j < (garg->ksidcnt - 1); j++) - garg->ksid_arr[j] = garg->ksid_arr[j + 1]; /* shift remaining key shares */ - /* ... and update the book keeping */ - garg->ksidcnt--; - } + garg->gidcnt--; + garg->tuplcnt_arr[j]--; + memmove(garg->gid_arr + i, garg->gid_arr + i + 1, + (garg->gidcnt - i) * sizeof(gid)); + + /* Handle keyshare removal */ + if (k < garg->ksidcnt && garg->ksid_arr[k] == gid) { + garg->ksidcnt--; + memmove(garg->ksid_arr + k, garg->ksid_arr + k + 1, + (garg->ksidcnt - k) * sizeof(gid)); + } + + /* + * Adjust closed or current tuple's group count, if a closed tuple + * count reaches zero excise the resulting empty tuple. The current + * (not yet closed) tuple at the end of the list stays even if empty. + */ + if (garg->tuplcnt_arr[j] == 0 && j < garg->tplcnt) { + garg->tplcnt--; + memmove(garg->tuplcnt_arr + j, garg->tuplcnt_arr + j + 1, + (garg->tplcnt - j) * sizeof(size_t)); } } else { /* Processing addition of a single new group */ @@ -1515,7 +1512,7 @@ static int gid_cb(const char *elem, int /* and update the book keeping for the number of groups in current tuple */ garg->tuplcnt_arr[garg->tplcnt]++; - /* We memorize if needed that we want to add a key share for the current group */ + /* We want to add a key share for the current group */ if (add_keyshare) garg->ksid_arr[garg->ksidcnt++] = gid; } @@ -1524,6 +1521,34 @@ done: return retval; } +static int grow_tuples(gid_cb_st *garg) +{ + if (garg->tplcnt == garg->tplmax) { + size_t *tmp = OPENSSL_realloc_array(garg->tuplcnt_arr, + garg->tplmax + GROUPLIST_INCREMENT, + sizeof(*garg->tuplcnt_arr)); + + if (tmp == NULL) + return 0; + garg->tplmax += GROUPLIST_INCREMENT; + garg->tuplcnt_arr = tmp; + } + return 1; +} + +static int close_tuple(gid_cb_st *garg) +{ + size_t gidcnt = garg->tuplcnt_arr[garg->tplcnt]; + + if (gidcnt == 0) + return 1; + if (!grow_tuples(garg)) + return 0; + + garg->tuplcnt_arr[++garg->tplcnt] = 0; + return 1; +} + /* Extract and process a tuple of groups */ static int tuple_cb(const char *tuple, int len, void *arg) { @@ -1537,17 +1562,9 @@ static int tuple_cb(const char *tuple, i return 0; } - /* Memory management for tuples */ - if (garg->tplcnt == garg->tplmax) { - size_t *tmp = - OPENSSL_realloc(garg->tuplcnt_arr, - (garg->tplmax + GROUPLIST_INCREMENT) * sizeof(*garg->tuplcnt_arr)); - - if (tmp == NULL) - return 0; - garg->tplmax += GROUPLIST_INCREMENT; - garg->tuplcnt_arr = tmp; - } + if (garg->inner && !garg->first && !close_tuple(garg)) + return 0; + garg->first = 0; /* Convert to \0-terminated string */ restored_tuple_string = OPENSSL_malloc((len + 1 /* \0 */) * sizeof(char)); @@ -1562,15 +1579,8 @@ static int tuple_cb(const char *tuple, i /* We don't need the \o-terminated string anymore */ OPENSSL_free(restored_tuple_string); - if (garg->tuplcnt_arr[garg->tplcnt] > 0) { /* Some valid groups are present in current tuple... */ - if (garg->tuple_mode) { - /* We 'close' the tuple */ - garg->tplcnt++; - garg->tuplcnt_arr[garg->tplcnt] = 0; /* Next tuple is initialized to be empty */ - garg->tuple_mode = 1; /* next call will start a tuple (unless overridden in gid_cb) */ - } - } - + if (!garg->inner && !close_tuple(garg)) + return 0; return retval; } @@ -1601,8 +1611,6 @@ int tls1_set_groups_list(SSL_CTX *ctx, } memset(&gcb, 0, sizeof(gcb)); - gcb.tuple_mode = 1; /* We prepare to collect the first tuple */ - gcb.ignore_unknown_default = 0; gcb.gidmax = GROUPLIST_INCREMENT; gcb.tplmax = GROUPLIST_INCREMENT; gcb.ksidmax = GROUPLIST_INCREMENT; Index: openssl-3.5.3/test/tls13groupselection_test.c =================================================================== --- openssl-3.5.3.orig/test/tls13groupselection_test.c +++ openssl-3.5.3/test/tls13groupselection_test.c @@ -38,6 +38,12 @@ typedef enum SERVER_RESPONSE { SH = 2 } SERVER_RESPONSE; +static const char *response_desc[] = { + "HRR", + "INIT", + "SH", +}; + static char *cert = NULL; static char *privkey = NULL; @@ -49,6 +55,18 @@ struct tls13groupselection_test_st { const enum SERVER_RESPONSE expected_server_response; }; + +/* + * Tests that probe robust handling of group removal depend on detailed + * knowledge of the default group list. A stable list is needed that does not + * depend on future changes in the actual built-in default. + */ +#define TEST_DEFLT \ + "?*X25519MLKEM768 / " \ + "?*X25519 : ?secp256r1 / " \ + "?X448 : ?secp384r1 : ?secp521r1 / " \ + "?ffdhe2048:?ffdhe3072" + static const struct tls13groupselection_test_st tls13groupselection_tests[] = { @@ -348,7 +366,39 @@ static const struct tls13groupselection_ "X25519", SERVER_PREFERENCE, NEGOTIATION_FAILURE, INIT - } + }, + /* DEFAULT retains tuple structure */ + { "*X25519:secp256r1", + "secp256r1:DEFAULT", /* test 44 */ + SERVER_PREFERENCE, + "secp256r1", HRR }, +#ifndef OPENSSL_NO_DH + { "*ffdhe2048:secp256r1", + "DEFAULT:ffdhe4096", /* test 45 */ + CLIENT_PREFERENCE, + "secp256r1", HRR }, + { "x25519:ffdhe2048:*ffdhe4096", + "DEFAULT:ffdhe4096", /* test 46 */ + SERVER_PREFERENCE, + "x25519", HRR }, + /* + * The server's second tuple becomes empty after removal + * of "secp256r1", the subsequent removal of X448 is + * then from the third tuple. + */ + { "*ffdhe2048:secp384r1", /* test 47 */ + "*X25519:" TEST_DEFLT ":-secp256r1:-X448", + SERVER_PREFERENCE, + "secp384r1", HRR }, + /* + * The server's last tuple becomes empty after removals, + * and then continues to fill. + */ + { "*ffdhe2048:ffdhe4096", /* test 48 */ + "*X25519:" TEST_DEFLT ":-ffdhe2048:-ffdhe3072:ffdhe4096", + SERVER_PREFERENCE, + "ffdhe4096", HRR }, +#endif }; static void server_response_check_cb(int write_p, int version, @@ -359,10 +409,12 @@ static void server_response_check_cb(int enum SERVER_RESPONSE *server_response = (enum SERVER_RESPONSE *)arg; /* Prepare check for HRR */ const uint8_t *incoming_random = (uint8_t *)buf + 6; - const uint8_t magic_HRR_random[32] = { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, - 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, - 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, - 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C }; + const uint8_t magic_HRR_random[32] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C + }; /* Did a server hello arrive? */ if (write_p == 0 && /* Incoming data... */ @@ -492,15 +544,16 @@ static int test_groupnegotiation(const s group_name_client = SSL_group_to_name(clientssl, negotiated_group_client); if (!TEST_int_eq(negotiated_group_client, negotiated_group_server)) goto end; - if (!TEST_int_eq((int)current_test_vector->expected_server_response, (int)server_response)) + if (!TEST_str_eq(response_desc[current_test_vector->expected_server_response], + response_desc[server_response])) goto end; if (TEST_str_eq(group_name_client, current_test_vector->expected_group)) ok = 1; } else { TEST_false_or_end(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)); - if (test_type == TEST_NEGOTIATION_FAILURE && - !TEST_int_eq((int)current_test_vector->expected_server_response, - (int)server_response)) + if (test_type == TEST_NEGOTIATION_FAILURE + && !TEST_str_eq(response_desc[current_test_vector->expected_server_response], + response_desc[server_response])) goto end; ok = 1; } ++++++ openssl-CVE-2026-28387.patch ++++++ commit 444958deaf450aea819171f97ae69eaedede42c3 Author: Alexandr Nedvedicky <[email protected]> Date: Tue Mar 3 13:23:46 2026 +0100 dane_match_cert() should X509_free() on ->mcert instead of OPENSSL_free() Fixes: 170b735820ac "DANE support for X509_verify_cert()" Reviewed-by: Eugene Syromiatnikov <[email protected]> Reviewed-by: Tomas Mraz <[email protected]> Reviewed-by: Paul Dale <[email protected]> Reviewed-by: Neil Horman <[email protected]> MergeDate: Thu Mar 5 12:37:17 2026 (Merged from https://github.com/openssl/openssl/pull/30250) (cherry picked from commit 8b5cd6a682f0f6e7b8bf55137137c567d1899c4a) diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 8f1b9f58ca..01ce14982d 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -3016,7 +3016,7 @@ static int dane_match_cert(X509_STORE_CTX *ctx, X509 *cert, int depth) break; } - OPENSSL_free(dane->mcert); + X509_free(dane->mcert); dane->mcert = cert; dane->mdpth = depth; dane->mtlsa = t; ++++++ openssl-CVE-2026-28388-tests.patch ++++++ >From ee5f89352b7bbc768436cce684036c24052a1938 Mon Sep 17 00:00:00 2001 From: Daniel Kubec <[email protected]> Date: Tue, 17 Mar 2026 11:14:56 +0100 Subject: [PATCH] Added test for CVE-2026-28388 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Saša Nedvědický <[email protected]> Reviewed-by: Tomas Mraz <[email protected]> MergeDate: Mon Apr 6 19:27:17 2026 (cherry picked from commit dd3544845e206ec8cbcbd756e2d402c57fc5d313) Signed-off-by: Lucas Mulling <[email protected]> --- test/certs/cve-2026-28388-ca.pem | 19 +++++++++++++++++++ test/certs/cve-2026-28388-crls.pem | 22 ++++++++++++++++++++++ test/certs/cve-2026-28388-leaf.pem | 19 +++++++++++++++++++ test/recipes/25-test_verify.t | 14 +++++++++++++- 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/certs/cve-2026-28388-ca.pem create mode 100644 test/certs/cve-2026-28388-crls.pem create mode 100644 test/certs/cve-2026-28388-leaf.pem Index: openssl-3.5.3/test/certs/cve-2026-28388-ca.pem =================================================================== --- /dev/null +++ openssl-3.5.3/test/certs/cve-2026-28388-ca.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgIUOl5NN/jfsuLU9JSGLZAfRzviF+owDQYJKoZIhvcNAQEL +BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAeFw0yNjAzMTcwODE5NDdaFw0yNzAzMTcw +ODE5NDdaMBIxEDAOBgNVBAMMB1Rlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQD0m4KETjF0c25spNWUiNChWP0GalDL0gVDFbtAoMVF/lvlZEcp +hcg62ifHJRPntWyVAmH70DAI87cWzl/73QYGaOcMVcH5yEM31BoK83FvhsS3RTPO +FSrNCHaZrrWuga+QkBmMcR6qX7GF5eb6ASMBsLuuDqbkCRbTJ2ryhYeWF+VFemBF +pSHpcinSSLvswTVbZiCqmoy0WkK8eiyfLMZA17PgVLQpyPZ3rp5YG5vEZZoqFc/f +1bCHjwQ7fNdLCEMqPvE/I0mg2skRClb1L1Vieud/jmjL8nVd9I12j1eUOcSKtCkW +nj4BFa7TRz13sN3LZOFvV774ZaXRJ1GxoAlnAgMBAAGjYzBhMB0GA1UdDgQWBBSt +UxfaVbV9QMmfwMoImdgi4MZHzTAfBgNVHSMEGDAWgBStUxfaVbV9QMmfwMoImdgi +4MZHzTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B +AQsFAAOCAQEA84w49n0pPJlqiD1/mn3pUZ66lBP0fFZiCuV/3YatBZcW+xcboW0Q +xImYztjZo0i+sQLZOalI4GoBqD77Dv4Qas0QoJZIp0wM8DjE3YcudCr4cpUhT1XC +ruHVHQA9bY5rW0GsfUBW6/3RbRpiK4SaFG3sUBbXPo0dC2EaLDjpLM7o2UljRrWu +d/vg6ieKuAicexLxqQLdM4SxjyvBpCwHg/dnMxawSj4Xhks1BHJ0hTLKJGDgfVHh +ex8+878u6Gf7fAOZa5idWUgTvdt5WHSW5x+Tm/P6LGG3HkM425ZU6BLTCHONoBud +cOlfWTTuIyweX5TRL5HY3SuO1cpMBpjiAA== +-----END CERTIFICATE----- Index: openssl-3.5.3/test/certs/cve-2026-28388-crls.pem =================================================================== --- /dev/null +++ openssl-3.5.3/test/certs/cve-2026-28388-crls.pem @@ -0,0 +1,22 @@ +-----BEGIN X509 CRL----- +MIIBizB1AgEBMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMMB1Rlc3QgQ0EXDTI2 +MDMxNzA4MTk0N1oXDTI2MDQxNjA4MTk0N1qgLzAtMB8GA1UdIwQYMBaAFK1TF9pV +tX1AyZ/AygiZ2CLgxkfNMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBl +3vVknchCNA/oW0ovtnrE+xQs8yAk3uElooQlw88moTcts2YAcKWl49lnNWZk/RbF +Zs8m+MUuNb2W861siuvY3EwnSKVaJB2tKPfCRBP4xt+Q0g/Tn5CWxzpzHjQfLT6l +pvWOwaO7aE6bthX7MQ9XBpnHSPxsbul+MhV5PER11BYZGVh5MH0XxfMI0jDHFh2M +klTamgaao3TkVOI3OQPgzUx/q0Lz/YoCIH0pYGGP6KTGUX2x7UfD1tcIOcUp6tvO +6hG3utMgJOpZJl9yMzhG+ZURjbz4MSbBM0FVIaWnBn2VzY1jHGky0nK83IZhiddf +OohWoSH8tqwrNFZkblAH +-----END X509 CRL----- +-----BEGIN X509 CRL----- +MIIBjjB4AgEBMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMMB1Rlc3QgQ0EXDTI2 +MDEwODEyMDAwMFoXDTI2MDIwODEyMDAwMFqgMjAwMB8GA1UdIwQYMBaAFK1TF9pV +tX1AyZ/AygiZ2CLgxkfNMA0GA1UdGwEB/wQDAgEBMA0GCSqGSIb3DQEBCwUAA4IB +AQCyYxa5iVUFxBpdXgBGSMqkuxJqQzVni8nXK0DiXHfgbTud+HD5Qp/6PX2EQuwK +SrT0yeNJBU1gxxMMsbdA0yVTPa7N2Ny39mjq/27yBXduiljo3Gs4NLEW9grJRnep +WOD1cQe3Fea5HlEfUoQJF1WVekF6CnOSqESaDvTAzqpZd7pxU8cuduiRJPin93ki +1nicQAU/G4Td190+JEAWD3/dJTg2LF6LKrmHiv2ZUTuNsVBfcbhFSoC6FpnjFUAI +kF8EgJpuBEfqV6erIuT1GD+5p1QGNqdcNl7LO9erJaUFnssJBJtj84iXd7RZARNs +njcibOSKC9YWgNmZUy0QV5D8 +-----END X509 CRL----- Index: openssl-3.5.3/test/certs/cve-2026-28388-leaf.pem =================================================================== --- /dev/null +++ openssl-3.5.3/test/certs/cve-2026-28388-leaf.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDHTCCAgWgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdUZXN0 +IENBMB4XDTI2MDMxNzA4MTk0N1oXDTI3MDMxNzA4MTk0N1owFDESMBAGA1UEAwwJ +VGVzdCBMZWFmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqx7jpC6+ +nRZ4ol6sShkpv04hGYtt7y+Ns4oIfdQTqo57DItFab8D8cH04zR8NND42MMnsPPn +Ovh9gv2l1mj9ZfwgXI5PvaKc6CoXvXb0ttekdDUS1iw9g04BxIXTDANxsdSXrCDd +Npyr1Pxdo3N2fiH6qN9/Lsh7yg0vJW/aJzdvhLcCTFcr89qmCsh17XfcTR0wZJXP +QdlRib9EK8aa6aKOYmm44SBbuXXyWojhheUaqVuzDj6A0L9opmh/DVXa9bdIN/FX +CKJB+d60Qxy5pKwpzDDxbCdG2vA1U2cPz8yAgelFG5AmXSHF7Id4G6GTCAY6PbTO +Jy2Z4I6NY+mj5wIDAQABo3wwejAdBgNVHQ4EFgQUlf2YZ93MvS4kZm7fshosgp+J +ImkwHwYDVR0jBBgwFoAUrVMX2lW1fUDJn8DKCJnYIuDGR80wCQYDVR0TBAIwADAt +BgNVHS4EJjAkMCKgIKAehhxodHRwOi8vZXhhbXBsZS5jb20vZGVsdGEucGVtMA0G +CSqGSIb3DQEBCwUAA4IBAQDoNAQGLS0Juf3i2fhuVQyWIFvNIMElLexeLnnd/y80 +13nsP68ZGT2D3DoHQSz3SL7sNjLBc2CiUVftdaRQ4dNCz8sBY5BRTS5XEGbbTAFZ +bQUReykuuTy83CGw/JYN6YT/OHcf4gEhUnWtRMCmIz3J/NMRVSRnpV2Ezjltm/Q+ +emFS/QclRhkP6Vu+lwM/nV6uAN8T7Ba68Hym2MN0clozrpoKeqFouB7D0i+iCZMw +zbac5as0hn7Fm+HGTbfTs2/fqUslvE6PmagepceP37pTSSVmYRmdpOD2cyCb30A+ +nJFGQg7PcacGSL1re65W35XzdU8Si8OYD+PxjDaRbPcP +-----END CERTIFICATE----- Index: openssl-3.5.3/test/recipes/25-test_verify.t =================================================================== --- openssl-3.5.3.orig/test/recipes/25-test_verify.t +++ openssl-3.5.3/test/recipes/25-test_verify.t @@ -30,7 +30,7 @@ sub verify { run(app([@args])); } -plan tests => 202; +plan tests => 203; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -595,6 +595,18 @@ ok(!verify("ee-cert-policies-bad", "", [ "-explicit_policy"), "Bad certificate policy"); +# CVE-2026-28388 +my $cve_28388_stderr = "cve-2026-28388.err"; +run(app(["openssl", "verify", + "-attime", "1739527200", + "-CAfile", srctop_file(@certspath, "cve-2026-28388-ca.pem"), + "-crl_check", "-use_deltas", + "-CRLfile", srctop_file(@certspath, "cve-2026-28388-crls.pem"), + srctop_file(@certspath, "cve-2026-28388-leaf.pem")], + stderr => $cve_28388_stderr)); +ok(grep(/CRL is not yet valid/, do { open my $fh, '<', $cve_28388_stderr; <$fh> }), + "CVE-2026-28388"); + # CAstore option my $rootcertname = "root-cert"; my $rootcert = srctop_file(@certspath, "${rootcertname}.pem"); ++++++ openssl-CVE-2026-28388.patch ++++++ commit 6297bdc962e9f2ecb436e26dc51f4fff653a0a89 Author: Daniel Kubec <[email protected]> Date: Tue Mar 17 11:11:22 2026 +0100 Fix NULL Dereference When Delta CRL Lacks CRL Number Extension Fixes CVE-2026-28388 Fixes https://github.com/openssl/srt/issues/77 diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 827a7663aa..f2b88524b6 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -1578,6 +1578,8 @@ static int check_delta_base(X509_CRL *delta, X509_CRL *base) if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) return 0; /* Delta CRL number must exceed full CRL number */ + if (delta->crl_number == NULL) + return 0; return ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0; } ++++++ openssl-CVE-2026-28389.patch ++++++ commit e406df64aea245a4caacf25793df9efa08ea5d8f Author: Neil Horman <[email protected]> Date: Mon Mar 16 13:49:07 2026 -0400 Fix inadvertent NULL deref in [ec]dh_cms_set_shared_info Two independent reports indicated a SIGSEGV was possible in CMS processing when a crafted CMS EnvelopedData message using A Key Agreement Recipient Info field. If they KeyEncryptionAlgorithmIdentifier omits the optional parameter field, The referenced funcitons above will attempt to dereference the alg->parameter data prior to checking if the paramter field is NULL. Easy fix, just make sure to check if the field is NULL before accessing Confirmed to resolve the issues using the reproducers provided in the security reports. Fixes CVE-2026-28389 diff --git a/crypto/cms/cms_dh.c b/crypto/cms/cms_dh.c index a10df73b10..7478a5dd5e 100644 --- a/crypto/cms/cms_dh.c +++ b/crypto/cms/cms_dh.c @@ -94,6 +94,9 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) goto err; + if (alg == NULL || alg->parameter == NULL) + goto err; + /* * For DH we only have one OID permissible. If ever any more get defined * we will need something cleverer. diff --git a/crypto/cms/cms_ec.c b/crypto/cms/cms_ec.c index ff8adad616..a5a00ca276 100644 --- a/crypto/cms/cms_ec.c +++ b/crypto/cms/cms_ec.c @@ -171,6 +171,9 @@ static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) return 0; + if (alg == NULL || alg->parameter == NULL) + return 0; + if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) { ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR); return 0; ++++++ openssl-CVE-2026-28390.patch ++++++ >From 2e39b7a6993be445fddb9fbce316fa756e0397b6 Mon Sep 17 00:00:00 2001 From: Neil Horman <[email protected]> Date: Wed, 1 Apr 2026 10:56:44 +0200 Subject: [PATCH] Fix NULL deref in rsa_cms_decrypt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Very simmilar to CVE-2026-28389, ensure that if we are missing parameters in RSA-OAEP SourceFunc in CMS KeyTransportRecipientInfo, we don't segfault when decrypting. Co-authored-by: Tomas Mraz <[email protected]> Fixes CVE-2026-28390 Reviewed-by: Saša Nedvědický <[email protected]> Reviewed-by: Nikola Pajkovsky <[email protected]> MergeDate: Mon Apr 6 19:06:14 2026 --- crypto/cms/cms_rsa.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) Index: openssl-3.5.0/crypto/cms/cms_rsa.c =================================================================== --- openssl-3.5.0.orig/crypto/cms/cms_rsa.c +++ openssl-3.5.0/crypto/cms/cms_rsa.c @@ -42,10 +42,13 @@ static int rsa_cms_decrypt(CMS_Recipient X509_ALGOR *cmsalg; int nid; int rv = -1; - unsigned char *label = NULL; + const unsigned char *label = NULL; int labellen = 0; const EVP_MD *mgf1md = NULL, *md = NULL; RSA_OAEP_PARAMS *oaep; + const ASN1_OBJECT *aoid; + const void *parameter = NULL; + int ptype = 0; pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (pkctx == NULL) @@ -75,21 +78,19 @@ static int rsa_cms_decrypt(CMS_Recipient goto err; if (oaep->pSourceFunc != NULL) { - X509_ALGOR *plab = oaep->pSourceFunc; + X509_ALGOR_get0(&aoid, &ptype, ¶meter, oaep->pSourceFunc); - if (OBJ_obj2nid(plab->algorithm) != NID_pSpecified) { + if (OBJ_obj2nid(aoid) != NID_pSpecified) { ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE); goto err; } - if (plab->parameter->type != V_ASN1_OCTET_STRING) { + if (ptype != V_ASN1_OCTET_STRING) { ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_LABEL); goto err; } - label = plab->parameter->value.octet_string->data; - /* Stop label being freed when OAEP parameters are freed */ - plab->parameter->value.octet_string->data = NULL; - labellen = plab->parameter->value.octet_string->length; + label = ASN1_STRING_get0_data(parameter); + labellen = ASN1_STRING_length(parameter); } if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0) @@ -98,10 +99,16 @@ static int rsa_cms_decrypt(CMS_Recipient goto err; if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0) goto err; - if (label != NULL - && EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0) { - OPENSSL_free(label); - goto err; + if (label != NULL) { + unsigned char *dup_label = OPENSSL_memdup(label, labellen); + + if (dup_label == NULL) + goto err; + + if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, dup_label, labellen) <= 0) { + OPENSSL_free(dup_label); + goto err; + } } /* Carry on */ rv = 1; ++++++ openssl-CVE-2026-31789.patch ++++++ commit c1f14e209519886cd7bc714cee819d8318b2f90f Author: Igor Ustinov <[email protected]> Date: Thu Mar 5 15:47:34 2026 +0100 Avoid possible buffer overflow in buf2hex conversion Fixes CVE-2026-31789 diff --git a/crypto/o_str.c b/crypto/o_str.c index 22d8028beb..c2ec1fc261 100644 --- a/crypto/o_str.c +++ b/crypto/o_str.c @@ -299,6 +299,11 @@ static int buf2hexstr_sep(char *str, size_t str_n, size_t *strlength, int has_sep = (sep != CH_ZERO); size_t i, len = has_sep ? buflen * 3 : 1 + buflen * 2; + if (buflen > (has_sep ? SIZE_MAX / 3 : (SIZE_MAX - 1) / 2)) { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_BYTES); + return 0; + } + if (len == 0) ++len; if (strlength != NULL) @@ -344,7 +349,13 @@ char *ossl_buf2hexstr_sep(const unsigned char *buf, long buflen, char sep) if (buflen == 0) return OPENSSL_zalloc(1); - tmp_n = (sep != CH_ZERO) ? buflen * 3 : 1 + buflen * 2; + if ((sep != CH_ZERO && (size_t)buflen > SIZE_MAX / 3) + || (sep == CH_ZERO && (size_t)buflen > (SIZE_MAX - 1) / 2)) { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_BYTES); + return NULL; + } + + tmp_n = (sep != CH_ZERO) ? (size_t)buflen * 3 : 1 + (size_t)buflen * 2; if ((tmp = OPENSSL_malloc(tmp_n)) == NULL) return NULL; ++++++ openssl-CVE-2026-31790-tests.patch ++++++ commit 5872c416ef46aabc48c2025fd064bedf221aaee0 Author: Nikola Pajkovsky <[email protected]> Date: Mon Mar 23 08:41:20 2026 +0100 rsa_kem: test RSA_public_encrypt() result in RSASVE RSA_public_encrypt() returns the number of bytes written on success and -1 on failure. Add regression coverage in evp_extra_test using invalid RSA pubkey which triggers -1 in RSA_public_encrypt() using encapsulation. Fixes: https://github.com/openssl/srt/issues/95 Signed-off-by: Nikola Pajkovsky <[email protected]> Index: openssl-3.5.0/test/evp_extra_test.c =================================================================== --- openssl-3.5.0.orig/test/evp_extra_test.c +++ openssl-3.5.0/test/evp_extra_test.c @@ -928,6 +928,32 @@ static EVP_PKEY *load_example_ec_key(voi #endif #ifndef OPENSSL_NO_DEPRECATED_3_0 + +static EVP_PKEY *make_bad_rsa_pubkey(void) +{ + RSA *rsa = NULL; + BIGNUM *n = NULL, *e = NULL; + EVP_PKEY *pkey = NULL; + + /* Deliberately invalid public key: n = 17, e = 17 */ + if (!TEST_ptr(pkey = EVP_PKEY_new()) + || !TEST_ptr(rsa = RSA_new()) + || !TEST_ptr(n = BN_new()) + || !TEST_ptr(e = BN_new()) + || !TEST_true(BN_set_word(n, 17)) + || !TEST_true(BN_set_word(e, 17)) + || !TEST_true(RSA_set0_key(rsa, n, e, NULL)) + || !EVP_PKEY_assign_RSA(pkey, rsa)) + goto err; + + return pkey; +err: + BN_free(n); + BN_free(e); + RSA_free(rsa); + return NULL; +} + # ifndef OPENSSL_NO_DH static EVP_PKEY *load_example_dh_key(void) { @@ -5901,6 +5927,46 @@ static int test_custom_ciph_meth(void) return testresult; } +static int test_rsasve_kem_with_invalid_pub_key(void) +{ + RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + unsigned char *ct = NULL; + unsigned char *secret = NULL; + size_t ctlen = 0, secretlen = 0; + int testresult = 0; + + if (nullprov != NULL) { + testresult = TEST_skip("Test does not support a non-default library context"); + goto err; + } + + if (!TEST_ptr(pkey = make_bad_rsa_pubkey())) + goto err; + + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pkey, NULL)) + || !TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1) + || !TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, "RSASVE"), 1) + || !TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, &ctlen, NULL, &secretlen), 1) + || !TEST_ptr(ct = OPENSSL_malloc(ctlen)) + || !TEST_ptr(secret = OPENSSL_malloc(secretlen))) + goto err; + + if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, ct, &ctlen, secret, &secretlen), 0)) + goto err; + + testresult = 1; + +err: + OPENSSL_free(secret); + OPENSSL_free(ct); + EVP_PKEY_CTX_free(ctx); + RSA_free(rsa); + EVP_PKEY_free(pkey); + return testresult; +} + # ifndef OPENSSL_NO_DYNAMIC_ENGINE /* Test we can create a signature keys with an associated ENGINE */ static int test_signatures_with_engine(int tst) @@ -6861,6 +6927,7 @@ int setup_tests(void) ADD_TEST(test_evp_md_cipher_meth); ADD_TEST(test_custom_md_meth); ADD_TEST(test_custom_ciph_meth); + ADD_TEST(test_rsasve_kem_with_invalid_pub_key); # ifndef OPENSSL_NO_DYNAMIC_ENGINE /* Tests only support the default libctx */ ++++++ openssl-CVE-2026-31790.patch ++++++ commit a6cea8781bf8fd53768a8ea3ff2d1120ec644b0d Author: Nikola Pajkovsky <[email protected]> Date: Thu Mar 19 12:16:08 2026 +0100 rsa_kem: validate RSA_public_encrypt() result in RSASVE RSA_public_encrypt() returns the number of bytes written on success and -1 on failure. With the existing `if (ret)` check, a provider-side RSA KEM encapsulation can incorrectly succeed when the underlying RSA public encrypt operation fails. In that case the code reports success, returns lengths as if encapsulation completed normally, and leaves the freshly generated secret available instead of discarding it. Tighten the success condition so RSASVE only succeeds when RSA_public_encrypt() returns a positive value equal to the modulus-sized output expected for RSA_NO_PADDING. Any other return value is treated as failure, and the generated secret is cleansed before returning. Fixes CVE: CVE-2026-31790 Fixes: https://github.com/openssl/srt/issues/95 Signed-off-by: Nikola Pajkovsky <[email protected]> diff --git a/providers/implementations/kem/rsa_kem.c b/providers/implementations/kem/rsa_kem.c index f7bf368a0d..74dfafddd9 100644 --- a/providers/implementations/kem/rsa_kem.c +++ b/providers/implementations/kem/rsa_kem.c @@ -316,17 +316,19 @@ static int rsasve_generate(PROV_RSA_CTX *prsactx, return 0; /* Step(3): out = RSAEP((n,e), z) */ - ret = RSA_public_encrypt(nlen, secret, out, prsactx->rsa, RSA_NO_PADDING); - if (ret) { - ret = 1; - if (outlen != NULL) - *outlen = nlen; - if (secretlen != NULL) - *secretlen = nlen; - } else { + ret = RSA_public_encrypt((int)nlen, secret, out, prsactx->rsa, + RSA_NO_PADDING); + if (ret <= 0 || ret != (int)nlen) { OPENSSL_cleanse(secret, nlen); + return 0; } - return ret; + + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + + return 1; } /** ++++++ openssl-NULL-pointer-dereference-in-ocsp_find_signer_sk.patch ++++++ commit de4bb3bfc7d5d56b2b678bbd90f60c8b440ea287 Author: Alexandr Nedvedicky <[email protected]> Date: Tue Mar 17 11:48:41 2026 +0100 CVE-2026-31791 NULL pointer dereference in ocsp_find_signer_sk() when ResponderID byKey is NULL the issue has been kindly reported and fix contributed by [email protected], [email protected] and [email protected] diff --git a/crypto/ocsp/ocsp_vfy.c b/crypto/ocsp/ocsp_vfy.c index 70e670cd63..d2a741c13f 100644 --- a/crypto/ocsp/ocsp_vfy.c +++ b/crypto/ocsp/ocsp_vfy.c @@ -199,6 +199,8 @@ static X509 *ocsp_find_signer_sk(const STACK_OF(X509) *certs, OCSP_RESPID *id) /* Lookup by key hash */ /* If key hash isn't SHA1 length then forget it */ + if (id->value.byKey == NULL) + return NULL; if (id->value.byKey->length != SHA_DIGEST_LENGTH) return NULL; keyhash = id->value.byKey->data; ++++++ openssl-crypto-mem.c-factor-out-memory-allocation-failure-reporting.patch ++++++ >From bd1c59739d57ca27162bd582161a5cbddba21999 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov <[email protected]> Date: Thu, 17 Jul 2025 03:29:35 +0200 Subject: [PATCH] crypto/mem.c: factor out memory allocation failure reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eugene Syromiatnikov <[email protected]> Reviewed-by: Saša Nedvědický <[email protected]> Reviewed-by: Matt Caswell <[email protected]> Reviewed-by: Paul Dale <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from https://github.com/openssl/openssl/pull/28059) Signed-off-by: Lucas Mulling <[email protected]> --- crypto/mem.c | 11 ++----- include/internal/mem_alloc_utils.h | 50 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 include/internal/mem_alloc_utils.h Index: openssl-3.5.3/crypto/mem.c =================================================================== --- openssl-3.5.3.orig/crypto/mem.c +++ openssl-3.5.3/crypto/mem.c @@ -9,6 +9,7 @@ #include "internal/e_os.h" #include "internal/cryptlib.h" +#include "internal/mem_alloc_utils.h" #include "crypto/cryptlib.h" #include <stdio.h> #include <stdlib.h> @@ -212,15 +213,7 @@ void *CRYPTO_malloc(size_t num, const ch if (ptr != NULL) return ptr; err: - /* - * ossl_err_get_state_int() in err.c uses CRYPTO_zalloc(num, NULL, 0) for - * ERR_STATE allocation. Prevent mem alloc error loop while reporting error. - */ - if (file != NULL || line != 0) { - ERR_new(); - ERR_set_debug(file, line, NULL); - ERR_set_error(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE, NULL); - } + ossl_report_alloc_err(file, line); return NULL; } Index: openssl-3.5.3/include/internal/mem_alloc_utils.h =================================================================== --- /dev/null +++ openssl-3.5.3/include/internal/mem_alloc_utils.h @@ -0,0 +1,50 @@ +/* + * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Utility overflow checking and reporting functions + */ + +#ifndef OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H +# define OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H + +# include "internal/common.h" + +# include <openssl/cryptoerr.h> +# include <openssl/err.h> + +/* + * A helper routine to report memory allocation errors. + * Similar to the ERR_raise() macro, but accepts explicit file/line arguments, + * pre-defines the library to ERR_LIB_CRYPTO, and avoids emitting an error + * if both file set to NULL and line set to 0. + */ +static ossl_inline ossl_unused void +ossl_report_alloc_err_ex(const char * const file, const int line, + const int reason) +{ + /* + * ossl_err_get_state_int() in err.c uses CRYPTO_zalloc(num, NULL, 0) for + * ERR_STATE allocation. Prevent mem alloc error loop while reporting error. + */ + if (file != NULL || line != 0) { + ERR_new(); + ERR_set_debug(file, line, NULL); + ERR_set_error(ERR_LIB_CRYPTO, reason, NULL); + } +} + +/* Report a memory allocation failure. */ +static inline void +ossl_report_alloc_err(const char * const file, const int line) +{ + ossl_report_alloc_err_ex(file, line, ERR_R_MALLOC_FAILURE); +} + +#endif /* OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H */
