summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Groffen <grobian@gentoo.org>2023-05-27 10:54:10 +0200
committerFabian Groffen <grobian@gentoo.org>2023-05-27 10:55:14 +0200
commitb03890e439529ef3bed2bb111f93687065dd54bb (patch)
tree0bee433b4cd85fc37179e429fa779fe1d435b3f9 /mail-mta
parentdev-python/hatchling: Keyword 1.17.0 alpha, #903715 (diff)
downloadgentoo-b03890e439529ef3bed2bb111f93687065dd54bb.tar.gz
gentoo-b03890e439529ef3bed2bb111f93687065dd54bb.tar.bz2
gentoo-b03890e439529ef3bed2bb111f93687065dd54bb.zip
mail-mta/exim-4.96-r3: add a bunch of upstream patches
Try to fix a bunch of crashes and problem with upstream fixes inspired by Debian packaging. Signed-off-by: Fabian Groffen <grobian@gentoo.org>
Diffstat (limited to 'mail-mta')
-rw-r--r--mail-mta/exim/exim-4.96-r3.ebuild (renamed from mail-mta/exim/exim-4.96-r2.ebuild)24
-rw-r--r--mail-mta/exim/files/exim-4.96-dane-dns_again.patch81
-rw-r--r--mail-mta/exim/files/exim-4.96-deamon-startup-fix.patch53
-rw-r--r--mail-mta/exim/files/exim-4.96-expansion-crash.patch69
-rw-r--r--mail-mta/exim/files/exim-4.96-openssl-bad-alpn.patch101
-rw-r--r--mail-mta/exim/files/exim-4.96-openssl-double-expansion.patch217
-rw-r--r--mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-lt-3.patch44
-rw-r--r--mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-setting.patch169
-rw-r--r--mail-mta/exim/files/exim-4.96-openssl-verify-ocsp.patch232
-rw-r--r--mail-mta/exim/files/exim-4.96-recursion-dns_again.patch57
-rw-r--r--mail-mta/exim/files/exim-4.96-regex-use-after-free.patch173
-rw-r--r--mail-mta/exim/files/exim-4.96-rewrite-malformed-addr-fix.patch42
-rw-r--r--mail-mta/exim/files/exim-4.96-spf-memory-error-fix.patch25
-rw-r--r--mail-mta/exim/files/exim-4.96-transport-crash.patch27
14 files changed, 1308 insertions, 6 deletions
diff --git a/mail-mta/exim/exim-4.96-r2.ebuild b/mail-mta/exim/exim-4.96-r3.ebuild
index e6c19640021e..646aa80b8ade 100644
--- a/mail-mta/exim/exim-4.96-r2.ebuild
+++ b/mail-mta/exim/exim-4.96-r3.ebuild
@@ -1,4 +1,4 @@
-# Copyright 1999-2022 Gentoo Authors
+# Copyright 1999-2023 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI="7"
@@ -116,7 +116,20 @@ src_prepare() {
eapply -p0 "${FILESDIR}"/exim-4.76-crosscompile.patch # 266591
eapply "${FILESDIR}"/exim-4.69-r1.27021.patch
eapply "${FILESDIR}"/exim-4.95-localscan_dlopen.patch
+ eapply "${FILESDIR}"/exim-4.96-rewrite-malformed-addr-fix.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-spf-memory-error-fix.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-regex-use-after-free.patch # upstr
eapply -p2 "${FILESDIR}"/exim-4.96-dmarc_use_after_free.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-deamon-startup-fix.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-openssl-verify-ocsp.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-openssl-double-expansion.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-recursion-dns_again.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-openssl-tls_eccurve-setting.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-openssl-tls_eccurve-lt-3.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-openssl-bad-alpn.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-dane-dns_again.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-expansion-crash.patch # upstr
+ eapply "${FILESDIR}"/exim-4.96-transport-crash.patch # upstr
# oddity, they disable berkdb as hack, and then throw an error when
# berkdb isn't enabled
@@ -125,11 +138,10 @@ src_prepare() {
-e 's/define DB void/define DONTMESS void/' \
src/auths/call_radius.c || die
- # for this reason we have a := dep on opendmarc, they changed their
- # API in a minor release
- if use dmarc && has_version ">=mail-filter/opendmarc-1.4" ; then
- eapply "${FILESDIR}"/exim-4.94-opendmarc-1.4.patch
- fi
+ # API changed from 1.3 to 1.4, upstream doesn't think 1.4 should be
+ # used, but 1.3 has a CVE and Gentoo (like most downstreams) only
+ # has 1.4 available
+ eapply "${FILESDIR}"/exim-4.94-opendmarc-1.4.patch
if use maildir ; then
eapply "${FILESDIR}"/exim-4.94-maildir.patch
diff --git a/mail-mta/exim/files/exim-4.96-dane-dns_again.patch b/mail-mta/exim/files/exim-4.96-dane-dns_again.patch
new file mode 100644
index 000000000000..9bd94f784594
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-dane-dns_again.patch
@@ -0,0 +1,81 @@
+modified for Gentoo, removed Changelog due to conflicts
+
+From 30520c8f87fcf660ed99a2344cae7f9787f7bc89 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 5 Jan 2023 18:39:51 +0000
+Subject: [PATCH 3/3] DANE: do not check dns_again_means_nonexist for TLSA
+ results of TRY_AGAIN
+
+---
+ doc/doc-docbook/spec.xfpt | 7 ++++++-
+ doc/ChangeLog | 4 ++++
+ src/dns.c | 35 ++++++++++++++++++++++-------------
+ 3 files changed, 32 insertions(+), 14 deletions(-)
+
+--- a/src/dns.c
++++ b/src/dns.c
+@@ -904,25 +904,34 @@ if (dnsa->answerlen < 0) switch (h_errno
+ DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n",
+ name, dns_text_type(type));
+
+ /* Cut this out for various test programs */
+ #ifndef STAND_ALONE
+- if (try_again_recursion)
++ /* Permitting dns_again_means nonexist for TLSA lookups breaks the
++ doewngrade resistance of dane, so avoid for those. */
++
++ if (type == T_TLSA)
++ rc = FAIL;
++ else
+ {
+- log_write(0, LOG_MAIN|LOG_PANIC,
+- "dns_again_means_nonexist recursion seen for %s (assuming nonexist)",
+- name);
+- return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH);
+- }
++ if (try_again_recursion)
++ {
++ log_write(0, LOG_MAIN|LOG_PANIC,
++ "dns_again_means_nonexist recursion seen for %s"
++ " (assuming nonexist)", name);
++ return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type),
++ DNS_NOMATCH);
++ }
+
+- try_again_recursion = TRUE;
+- save_domain = deliver_domain;
+- deliver_domain = string_copy(name); /* set $domain */
+- rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
+- &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
+- deliver_domain = save_domain;
+- try_again_recursion = FALSE;
++ try_again_recursion = TRUE;
++ save_domain = deliver_domain;
++ deliver_domain = string_copy(name); /* set $domain */
++ rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
++ &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
++ deliver_domain = save_domain;
++ try_again_recursion = FALSE;
++ }
+
+ if (rc != OK)
+ {
+ DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n");
+ return dns_fail_return(name, type, 0, DNS_AGAIN);
+--- a/doc/spec.txt
++++ b/doc/spec.txt
+@@ -14246,11 +14246,13 @@ dns_again_means_nonexist, it is treated
+ should be used with care. You can make it apply to reverse lookups by a setting
+ such as this:
+
+ dns_again_means_nonexist = *.in-addr.arpa
+
+-This option applies to all DNS lookups that Exim does. It also applies when the
++This option applies to all DNS lookups that Exim does, except for TLSA lookups
++(where knowing about such failures +is security-relevant). It also applies
++when the
+ gethostbyname() or getipnodebyname() functions give temporary errors, since
+ these are most likely to be caused by DNS lookup problems. The dnslookup router
+ has some options of its own for controlling what happens when lookups for MX or
+ SRV records give temporary errors. These more specific options are applied
+ after this global option.
diff --git a/mail-mta/exim/files/exim-4.96-deamon-startup-fix.patch b/mail-mta/exim/files/exim-4.96-deamon-startup-fix.patch
new file mode 100644
index 000000000000..8cf0cb703f1d
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-deamon-startup-fix.patch
@@ -0,0 +1,53 @@
+modified for Gentoo, removed Changelog to avoid conflicts
+
+From 221321d2c51b83d1feced80ecd6c2fe33ec5456c Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 3 Nov 2022 20:08:25 +0000
+Subject: [PATCH 1/2] Fix daemon startup. Bug 2930
+
+Broken-by: 7d5055276a
+---
+ doc/ChangeLog | 4 ++++
+ src/daemon.c | 8 ++++++--
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+--- a/src/daemon.c
++++ b/src/daemon.c
+@@ -1744,19 +1744,23 @@
+ {
+ /* If the parent process of this one has pid == 1, we are re-initializing the
+ daemon as the result of a SIGHUP. In this case, there is no need to do
+ anything, because the controlling terminal has long gone. Otherwise, fork, in
+ case current process is a process group leader (see 'man setsid' for an
+- explanation) before calling setsid(). */
++ explanation) before calling setsid().
++ All other forks want daemon_listen cleared. Rather than blow a register, jsut
++ restore it here. */
+
+ if (getppid() != 1)
+ {
++ BOOL daemon_listen = f.daemon_listen;
+ pid_t pid = exim_fork(US"daemon");
+ if (pid < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "fork() failed when starting daemon: %s", strerror(errno));
+ if (pid > 0) exit(EXIT_SUCCESS); /* in parent process, just exit */
+ (void)setsid(); /* release controlling terminal */
++ f.daemon_listen = daemon_listen;
+ }
+ }
+
+ /* We are now in the disconnected, daemon process (unless debugging). Set up
+ the listening sockets if required. */
+@@ -2090,11 +2094,11 @@
+ { /* found; append port to list */
+ for (p = i2->log; *p; ) p++; /* end of existing string */
+ if (*--p == '}') *p = '\0'; /* drop EOL */
+ while (isdigit(*--p)) ; /* char before port */
+
+- i2->log = *p == ':' /* no list yet? */
++ i2->log = *p == ':' /* no list yet? { */
+ ? string_sprintf("%.*s{%s,%d}",
+ (int)(p - i2->log + 1), i2->log, p+1, ipa->port)
+ : string_sprintf("%s,%d}", i2->log, ipa->port);
+ ipa->log = NULL;
+ break;
diff --git a/mail-mta/exim/files/exim-4.96-expansion-crash.patch b/mail-mta/exim/files/exim-4.96-expansion-crash.patch
new file mode 100644
index 000000000000..4b79784f9979
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-expansion-crash.patch
@@ -0,0 +1,69 @@
+modified for Gentoo, removed Changelog and tests
+
+From 70069b65a39a7ba73a36fbd95371ff03cde1eb23 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 2 Feb 2023 20:00:35 +0000
+Subject: [PATCH] Fix crash in expansions
+
+Broken-by: 1058096b8c53
+---
+ doc/ChangeLog | 4 ++++
+ src/expand.c | 9 +++++----
+ test/stderr/0630 | 1 +
+ 3 files changed, 10 insertions(+), 4 deletions(-)
+
+--- a/src/expand.c
++++ b/src/expand.c
+@@ -4652,11 +4652,11 @@ while (*s)
+ yield = string_catn(yield, value, len);
+
+ continue;
+ }
+
+- if (isdigit(*s))
++ if (isdigit(*s)) /* A $<n> variable */
+ {
+ int n;
+ s = read_cnumber(&n, s);
+ if (n >= 0 && n <= expand_nmax)
+ yield = string_catn(yield, expand_nstring[n], expand_nlength[n]);
+@@ -7060,10 +7060,11 @@ NOT_ITEM: ;
+ if (arg) *arg++ = '_'; /* Put back for error messages */
+ }
+
+ /* Deal specially with operators that might take a certificate variable
+ as we do not want to do the usual expansion. For most, expand the string.*/
++
+ switch(c)
+ {
+ #ifndef DISABLE_TLS
+ case EOP_MD5:
+ case EOP_SHA1:
+@@ -7107,11 +7108,11 @@ NOT_ITEM: ;
+
+ /* Otherwise, switch on the operator type. After handling go back
+ to the main loop top. */
+
+ {
+- int start = yield->ptr;
++ unsigned expansion_start = gstring_length(yield);
+ switch(c)
+ {
+ case EOP_BASE32:
+ {
+ uschar *t;
+@@ -8168,12 +8169,12 @@ NOT_ITEM: ;
+ goto EXPAND_FAILED;
+ } /* EOP_* switch */
+
+ DEBUG(D_expand)
+ {
+- const uschar * s = yield->s + start;
+- int i = yield->ptr - start;
++ const uschar * s = yield->s + expansion_start;
++ int i = gstring_length(yield) - expansion_start;
+ BOOL tainted = is_tainted(s);
+
+ DEBUG(D_noutf8)
+ {
+ debug_printf_indent("|-----op-res: %.*s\n", i, s);
diff --git a/mail-mta/exim/files/exim-4.96-openssl-bad-alpn.patch b/mail-mta/exim/files/exim-4.96-openssl-bad-alpn.patch
new file mode 100644
index 000000000000..f494fff85a09
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-openssl-bad-alpn.patch
@@ -0,0 +1,101 @@
+modified for Gentoo, removed tests
+
+From e1aca33756f73c22b00a98d40ce2be8ed94464b1 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 5 Jan 2023 13:03:37 +0000
+Subject: [PATCH 2/3] OpenSSL: log conns rejected for bad ALPN, with the
+ offered value
+
+Unfortunately, no way to do this under GnuTLS
+---
+ src/match.c | 1 +
+ src/tls-gnu.c | 9 ++++++++-
+ src/tls-openssl.c | 13 +++++++++++--
+ test/log/1190 | 2 ++
+ test/runtest | 3 +++
+ 5 files changed, 25 insertions(+), 3 deletions(-)
+
+diff --git a/src/match.c b/src/match.c
+index 91a49c0f0..07070362d 100644
+--- a/src/match.c
++++ b/src/match.c
+@@ -968,6 +968,7 @@ Arguments:
+ s string to search for
+ listptr ptr to ptr to colon separated list of patterns, or NULL
+ sep a separator value for the list (see string_nextinlist())
++ or zero for auto
+ anchorptr ptr to tree for named items, or NULL if no named items
+ cache_bits ptr to cache_bits for ditto, or NULL if not caching
+ type MCL_DOMAIN when matching a domain list
+diff --git a/src/tls-gnu.c b/src/tls-gnu.c
+index 729fb5879..b47fabf1d 100644
+--- a/src/tls-gnu.c
++++ b/src/tls-gnu.c
+@@ -1119,21 +1119,28 @@ switch (tls_id)
+ /* The format of "data" here doesn't seem to be documented, but appears
+ to be a 2-byte field with a (redundant, given the "size" arg) total length
+ then a sequence of one-byte size then string (not nul-term) names. The
+- latter is as described in OpenSSL documentation. */
++ latter is as described in OpenSSL documentation.
++ Note that we do not get called for a match_fail, making it hard to log
++ a single bad ALPN being offered (the common case). */
++ {
++ gstring * g = NULL;
+
+ DEBUG(D_tls) debug_printf("Seen ALPN extension from client (s=%u):", size);
+ for (const uschar * s = data+2; s-data < size-1; s += *s + 1)
+ {
+ server_seen_alpn++;
++ g = string_append_listele_n(g, ':', s+1, *s);
+ DEBUG(D_tls) debug_printf(" '%.*s'", (int)*s, s+1);
+ }
+ DEBUG(D_tls) debug_printf("\n");
+ if (server_seen_alpn > 1)
+ {
++ log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g));
+ DEBUG(D_tls) debug_printf("TLS: too many ALPNs presented in handshake\n");
+ return GNUTLS_E_NO_APPLICATION_PROTOCOL;
+ }
+ break;
++ }
+ #endif
+ }
+ return 0;
+diff --git a/src/tls-openssl.c b/src/tls-openssl.c
+index e063d29bd..513ba0d3a 100644
+--- a/src/tls-openssl.c
++++ b/src/tls-openssl.c
+@@ -2324,6 +2324,8 @@ static int
+ tls_server_alpn_cb(SSL *ssl, const uschar ** out, uschar * outlen,
+ const uschar * in, unsigned int inlen, void * arg)
+ {
++gstring * g = NULL;
++
+ server_seen_alpn = TRUE;
+ DEBUG(D_tls)
+ {
+@@ -2354,12 +2356,19 @@ if ( inlen > 1 /* at least one name */
+ }
+ }
+
+-/* More than one name from clilent, or name did not match our list. */
++/* More than one name from client, or name did not match our list. */
+
+ /* This will be fatal to the TLS conn; would be nice to kill TCP also.
+ Maybe as an option in future; for now leave control to the config (must-tls). */
+
+-DEBUG(D_tls) debug_printf("TLS ALPN rejected\n");
++for (int pos = 0, siz; pos < inlen; pos += siz+1)
++ {
++ siz = in[pos];
++ if (pos + 1 + siz > inlen) siz = inlen - pos - 1;
++ g = string_append_listele_n(g, ':', in + pos + 1, siz);
++ }
++log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g));
++gstring_release_unused(g);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ #endif /* EXIM_HAVE_ALPN */
+--
+2.39.0
+
diff --git a/mail-mta/exim/files/exim-4.96-openssl-double-expansion.patch b/mail-mta/exim/files/exim-4.96-openssl-double-expansion.patch
new file mode 100644
index 000000000000..09e4f11ef20e
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-openssl-double-expansion.patch
@@ -0,0 +1,217 @@
+From 62b97c2ecf148ee86053d82e5509e4c3a5a20054 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Sat, 29 Oct 2022 22:33:43 +0100
+Subject: [PATCH 2/2] OpenSSL: fix double-expansion of tls_verify_certificates
+
+---
+ src/tls-openssl.c | 66 +++++++++++++++++++++----------------------
+ 1 file changed, 33 insertions(+), 33 deletions(-)
+
+diff --git a/src/tls-openssl.c b/src/tls-openssl.c
+index fdf0d92b2..2e09882d2 100644
+--- a/src/tls-openssl.c
++++ b/src/tls-openssl.c
+@@ -435,15 +435,15 @@ typedef struct exim_openssl_state {
+ /* should figure out a cleanup of API to handle state preserved per
+ implementation, for various reasons, which can be void * in the APIs.
+ For now, we hack around it. */
+ exim_openssl_state_st *client_static_state = NULL; /*XXX should not use static; multiple concurrent clients! */
+ exim_openssl_state_st state_server = {.is_server = TRUE};
+
+ static int
+-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
++setup_certs(SSL_CTX * sctx, uschar ** certs, uschar * crl, host_item * host,
+ uschar ** errstr );
+
+ /* Callbacks */
+ #ifndef DISABLE_OCSP
+ static int tls_server_stapling_cb(SSL *s, void *arg);
+ static void x509_stack_dump_cert_s_names(const STACK_OF(X509) * sk);
+ static void x509_store_dump_cert_s_names(X509_STORE * store);
+@@ -1762,18 +1762,18 @@ if ( opt_set_and_noexpand(tls_verify_certificates)
+ {
+ /* Watch the default dir also as they are always included */
+
+ if ( tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
+ && tls_set_watch(tls_verify_certificates, FALSE)
+ && tls_set_watch(tls_crl, FALSE))
+ {
++ uschar * v_certs = tls_verify_certificates;
+ DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
+
+- if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr)
+- == OK)
++ if (setup_certs(ctx, &v_certs, tls_crl, NULL, &dummy_errstr) == OK)
+ state_server.lib_state.cabundle = TRUE;
+
+ /* If we can, preload the server-side cert, key and ocsp */
+
+ if ( opt_set_and_noexpand(tls_certificate)
+ # ifndef DISABLE_OCSP
+ && opt_unset_or_noexpand(tls_ocsp_file)
+@@ -1897,18 +1897,19 @@ if ( opt_set_and_noexpand(ob->tls_verify_certificates)
+ {
+ if ( !watch
+ || tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
+ && tls_set_watch(ob->tls_verify_certificates, FALSE)
+ && tls_set_watch(ob->tls_crl, FALSE)
+ )
+ {
++ uschar * v_certs = ob->tls_verify_certificates;
+ DEBUG(D_tls)
+ debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
+
+- if (setup_certs(ctx, ob->tls_verify_certificates,
++ if (setup_certs(ctx, &v_certs,
+ ob->tls_crl, dummy_host, &dummy_errstr) == OK)
+ ob->tls_preload.cabundle = TRUE;
+ }
+ }
+ else
+ DEBUG(D_tls)
+ debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name);
+@@ -2238,22 +2239,20 @@ if (state->u_ocsp.server.file)
+ {
+ SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
+ SSL_CTX_set_tlsext_status_arg(server_sni, state);
+ }
+ #endif
+
+ {
+- uschar * expcerts;
+- if ( !expand_check(tls_verify_certificates, US"tls_verify_certificates",
+- &expcerts, &dummy_errstr)
+- || (rc = setup_certs(server_sni, expcerts, tls_crl, NULL,
++ uschar * v_certs = tls_verify_certificates;
++ if ((rc = setup_certs(server_sni, &v_certs, tls_crl, NULL,
+ &dummy_errstr)) != OK)
+ goto bad;
+
+- if (expcerts && *expcerts)
++ if (v_certs && *v_certs)
+ setup_cert_verify(server_sni, FALSE, verify_callback_server);
+ }
+
+ /* do this after setup_certs, because this can require the certs for verifying
+ OCSP information. */
+ if ((rc = tls_expand_session_files(server_sni, state, &dummy_errstr)) != OK)
+ goto bad;
+@@ -3017,32 +3016,33 @@ return TRUE;
+
+
+ /* Called by both client and server startup; on the server possibly
+ repeated after a Server Name Indication.
+
+ Arguments:
+ sctx SSL_CTX* to initialise
+- certs certs file, expanded
++ certs certs file, returned expanded
+ crl CRL file or NULL
+ host NULL in a server; the remote host in a client
+ errstr error string pointer
+
+ Returns: OK/DEFER/FAIL
+ */
+
+ static int
+-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
++setup_certs(SSL_CTX * sctx, uschar ** certsp, uschar * crl, host_item * host,
+ uschar ** errstr)
+ {
+-uschar *expcerts, *expcrl;
++uschar * expcerts, * expcrl;
+
+-if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr))
++if (!expand_check(*certsp, US"tls_verify_certificates", &expcerts, errstr))
+ return DEFER;
+ DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
+
++*certsp = expcerts;
+ if (expcerts && *expcerts)
+ {
+ /* Tell the library to use its compiled-in location for the system default
+ CA bundle. Then add the ones specified in the config, if any. */
+
+ if (!SSL_CTX_set_default_verify_paths(sctx))
+ return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL, errstr);
+@@ -3330,28 +3330,28 @@ if (verify_check_host(&tls_verify_hosts) == OK)
+ server_verify_optional = FALSE;
+ else if (verify_check_host(&tls_try_verify_hosts) == OK)
+ server_verify_optional = TRUE;
+ else
+ goto skip_certs;
+
+ {
+- uschar * expcerts;
+- if (!expand_check(tls_verify_certificates, US"tls_verify_certificates",
+- &expcerts, errstr))
+- return DEFER;
+- DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
++ uschar * v_certs = tls_verify_certificates;
+
+ if (state_server.lib_state.cabundle)
+- { DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); }
++ {
++ DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n");
++ setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
++ }
+ else
+- if ((rc = setup_certs(ctx, expcerts, tls_crl, NULL, errstr)) != OK)
++ {
++ if ((rc = setup_certs(ctx, &v_certs, tls_crl, NULL, errstr)) != OK)
+ return rc;
+-
+- if (expcerts && *expcerts)
+- setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
++ if (v_certs && *v_certs)
++ setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
++ }
+ }
+ skip_certs: ;
+
+ #ifndef DISABLE_TLS_RESUME
+ # if OPENSSL_VERSION_NUMBER < 0x30000000L
+ SSL_CTX_set_tlsext_ticket_key_cb(ctx, ticket_key_callback);
+ /* despite working, appears to always return failure, so ignoring */
+@@ -3606,28 +3606,28 @@ if ( ( ( !ob->tls_verify_hosts || !ob->tls_verify_hosts
+ client_verify_optional = FALSE;
+ else if (verify_check_given_host(CUSS &ob->tls_try_verify_hosts, host) == OK)
+ client_verify_optional = TRUE;
+ else
+ return OK;
+
+ {
+- uschar * expcerts;
+- if (!expand_check(ob->tls_verify_certificates, US"tls_verify_certificates",
+- &expcerts, errstr))
+- return DEFER;
+- DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
++ uschar * v_certs = ob->tls_verify_certificates;
+
+ if (state->lib_state.cabundle)
+- { DEBUG(D_tls) debug_printf("TLS: CA bundle was preloaded\n"); }
++ {
++ DEBUG(D_tls) debug_printf("TLS: CA bundle for tpt was preloaded\n");
++ setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
++ }
+ else
+- if ((rc = setup_certs(ctx, expcerts, ob->tls_crl, host, errstr)) != OK)
++ {
++ if ((rc = setup_certs(ctx, &v_certs, ob->tls_crl, host, errstr)) != OK)
+ return rc;
+-
+- if (expcerts && *expcerts)
+- setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
++ if (v_certs && *v_certs)
++ setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
++ }
+ }
+
+ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
+ {
+ state->verify_cert_hostnames =
+ #ifdef SUPPORT_I18N
+ string_domain_utf8_to_alabel(host->certname, NULL);
+--
+2.35.1
+
diff --git a/mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-lt-3.patch b/mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-lt-3.patch
new file mode 100644
index 000000000000..37d1d445cb0a
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-lt-3.patch
@@ -0,0 +1,44 @@
+modified for Gentoo, removed tests due to conflicts
+
+From 7fa5764c203f2f4a900898a79ed02d674075313f Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Mon, 2 Jan 2023 15:04:14 +0000
+Subject: [PATCH 1/3] OpenSSL: Fix tls_eccurve on earlier versions than 3.0.0.
+ Bug 2954
+
+Broken-by: ca4014de81e6
+---
+ src/tls-openssl.c | 7 ++++---
+ test/log/2149 | 28 ++++++++++++++--------------
+ test/runtest | 3 +++
+ test/scripts/2100-OpenSSL/2149 | 22 ++++++++++++----------
+ 4 files changed, 33 insertions(+), 27 deletions(-)
+
+diff --git a/src/tls-openssl.c b/src/tls-openssl.c
+index 4d0f99ea9..e063d29bd 100644
+--- a/src/tls-openssl.c
++++ b/src/tls-openssl.c
+@@ -786,8 +786,9 @@ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef
+ # endif
+ )
+ {
+- tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
+- NULL, NULL, errstr);
++ uschar * s = string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve);
++ DEBUG(D_tls) debug_printf("TLS error '%s'\n", s);
++ if (errstr) *errstr = s;
+ return FALSE;
+ }
+
+@@ -803,7 +804,7 @@ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef
+ /* The "tmp" in the name here refers to setting a temporary key
+ not to the stability of the interface. */
+
+- if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
++ if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh)) == 0)
+ tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr);
+ else
+ DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve);
+--
+2.39.0
+
diff --git a/mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-setting.patch b/mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-setting.patch
new file mode 100644
index 000000000000..6ccfbca9a985
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-openssl-tls_eccurve-setting.patch
@@ -0,0 +1,169 @@
+modified for Gentoo, dropped Changelog and test due to conflicts
+
+From ca4014de81e6aa367aa0a54c49b4c3d4b137814c Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Sun, 1 Jan 2023 12:18:38 +0000
+Subject: [PATCH] OpenSSL: fix tls_eccurve setting explicit curve/group. Bug
+ 2954
+
+---
+ doc/ChangeLog | 4 +++
+ src/tls-openssl.c | 39 ++++++++++++++----------
+ test/confs/2148 | 54 ++++++++++++++++++++++++++++++++++
+ test/confs/2149 | 39 +++++++++++++-----------
+ test/log/2148 | 48 ++++++++++++++++++++++++++++++
+ test/log/2149 | 39 ++++++++++++------------
+ test/paniclog/{2149 => 2148} | 0
+ test/scripts/2100-OpenSSL/2148 | 50 +++++++++++++++++++++++++++++++
+ test/scripts/2100-OpenSSL/2149 | 50 ++++++++++++++++---------------
+ test/stderr/2148 | 5 ++++
+ test/stderr/2149 | 3 --
+ 11 files changed, 250 insertions(+), 81 deletions(-)
+ create mode 100644 test/confs/2148
+ create mode 100644 test/log/2148
+ rename test/paniclog/{2149 => 2148} (100%)
+ create mode 100644 test/scripts/2100-OpenSSL/2148
+ create mode 100644 test/stderr/2148
+
+--- a/src/tls-openssl.c
++++ b/src/tls-openssl.c
+@@ -657,16 +657,16 @@ if (dh_bitsize <= tls_dh_max_bits)
+ /* EVP_PKEY_free(pkey); crashes */
+ #endif
+ }
+ else
+ DEBUG(D_tls)
+- debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
++ debug_printf(" Diffie-Hellman initialized from %s with %d-bit prime\n",
+ dhexpanded ? dhexpanded : US"default", dh_bitsize);
+ }
+ else
+ DEBUG(D_tls)
+- debug_printf("dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
++ debug_printf(" dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
+ dhexpanded ? dhexpanded : US"default", dh_bitsize, tls_dh_max_bits);
+
+ #if OPENSSL_VERSION_NUMBER < 0x30000000L
+ DH_free(dh);
+ #endif
+@@ -712,23 +712,31 @@ init_ecdh(SSL_CTX * sctx, uschar ** errs
+ #ifdef OPENSSL_NO_ECDH
+ return TRUE;
+ #else
+
+ uschar * exp_curve;
+-int nid;
+-BOOL rv;
++int nid, rc;
+
+ # ifndef EXIM_HAVE_ECDH
+ DEBUG(D_tls)
+- debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
++ debug_printf(" No OpenSSL API to define ECDH parameters, skipping\n");
+ return TRUE;
+ # else
+
+ if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
+ return FALSE;
++
++/* Is the option deliberately empty? */
++
+ if (!exp_curve || !*exp_curve)
++ {
++#if OPENSSL_VERSION_NUMBER >= 0x10002000L
++ DEBUG(D_tls) debug_printf( " ECDH OpenSSL 1.0.2+: clearing curves list\n");
++ (void) SSL_CTX_set1_curves(sctx, &nid, 0);
++#endif
+ return TRUE;
++ }
+
+ /* "auto" needs to be handled carefully.
+ * OpenSSL < 1.0.2: we do not select anything, but fallback to prime256v1
+ * OpenSSL < 1.1.0: we have to call SSL_CTX_set_ecdh_auto
+ * (openssl/ssl.h defines SSL_CTRL_SET_ECDH_AUTO)
+@@ -737,27 +745,26 @@ if (!exp_curve || !*exp_curve)
+ */
+ if (Ustrcmp(exp_curve, "auto") == 0)
+ {
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
+ DEBUG(D_tls) debug_printf(
+- "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
++ " ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
+ exp_curve = US"prime256v1";
+ #else
+ # if defined SSL_CTRL_SET_ECDH_AUTO
+ DEBUG(D_tls) debug_printf(
+- "ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
++ " ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
+ SSL_CTX_set_ecdh_auto(sctx, 1);
+ return TRUE;
+ # else
+ DEBUG(D_tls) debug_printf(
+- "ECDH OpenSSL 1.1.0+: temp key parameter settings: default selection\n");
++ " ECDH OpenSSL 1.1.0+: temp key parameter settings: library default selection\n");
+ return TRUE;
+ # endif
+ #endif
+ }
+
+-DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
+ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef
+ # ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID
+ && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef
+ # endif
+ )
+@@ -777,27 +784,27 @@ if ( (nid = OBJ_sn2nid (CCS exp_c
+ }
+
+ /* The "tmp" in the name here refers to setting a temporary key
+ not to the stability of the interface. */
+
+- if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
++ if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
+ tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr);
+ else
+- DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
++ DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve);
+ EC_KEY_free(ecdh);
+ }
+
+ #else /* v 3.0.0 + */
+
+-if ((rv = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
++if ((rc = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
+ tls_error(string_sprintf("Error enabling '%s' group", exp_curve), NULL, NULL, errstr);
+ else
+- DEBUG(D_tls) debug_printf("ECDH: enabled '%s' group\n", exp_curve);
++ DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' group\n", exp_curve);
+
+ #endif
+
+-return !rv;
++return !!rc;
+
+ # endif /*EXIM_HAVE_ECDH*/
+ #endif /*OPENSSL_NO_ECDH*/
+ }
+
+@@ -1719,19 +1726,19 @@ state_server.lib_state.lib_ctx = ctx;
+
+ /* Preload DH params and EC curve */
+
+ if (opt_unset_or_noexpand(tls_dhparam))
+ {
+- DEBUG(D_tls) debug_printf("TLS: preloading DH params for server\n");
++ DEBUG(D_tls) debug_printf("TLS: preloading DH params '%s' for server\n", tls_dhparam);
+ if (init_dh(ctx, tls_dhparam, &dummy_errstr))
+ state_server.lib_state.dh = TRUE;
+ }
+ else
+ DEBUG(D_tls) debug_printf("TLS: not preloading DH params for server\n");
+ if (opt_unset_or_noexpand(tls_eccurve))
+ {
+- DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for server\n");
++ DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve '%s' for server\n", tls_eccurve);
+ if (init_ecdh(ctx, &dummy_errstr))
+ state_server.lib_state.ecdh = TRUE;
+ }
+ else
+ DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n");
diff --git a/mail-mta/exim/files/exim-4.96-openssl-verify-ocsp.patch b/mail-mta/exim/files/exim-4.96-openssl-verify-ocsp.patch
new file mode 100644
index 000000000000..2e21065fb1d6
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-openssl-verify-ocsp.patch
@@ -0,0 +1,232 @@
+From 7f65a63b60c6ea86db683ac00e221939f3bb1d47 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Tue, 25 Oct 2022 21:26:30 +0100
+Subject: [PATCH 1/2] OpenSSL: when preloading creds do the server certs before
+ the OCSP proofs so that the latter can ve verified before loading
+
+---
+ src/tls-openssl.c | 113 ++++++++++++++++++++++--------------------
+ 1 file changed, 58 insertions(+), 55 deletions(-)
+
+diff --git a/src/tls-openssl.c b/src/tls-openssl.c
+index 68ad6f15b..fdf0d92b2 100644
+--- a/src/tls-openssl.c
++++ b/src/tls-openssl.c
+@@ -441,14 +441,16 @@ exim_openssl_state_st state_server = {.is_server = TRUE};
+ static int
+ setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
+ uschar ** errstr );
+
+ /* Callbacks */
+ #ifndef DISABLE_OCSP
+ static int tls_server_stapling_cb(SSL *s, void *arg);
++static void x509_stack_dump_cert_s_names(const STACK_OF(X509) * sk);
++static void x509_store_dump_cert_s_names(X509_STORE * store);
+ #endif
+
+
+
+ /* Daemon-called, before every connection, key create/rotate */
+ #ifndef DISABLE_TLS_RESUME
+ static void tk_init(void);
+@@ -1307,15 +1309,14 @@ ocsp_load_response(exim_openssl_state_st * state, const uschar * filename,
+ {
+ BIO * bio;
+ OCSP_RESPONSE * resp;
+ OCSP_BASICRESP * basic_response;
+ OCSP_SINGLERESP * single_response;
+ ASN1_GENERALIZEDTIME * rev, * thisupd, * nextupd;
+ STACK_OF(X509) * sk;
+-unsigned long verify_flags;
+ int status, reason, i;
+
+ DEBUG(D_tls)
+ debug_printf("tls_ocsp_file (%s) '%s'\n", is_pem ? "PEM" : "DER", filename);
+
+ if (!filename || !*filename) return;
+
+@@ -1372,28 +1373,28 @@ if ((status = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+ if (!(basic_response = OCSP_response_get1_basic(resp)))
+ {
+ DEBUG(D_tls)
+ debug_printf("OCSP response parse error: unable to extract basic response.\n");
+ goto bad;
+ }
+
+-sk = state->verify_stack;
+-verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */
++sk = state->verify_stack; /* set by setup_certs() / chain_from_pem_file() */
+
+ /* May need to expose ability to adjust those flags?
+ OCSP_NOSIGS OCSP_NOVERIFY OCSP_NOCHAIN OCSP_NOCHECKS OCSP_NOEXPLICIT
+ OCSP_TRUSTOTHER OCSP_NOINTERN */
+
+-/* This does a full verify on the OCSP proof before we load it for serving
+-up; possibly overkill - just date-checks might be nice enough.
++/* This does a partial verify (only the signer link, not the whole chain-to-CA)
++on the OCSP proof before we load it for serving up; possibly overkill -
++just date-checks might be nice enough.
+
+ OCSP_basic_verify takes a "store" arg, but does not
+-use it for the chain verification, which is all we do
+-when OCSP_NOVERIFY is set. The content from the wire
+-"basic_response" and a cert-stack "sk" are all that is used.
++use it for the chain verification, when OCSP_NOVERIFY is set.
++The content from the wire "basic_response" and a cert-stack "sk" are all
++that is used.
+
+ We have a stack, loaded in setup_certs() if tls_verify_certificates
+ was a file (not a directory, or "system"). It is unfortunate we
+ cannot used the connection context store, as that would neatly
+ handle the "system" case too, but there seems to be no library
+ function for getting a stack from a store.
+ [ In OpenSSL 1.1 - ? X509_STORE_CTX_get0_chain(ctx) ? ]
+@@ -1402,15 +1403,15 @@ SNI handling.
+
+ Separately we might try to replace using OCSP_basic_verify() - which seems to not
+ be a public interface into the OpenSSL library (there's no manual entry) -
+ But what with? We also use OCSP_basic_verify in the client stapling callback.
+ And there we NEED it; we must verify that status... unless the
+ library does it for us anyway? */
+
+-if ((i = OCSP_basic_verify(basic_response, sk, NULL, verify_flags)) < 0)
++if ((i = OCSP_basic_verify(basic_response, sk, NULL, OCSP_NOVERIFY)) < 0)
+ {
+ DEBUG(D_tls)
+ {
+ ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+ debug_printf("OCSP response verify failure: %s\n", US ssl_errstring);
+ }
+ goto bad;
+@@ -1747,61 +1748,18 @@ if (opt_unset_or_noexpand(tls_eccurve))
+ if (init_ecdh(ctx, &dummy_errstr))
+ state_server.lib_state.ecdh = TRUE;
+ }
+ else
+ DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n");
+
+ #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
+-/* If we can, preload the server-side cert, key and ocsp */
+-
+-if ( opt_set_and_noexpand(tls_certificate)
+-# ifndef DISABLE_OCSP
+- && opt_unset_or_noexpand(tls_ocsp_file)
+-#endif
+- && opt_unset_or_noexpand(tls_privatekey))
+- {
+- /* Set watches on the filenames. The implementation does de-duplication
+- so we can just blindly do them all. */
+-
+- if ( tls_set_watch(tls_certificate, TRUE)
+-# ifndef DISABLE_OCSP
+- && tls_set_watch(tls_ocsp_file, TRUE)
+-#endif
+- && tls_set_watch(tls_privatekey, TRUE))
+- {
+- state_server.certificate = tls_certificate;
+- state_server.privatekey = tls_privatekey;
+-#ifndef DISABLE_OCSP
+- state_server.u_ocsp.server.file = tls_ocsp_file;
+-#endif
+-
+- DEBUG(D_tls) debug_printf("TLS: preloading server certs\n");
+- if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
+- state_server.lib_state.conn_certs = TRUE;
+- }
+- }
+-else if ( !tls_certificate && !tls_privatekey
+-# ifndef DISABLE_OCSP
+- && !tls_ocsp_file
+-#endif
+- )
+- { /* Generate & preload a selfsigned cert. No files to watch. */
+- if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
+- {
+- state_server.lib_state.conn_certs = TRUE;
+- lifetime = f.running_in_test_harness ? 2 : 60 * 60; /* 1 hour */
+- }
+- }
+-else
+- DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");
+-
+-
+ /* If we can, preload the Authorities for checking client certs against.
+ Actual choice to do verify is made (tls_{,try_}verify_hosts)
+-at TLS conn startup */
++at TLS conn startup.
++Do this before the server ocsp so that its info can verify the ocsp. */
+
+ if ( opt_set_and_noexpand(tls_verify_certificates)
+ && opt_unset_or_noexpand(tls_crl))
+ {
+ /* Watch the default dir also as they are always included */
+
+ if ( tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
+@@ -1809,18 +1767,63 @@ if ( opt_set_and_noexpand(tls_verify_certificates)
+ && tls_set_watch(tls_crl, FALSE))
+ {
+ DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
+
+ if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr)
+ == OK)
+ state_server.lib_state.cabundle = TRUE;
+- }
++
++ /* If we can, preload the server-side cert, key and ocsp */
++
++ if ( opt_set_and_noexpand(tls_certificate)
++# ifndef DISABLE_OCSP
++ && opt_unset_or_noexpand(tls_ocsp_file)
++# endif
++ && opt_unset_or_noexpand(tls_privatekey))
++ {
++ /* Set watches on the filenames. The implementation does de-duplication
++ so we can just blindly do them all. */
++
++ if ( tls_set_watch(tls_certificate, TRUE)
++# ifndef DISABLE_OCSP
++ && tls_set_watch(tls_ocsp_file, TRUE)
++# endif
++ && tls_set_watch(tls_privatekey, TRUE))
++ {
++ state_server.certificate = tls_certificate;
++ state_server.privatekey = tls_privatekey;
++#ifndef DISABLE_OCSP
++ state_server.u_ocsp.server.file = tls_ocsp_file;
++# endif
++
++ DEBUG(D_tls) debug_printf("TLS: preloading server certs\n");
++ if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
++ state_server.lib_state.conn_certs = TRUE;
++ }
++ }
++ else if ( !tls_certificate && !tls_privatekey
++# ifndef DISABLE_OCSP
++ && !tls_ocsp_file
++# endif
++ )
++ { /* Generate & preload a selfsigned cert. No files to watch. */
++ if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
++ {
++ state_server.lib_state.conn_certs = TRUE;
++ lifetime = f.running_in_test_harness ? 2 : 60 * 60; /* 1 hour */
++ }
++ }
++ else
++ DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");
++ }
+ }
+ else
+ DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n");
++
++
+ #endif /* EXIM_HAVE_INOTIFY */
+
+
+ /* If we can, preload the ciphers control string */
+
+ if (opt_set_and_noexpand(tls_require_ciphers))
+ {
+--
+2.35.1
+
diff --git a/mail-mta/exim/files/exim-4.96-recursion-dns_again.patch b/mail-mta/exim/files/exim-4.96-recursion-dns_again.patch
new file mode 100644
index 000000000000..6ac0e81c9551
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-recursion-dns_again.patch
@@ -0,0 +1,57 @@
+modified for Gentoo, removed Changelog due to conflicts
+
+From 1d38781da934809e6ce0b8c3718c4b3bccdfe1d2 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Wed, 28 Dec 2022 19:39:06 +0000
+Subject: [PATCH] Fix recursion on dns_again_means_nonexist. Bug 2911
+
+---
+ doc/ChangeLog | 8 +++++
+ src/dns.c | 12 ++++++++
+ test/confs/2202 | 18 +++++++++--
+ test/scripts/2200-dnsdb/2202 | 8 +++++
+ test/stderr/2202 | 58 +++++++++++++++++++++++++++++++++++-
+ test/stdout/2202 | 8 +++++
+ 6 files changed, 108 insertions(+), 4 deletions(-)
+
+--- a/src/dns.c
++++ b/src/dns.c
+@@ -799,10 +799,11 @@ int
+ dns_basic_lookup(dns_answer * dnsa, const uschar * name, int type)
+ {
+ int rc;
+ #ifndef STAND_ALONE
+ const uschar * save_domain;
++static BOOL try_again_recursion = FALSE;
+ #endif
+
+ /* DNS lookup failures of any kind are cached in a tree. This is mainly so that
+ a timeout on one domain doesn't happen time and time again for messages that
+ have many addresses in the same domain. We rely on the resolver and name server
+@@ -903,15 +904,26 @@ if (dnsa->answerlen < 0) switch (h_errno
+ DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n",
+ name, dns_text_type(type));
+
+ /* Cut this out for various test programs */
+ #ifndef STAND_ALONE
++ if (try_again_recursion)
++ {
++ log_write(0, LOG_MAIN|LOG_PANIC,
++ "dns_again_means_nonexist recursion seen for %s (assuming nonexist)",
++ name);
++ return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH);
++ }
++
++ try_again_recursion = TRUE;
+ save_domain = deliver_domain;
+ deliver_domain = string_copy(name); /* set $domain */
+ rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
+ &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
+ deliver_domain = save_domain;
++ try_again_recursion = FALSE;
++
+ if (rc != OK)
+ {
+ DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n");
+ return dns_fail_return(name, type, 0, DNS_AGAIN);
+ }
diff --git a/mail-mta/exim/files/exim-4.96-regex-use-after-free.patch b/mail-mta/exim/files/exim-4.96-regex-use-after-free.patch
new file mode 100644
index 000000000000..1ec6d9a4abd6
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-regex-use-after-free.patch
@@ -0,0 +1,173 @@
+modified for Gentoo, removed Changelog due to conflicts
+
+From 4e9ed49f8f12eb331b29bd5b6dc3693c520fddc2 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Wed, 31 Aug 2022 15:37:40 +0100
+Subject: [PATCH] Fix $regex<n> use-after-free. Bug 2915
+
+---
+ doc/ChangeLog | 8 +++++++-
+ src/exim.c | 4 +---
+ src/expand.c | 2 +-
+ src/functions.h | 1 +
+ src/globals.c | 2 +-
+ src/regex.c | 29 ++++++++++++++++++-----------
+ src/smtp_in.c | 2 ++
+ test/confs/4002 | 10 ++++++++++
+ test/mail/4002.userx | 7 +++++++
+ test/scripts/4000-scanning/4002 | 7 +++++++
+ 10 files changed, 55 insertions(+), 17 deletions(-)
+
+--- a/src/exim.c
++++ b/src/exim.c
+@@ -1999,12 +1999,10 @@
+
+ regex_whitelisted_macro =
+ regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE);
+ #endif
+
+-for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
+-
+ /* If the program is called as "mailq" treat it as equivalent to "exim -bp";
+ this seems to be a generally accepted convention, since one finds symbolic
+ links called "mailq" in standard OS configurations. */
+
+ if ((namelen == 5 && Ustrcmp(argv[0], "mailq") == 0) ||
+@@ -6082,11 +6080,11 @@
+ callout_address = NULL;
+ sending_ip_address = NULL;
+ deliver_localpart_data = deliver_domain_data =
+ recipient_data = sender_data = NULL;
+ acl_var_m = NULL;
+- for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
++ regex_vars_clear();
+
+ store_reset(reset_point);
+ }
+
+ exim_exit(EXIT_SUCCESS); /* Never returns */
+--- a/src/expand.c
++++ b/src/expand.c
+@@ -1871,11 +1871,11 @@
+ {
+ tree_node * node = tree_search(router_var, name + 2);
+ return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
+ }
+
+-/* Handle $auth<n> variables. */
++/* Handle $auth<n>, $regex<n> variables. */
+
+ if (Ustrncmp(name, "auth", 4) == 0)
+ {
+ uschar *endptr;
+ int n = Ustrtoul(name + 4, &endptr, 10);
+--- a/src/functions.h
++++ b/src/functions.h
+@@ -436,10 +436,11 @@
+ extern int regex(const uschar **);
+ #endif
+ extern BOOL regex_match(const pcre2_code *, const uschar *, int, uschar **);
+ extern BOOL regex_match_and_setup(const pcre2_code *, const uschar *, int, int);
+ extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL);
++extern void regex_vars_clear(void);
+ extern void retry_add_item(address_item *, uschar *, int);
+ extern BOOL retry_check_address(const uschar *, host_item *, uschar *, BOOL,
+ uschar **, uschar **);
+ extern retry_config *retry_find_config(const uschar *, const uschar *, int, int);
+ extern BOOL retry_ultimate_address_timeout(uschar *, const uschar *,
+--- a/src/globals.c
++++ b/src/globals.c
+@@ -1313,11 +1313,11 @@
+ #ifndef DISABLE_PIPE_CONNECT
+ const pcre2_code *regex_EARLY_PIPE = NULL;
+ #endif
+ const pcre2_code *regex_ismsgid = NULL;
+ const pcre2_code *regex_smtp_code = NULL;
+-const uschar *regex_vars[REGEX_VARS];
++const uschar *regex_vars[REGEX_VARS] = { 0 };;
+ #ifdef WHITELIST_D_MACROS
+ const pcre2_code *regex_whitelisted_macro = NULL;
+ #endif
+ #ifdef WITH_CONTENT_SCAN
+ uschar *regex_match_string = NULL;
+--- a/src/regex.c
++++ b/src/regex.c
+@@ -94,22 +94,32 @@
+ }
+ pcre2_match_data_free(md);
+ return FAIL;
+ }
+
++
++/* reset expansion variables */
++void
++regex_vars_clear(void)
++{
++regex_match_string = NULL;
++for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
++}
++
++
++
+ int
+-regex(const uschar **listptr)
++regex(const uschar ** listptr)
+ {
+ unsigned long mbox_size;
+-FILE *mbox_file;
+-pcre_list *re_list_head;
+-uschar *linebuffer;
++FILE * mbox_file;
++pcre_list * re_list_head;
++uschar * linebuffer;
+ long f_pos = 0;
+ int ret = FAIL;
+
+-/* reset expansion variable */
+-regex_match_string = NULL;
++regex_vars_clear();
+
+ if (!mime_stream) /* We are in the DATA ACL */
+ {
+ if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL)))
+ { /* error while spooling */
+@@ -167,18 +177,17 @@
+
+
+ int
+ mime_regex(const uschar **listptr)
+ {
+-pcre_list *re_list_head = NULL;
+-FILE *f;
+-uschar *mime_subject = NULL;
++pcre_list * re_list_head = NULL;
++FILE * f;
++uschar * mime_subject = NULL;
+ int mime_subject_len = 0;
+ int ret;
+
+-/* reset expansion variable */
+-regex_match_string = NULL;
++regex_vars_clear();
+
+ /* precompile our regexes */
+ if (!(re_list_head = compile(*listptr)))
+ return FAIL; /* no regexes -> nothing to do */
+
+--- a/src/smtp_in.c
++++ b/src/smtp_in.c
+@@ -2155,12 +2155,14 @@
+ prdr_requested = FALSE;
+ #endif
+ #ifdef SUPPORT_I18N
+ message_smtputf8 = FALSE;
+ #endif
++regex_vars_clear();
+ body_linecount = body_zerocount = 0;
+
++lookup_value = NULL; /* Can be set by ACL */
+ sender_rate = sender_rate_limit = sender_rate_period = NULL;
+ ratelimiters_mail = NULL; /* Updated by ratelimit ACL condition */
+ /* Note that ratelimiters_conn persists across resets. */
+
+ /* Reset message ACL variables */
diff --git a/mail-mta/exim/files/exim-4.96-rewrite-malformed-addr-fix.patch b/mail-mta/exim/files/exim-4.96-rewrite-malformed-addr-fix.patch
new file mode 100644
index 000000000000..2d3363e7b6cf
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-rewrite-malformed-addr-fix.patch
@@ -0,0 +1,42 @@
+modified for Gentoo, removed Changelog change due to conflicts
+
+From e7ec503729970a03d4509921342bc81313976126 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Tue, 12 Jul 2022 22:14:04 +0100
+Subject: [PATCH] Fix exit on attempt to rewrite a malformed address. Bug 2903
+
+---
+ doc/ChangeLog | 5 +
+ src/rewrite.c | 9 +-
+ test/confs/0471 | 7 +
+ test/log/0471 | 5 +
+ test/scripts/0000-Basic/0471 | 4 +-
+ test/stderr/0471 | 245 ++++++++++++++++++++++++++++++++++-
+ 6 files changed, 267 insertions(+), 8 deletions(-)
+
+--- a/src/rewrite.c
++++ b/src/rewrite.c
+@@ -493,19 +493,18 @@
+ empty address, overlong addres. Sometimes the result matters, sometimes not.
+ It seems this function is called for *any* header we see. */
+
+ if (!recipient)
+ {
+- /* Handle unparesable addresses in the header. Slightly ugly because a
++ /* Log unparesable addresses in the header. Slightly ugly because a
+ null output from the extract can also result from a header without an
+- address, "To: undisclosed recpients:;" being the classic case. */
++ address, "To: undisclosed recpients:;" being the classic case. Ignore
++ this one and carry on. */
+
+ if ((rewrite_rules || routed_old) && Ustrcmp(errmess, "empty address") != 0)
+- {
+ log_write(0, LOG_MAIN, "rewrite: %s", errmess);
+- exim_exit(EXIT_FAILURE);
+- }
++
+ loop_reset_point = store_reset(loop_reset_point);
+ continue;
+ }
+
+ /* If routed_old is not NULL, this is a rewrite caused by a router,
diff --git a/mail-mta/exim/files/exim-4.96-spf-memory-error-fix.patch b/mail-mta/exim/files/exim-4.96-spf-memory-error-fix.patch
new file mode 100644
index 000000000000..e474acf6f54d
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-spf-memory-error-fix.patch
@@ -0,0 +1,25 @@
+From 93c722ce0549360af68269f088f4e59ed8fc130e Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Sun, 7 Aug 2022 17:00:27 +0100
+Subject: [PATCH] SPF: fix memory accounting for error case
+
+---
+ src/spf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/spf.c b/src/spf.c
+index db6eea3a8..a8c0f75c4 100644
+--- a/src/spf.c
++++ b/src/spf.c
+@@ -204,7 +204,7 @@ spf_nxdomain = SPF_dns_rr_new_init(spf_dns_server,
+ "", ns_t_any, 24 * 60 * 60, HOST_NOT_FOUND);
+ if (!spf_nxdomain)
+ {
+- free(spf_dns_server);
++ store_free(spf_dns_server);
+ return NULL;
+ }
+
+--
+2.35.1
+
diff --git a/mail-mta/exim/files/exim-4.96-transport-crash.patch b/mail-mta/exim/files/exim-4.96-transport-crash.patch
new file mode 100644
index 000000000000..913fbf2d0918
--- /dev/null
+++ b/mail-mta/exim/files/exim-4.96-transport-crash.patch
@@ -0,0 +1,27 @@
+modified for Gentoo, removed Changelog
+
+From a8786a66feb3c003c74551399b345b1634cc6739 Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Thu, 4 May 2023 15:41:46 +0100
+Subject: [PATCH 1/3] Fix variable initialisation in smtp transport. Bug 2996
+
+---
+ doc/ChangeLog | 8 ++++++++
+ src/transports/smtp.c | 2 +-
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+--- a/src/transports/smtp.c
++++ b/src/transports/smtp.c
+@@ -4950,11 +4950,11 @@ Returns: nothing
+ void
+ smtp_transport_closedown(transport_instance *tblock)
+ {
+ smtp_transport_options_block * ob = SOB tblock->options_block;
+ client_conn_ctx cctx;
+-smtp_context sx;
++smtp_context sx = {0};
+ uschar buffer[256];
+ uschar inbuffer[4096];
+ uschar outbuffer[16];
+
+ /*XXX really we need an active-smtp-client ctx, rather than assuming stdout */