[exim-cvs] Move the TLS resumption support from Experimental…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] Move the TLS resumption support from Experimental to mainline
Gitweb: https://git.exim.org/exim.git/commitdiff/2983e1a616058c03b57f1ab32a691f8b8ff9764e
Commit:     2983e1a616058c03b57f1ab32a691f8b8ff9764e
Parent:     7adc9ca07a9a870f92a14d16740abfecde0bdfa4
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sun May 10 12:08:50 2020 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sun May 10 15:22:20 2020 +0100


    Move the TLS resumption support from Experimental to mainline
---
 doc/doc-docbook/spec.xfpt         | 134 ++++++++++++++++++++++++++++++++++++++
 doc/doc-txt/NewStuff              |   3 +
 doc/doc-txt/OptionLists.txt       |   2 +
 doc/doc-txt/experimental-spec.txt |  59 -----------------
 src/src/EDITME                    |   6 +-
 src/src/auths/gsasl_exim.c        |   4 +-
 src/src/config.h.defaults         |   2 +-
 src/src/configure.default         |  13 +++-
 src/src/deliver.c                 |   4 +-
 src/src/exim.c                    |   6 +-
 src/src/expand.c                  |   4 +-
 src/src/globals.c                 |   2 +-
 src/src/globals.h                 |   4 +-
 src/src/macro_predef.c            |   2 +-
 src/src/readconf.c                |   2 +-
 src/src/receive.c                 |   2 +-
 src/src/smtp_in.c                 |   2 +-
 src/src/spool_in.c                |   2 +-
 src/src/spool_out.c               |   2 +-
 src/src/structs.h                 |   2 +-
 src/src/tls-gnu.c                 |  28 ++++----
 src/src/tls-openssl.c             |  30 ++++-----
 src/src/transports/smtp.c         |   6 +-
 src/src/transports/smtp.h         |   2 +-
 24 files changed, 207 insertions(+), 116 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 748f81c..5f5538e 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -13766,6 +13766,17 @@ the value of the Distinguished Name of the certificate is made available in the
If certificate verification fails it may refer to a failing chain element
which is not the leaf.

+
+.new
+.vitem &$tls_in_resumption$& &&&
+       &$tls_out_resumption$&
+.vindex &$tls_in_resumption$&
+.vindex &$tls_out_resumption$&
+.cindex TLS resumption
+Observability for TLS session resumption.  See &<<SECTresumption>>& for details.
+.wen
+
+
 .vitem &$tls_in_sni$&
 .vindex "&$tls_in_sni$&"
 .vindex "&$tls_sni$&"
@@ -18274,6 +18285,14 @@ preference order of the available ciphers. Details are given in sections
 &<<SECTreqciphssl>>& and &<<SECTreqciphgnu>>&.



+.new
+.option tls_resumption_hosts main "host list&!!" unset
+.cindex TLS resumption
+This option controls which connections to offer the TLS resumption feature.
+See &<<SECTresumption>>& for details.
+.wen
+
+
.option tls_try_verify_hosts main "host list&!!" unset
.cindex "TLS" "client certificate verification"
.cindex "certificate" "verification of client"
@@ -25594,6 +25613,14 @@ is used in different ways by OpenSSL and GnuTLS (see sections
ciphers is a preference order.


+.new
+.option tls_resumption_hosts smtp "host list&!!" unset
+.cindex TLS resumption
+This option controls which connections to use the TLS resumption feature.
+See &<<SECTresumption>>& for details.
+.wen
+
+

.option tls_sni smtp string&!! unset
.cindex "TLS" "Server Name Indication"
@@ -29424,6 +29451,100 @@ Open-source PKI book, available online at
.ecindex IIDencsmtp2


+.new
+.section "TLS Resumption" "SECTresumption"
+.cindex TLS resumption
+TLS Session Resumption for TLS 1.2 and TLS 1.3 connections can be used (defined
+in RFC 5077 for 1.2). The support for this requires GnuTLS 3.6.3 or OpenSSL 1.1.1
+(or later).
+
+Session resumption (this is the "stateless" variant) involves the server sending
+a "session ticket" to the client on one connection, which can be stored by the
+client and used for a later session. The ticket contains sufficient state for
+the server to reconstruct the TLS session, avoiding some expensive crypto
+calculation and one full packet roundtrip time.
+
+.ilist
+Operational cost/benefit:
+
+ The extra data being transmitted costs a minor amount, and the client has
+ extra costs in storing and retrieving the data.
+
+ In the Exim/Gnutls implementation the extra cost on an initial connection
+ which is TLS1.2 over a loopback path is about 6ms on 2017-laptop class hardware.
+ The saved cost on a subsequent connection is about 4ms; three or more
+ connections become a net win. On longer network paths, two or more
+ connections will have an average lower startup time thanks to the one
+ saved packet roundtrip. TLS1.3 will save the crypto cpu costs but not any
+ packet roundtrips.
+
+.cindex "hints database" tls
+ Since a new hints DB is used on the TLS client,
+ the hints DB maintenance should be updated to additionally handle "tls".
+
+.next
+Security aspects:
+
+ The session ticket is encrypted, but is obviously an additional security
+ vulnarability surface. An attacker able to decrypt it would have access
+ all connections using the resumed session.
+ The session ticket encryption key is not committed to storage by the server
+ and is rotated regularly (OpenSSL: 1hr, and one previous key is used for
+ overlap; GnuTLS 6hr but does not specify any overlap).
+ Tickets have limited lifetime (2hr, and new ones issued after 1hr under
+ OpenSSL. GnuTLS 2hr, appears to not do overlap).
+
+ There is a question-mark over the security of the Diffie-Helman parameters
+ used for session negotiation.
+
+.next
+Observability:
+
+ The &%log_selector%& "tls_resumption" appends an asterisk to the tls_cipher "X="
+ element.
+
+ The variables &$tls_in_resumption$& and &$tls_out_resumption$&
+ have bits 0-4 indicating respectively
+ support built, client requested ticket, client offered session,
+ server issued ticket, resume used. A suitable decode list is provided
+ in the builtin macro _RESUME_DECODE for in &%listextract%& expansions.
+
+.next:
+Control:
+
+The &%tls_resumption_hosts%& main option specifies a hostlist for which
+exim, operating as a server, will offer resumption to clients.
+Current best practice is to not offer the feature to MUA connection.
+Commonly this can be done like this:
+.code
+tls_resumption_hosts = ${if inlist {$received_port}{587:465} {:}{*}}
+.endd
+If the peer host matches the list after expansion then resumption
+is offered and/or accepted.
+
+The &%tls_resumption_hosts% smtp transport option performs the
+equivalent function for operation as a client.
+If the peer host matches the list after expansion then resumption
+is attempted (if a stored session is available) or the information
+stored (if supplied by the peer).
+
+
+.next
+Issues:
+
+ In a resumed session:
+.ilist
+ The variables &$tls_{in,out}_cipher$& will have values different
+ to the original (under GnuTLS).
+.next
+ The variables &$tls_{in,out}_ocsp$& will be "not requested" or "no response",
+ and the &%hosts_require_ocsp%& smtp trasnport option will fail.
+. XXX need to do something with that hosts_require_ocsp
+.endlist
+
+.endlist
+.wen
+

 .section DANE "SECDANE"
 .cindex DANE
@@ -38043,6 +38164,7 @@ selection marked by asterisks:
 &`*tls_certificate_verified   `&  certificate verification status
 &`*tls_cipher                 `&  TLS cipher suite on <= and => lines
 &` tls_peerdn                 `&  TLS peer DN on <= and => lines
+&` tls_resumption             `&  append * to cipher field
 &` tls_sni                    `&  TLS SNI on <= lines
 &` unknown_in_list            `&  DNS lookup failed in list match


@@ -38444,6 +38566,14 @@ connection, the cipher suite used is added to the log line, preceded by X=.
connection, and a certificate is supplied by the remote host, the peer DN is
added to the log line, preceded by DN=.
.next
+.cindex "log" "TLS resumption"
+.cindex "TLS" "logging session resumption"
+.new
+&%tls_resumption%&: When a message is sent or received over an encrypted
+connection and the TLS session resumed one used on a previous TCP connection,
+an asterisk is appended to the X= cipher field in the log line.
+.wen
+.next
.cindex "log" "TLS SNI"
.cindex "TLS" "logging SNI"
&%tls_sni%&: When a message is received over an encrypted connection, and
@@ -38989,6 +39119,10 @@ for remote hosts
.next
&'ratelimit'&: the data for implementing the ratelimit ACL condition
.next
+.new
+&'tls'&: TLS session resumption data
+.wen
+.next
&'misc'&: other hints data
.endlist

diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 53d7b5c..f3bf3e8 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -15,6 +15,9 @@ Version 4.95
  2. The native SRS support, previously experimental, is now supported. It is
     not built unless specified in the Local/Makefile.


+ 3. TLS resumption support, previously experimental, is now supported and
+    included in default builds.
+


 Version 4.94
 ------------
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index f15ccd5..39827b6 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -602,6 +602,8 @@ tls_privatekey                       string*         unset         main
 tls_remember_emstp                   boolean         false         main              4.21
 tls_require_ciphers                  string*         unset         smtp              4.00 replaces tls_verify_ciphers
                                      string*         unset         main              4.33
+tls_resumption_hosts                 host list*      unset         main              4.95
+                                     host list*      unset         smtp              4.95
 tls_sni                              string*         unset         main              4.80
 tls_tempfail_tryclear                boolean         true          smtp              4.05
 tls_try_verify_hosts                 host list       unset         main              4.00
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index 2b6d01f..599d2bb 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -684,65 +684,6 @@ used via the transport in question.




-
-TLS Session Resumption
-----------------------
-TLS Session Resumption for TLS 1.2 and TLS 1.3 connections can be used (defined
-in RFC 5077 for 1.2). The support for this can be included by building with
-EXPERIMENTAL_TLS_RESUME defined. This requires GnuTLS 3.6.3 or OpenSSL 1.1.1
-(or later).
-
-Session resumption (this is the "stateless" variant) involves the server sending
-a "session ticket" to the client on one connection, which can be stored by the
-client and used for a later session. The ticket contains sufficient state for
-the server to reconstruct the TLS session, avoiding some expensive crypto
-calculation and one full packet roundtrip time.
-
-Operational cost/benefit:
- The extra data being transmitted costs a minor amount, and the client has
- extra costs in storing and retrieving the data.
-
- In the Exim/Gnutls implementation the extra cost on an initial connection
- which is TLS1.2 over a loopback path is about 6ms on 2017-laptop class hardware.
- The saved cost on a subsequent connection is about 4ms; three or more
- connections become a net win. On longer network paths, two or more
- connections will have an average lower startup time thanks to the one
- saved packet roundtrip. TLS1.3 will save the crypto cpu costs but not any
- packet roundtrips.
-
- Since a new hints DB is used, the hints DB maintenance should be updated
- to additionally handle "tls".
-
-Security aspects:
- The session ticket is encrypted, but is obviously an additional security
- vulnarability surface. An attacker able to decrypt it would have access
- all connections using the resumed session.
- The session ticket encryption key is not committed to storage by the server
- and is rotated regularly (OpenSSL: 1hr, and one previous key is used for
- overlap; GnuTLS 6hr but does not specify any overlap).
- Tickets have limited lifetime (2hr, and new ones issued after 1hr under
- OpenSSL. GnuTLS 2hr, appears to not do overlap).
-
- There is a question-mark over the security of the Diffie-Helman parameters
- used for session negotiation. TBD. q-value; cf bug 1895
-
-Observability:
- New log_selector "tls_resumption", appends an asterisk to the tls_cipher "X="
- element.
-
- Variables $tls_{in,out}_resumption have bits 0-4 indicating respectively
- support built, client requested ticket, client offered session,
- server issued ticket, resume used. A suitable decode list is provided
- in the builtin macro _RESUME_DECODE for ${listextract {}{}}.
-
-Issues:
- In a resumed session:
- $tls_{in,out}_cipher will have values different to the original (under GnuTLS)
- $tls_{in,out}_ocsp will be "not requested" or "no response", and
- hosts_require_ocsp will fail
-
-
-
Dovecot authenticator via inet socket
------------------------------------
If Dovecot is configured similar to :-
diff --git a/src/src/EDITME b/src/src/EDITME
index cf671af..e198a9c 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -277,6 +277,9 @@ SPOOL_DIRECTORY=/var/spool/exim
# specified in INCLUDE.


+# Uncomment the following line to remove support for TLS Resumption
+# DISABLE_TLS_RESUME=yes
+

 ###############################################################################
 #           THESE ARE THINGS YOU PROBABLY WANT TO SPECIFY                     #
@@ -633,9 +636,6 @@ DISABLE_MAL_MKS=yes
 # Uncomment the following line to add queuefile transport support
 # EXPERIMENTAL_QUEUEFILE=yes


-# Uncomment the following line to include support for TLS Resumption
-# EXPERIMENTAL_TLS_RESUME=yes
-
 ###############################################################################
 #                 THESE ARE THINGS YOU MIGHT WANT TO SPECIFY                  #
 ###############################################################################
diff --git a/src/src/auths/gsasl_exim.c b/src/src/auths/gsasl_exim.c
index a3aaf1f..708957f 100644
--- a/src/src/auths/gsasl_exim.c
+++ b/src/src/auths/gsasl_exim.c
@@ -365,7 +365,7 @@ HDEBUG(D_auth)
 #ifndef DISABLE_TLS
 if (tls_in.channelbinding && ob->server_channelbinding)
   {
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED)
     {        /* per RFC 7677 section 4 */
     HDEBUG(D_auth) debug_printf(
@@ -814,7 +814,7 @@ HDEBUG(D_auth)
 #ifndef DISABLE_TLS
 if (tls_out.channelbinding && ob->client_channelbinding)
   {
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   if (!tls_out.ext_master_secret && tls_out.resumption == RESUME_USED)
     {        /* per RFC 7677 section 4 */
     string_format(buffer, buffsize, "%s",
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index a91c3c3..1a1091f 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -54,6 +54,7 @@ Do not put spaces between # and the 'define'.
 #define DISABLE_PRDR
 #define DISABLE_QUEUE_RAMP
 #define DISABLE_TLS
+#define DISABLE_TLS_RESUME
 #define DISABLE_D_OPTION


#define ENABLE_DISABLE_FSYNC
@@ -206,7 +207,6 @@ Do not put spaces between # and the 'define'.
#define EXPERIMENTAL_LMDB
#define EXPERIMENTAL_QUEUEFILE
#define EXPERIMENTAL_SRS_ALT
-#define EXPERIMENTAL_TLS_RESUME


 /* For developers */
diff --git a/src/src/configure.default b/src/src/configure.default
index b758c89..57af99c 100644
--- a/src/src/configure.default
+++ b/src/src/configure.default
@@ -169,7 +169,14 @@ acl_smtp_data =         acl_check_data
 # tls_privatekey = /etc/ssl/exim.pem


# For OpenSSL, prefer EC- over RSA-authenticated ciphers
-# tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAULT
+.ifdef _HAVE_OPENSSL
+tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAULT
+.endif
+
+# Don't offer resumption to (most) MUAs, who we don't want to reuse
+# tickets. Once the TLS extension for vended ticket numbers comes
+# though, re-examine since resumption on a single-use ticket is still a benefit.
+tls_resumption_hosts = ${if inlist {$received_port}{587:465} {:}{*}}

 # In order to support roaming users who wish to send email from anywhere,
 # you may want to make Exim listen on other ports as well as port 25, in
@@ -808,6 +815,9 @@ begin transports
 remote_smtp:
   driver = smtp
   message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
+.ifdef _HAVE_TLS
+  tls_resumption_hosts = *
+#endif
 .ifdef _HAVE_PRDR
   hosts_try_prdr = *
 .endif
@@ -848,6 +858,7 @@ smarthost_smtp:
 .ifdef _HAVE_GNUTLS
   tls_require_ciphers = SECURE192:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1
 .endif
+  tls_resumption_hosts = *
 .endif
 .ifdef _HAVE_PRDR
   hosts_try_prdr = *
diff --git a/src/src/deliver.c b/src/src/deliver.c
index b681584..3dcd7f9 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -817,7 +817,7 @@ d_tlslog(gstring * g, address_item * addr)
 if (LOGGING(tls_cipher) && addr->cipher)
   {
   g = string_append(g, 2, US" X=", addr->cipher);
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume))
     g = string_catn(g, US"*", 1);
 #endif
@@ -4773,7 +4773,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 #ifdef SUPPORT_DANE
       if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
 #endif
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
       if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume);
 # endif


diff --git a/src/src/exim.c b/src/src/exim.c
index ab2d673..f61fe20 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -931,6 +931,9 @@ g = string_cat(NULL, US"Support for:");
#ifdef USE_OPENSSL
g = string_cat(g, US" OpenSSL");
#endif
+#ifndef DISABLE_TLS_RESUME
+ g = string_cat(g, US" TLS_resume");
+#endif
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
g = string_cat(g, US" translate_ip_address");
#endif
@@ -1007,9 +1010,6 @@ g = string_cat(NULL, US"Support for:");
#if defined(EXPERIMENTAL_SRS_ALT)
g = string_cat(g, US" Experimental_SRS");
#endif
-#ifdef EXPERIMENTAL_TLS_RESUME
- g = string_cat(g, US" Experimental_TLS_resume");
-#endif
g = string_cat(g, US"\n");

 g = string_cat(g, US"Lookups (built-in):");
diff --git a/src/src/expand.c b/src/src/expand.c
index 4abde0a..732e20f 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -779,7 +779,7 @@ static var_entry var_table[] = {
   { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
   { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
   { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   { "tls_in_resumption",   vtype_int,         &tls_in.resumption },
 #endif
 #ifndef DISABLE_TLS
@@ -797,7 +797,7 @@ static var_entry var_table[] = {
   { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
   { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
   { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   { "tls_out_resumption",  vtype_int,         &tls_out.resumption },
 #endif
 #ifndef DISABLE_TLS
diff --git a/src/src/globals.c b/src/src/globals.c
index 5610549..1a4e3c8 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -137,7 +137,7 @@ uschar *tls_ocsp_file          = NULL;
 uschar *tls_privatekey         = NULL;
 BOOL    tls_remember_esmtp     = FALSE;
 uschar *tls_require_ciphers    = NULL;
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
 uschar *tls_resumption_hosts   = NULL;
 # endif
 uschar *tls_try_verify_hosts   = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index fffe744..1bdf338 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -107,7 +107,7 @@ typedef struct {
     OCSP_FAILED,        /* verify failed */
     OCSP_VFIED            /* verified */
     }     ocsp;              /* Stapled OCSP status */
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   unsigned resumption;        /* Session resumption */
   BOOL      host_resumable:1;
   BOOL      ticket_received:1;
@@ -134,7 +134,7 @@ extern uschar *tls_ocsp_file;          /* OCSP stapling proof file */
 extern uschar *tls_privatekey;         /* Private key file */
 extern BOOL    tls_remember_esmtp;     /* For YAEB */
 extern uschar *tls_require_ciphers;    /* So some can be avoided */
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
 extern uschar *tls_resumption_hosts;   /* TLS session resumption */
 # endif
 extern uschar *tls_try_verify_hosts;   /* Optional client verification */
diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c
index f6cfcb1..aeb234a 100644
--- a/src/src/macro_predef.c
+++ b/src/src/macro_predef.c
@@ -204,7 +204,7 @@ due to conflicts with other common macros. */
 #ifdef EXPERIMENTAL_DSN_INFO
   builtin_macro_create(US"_HAVE_DSN_INFO");
 #endif
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   builtin_macro_create(US"_HAVE_TLS_RESUME");
 #endif


diff --git a/src/src/readconf.c b/src/src/readconf.c
index 3921ccf..7b474f5 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -378,7 +378,7 @@ static optionlist optionlist_config[] = {
   { "tls_privatekey",           opt_stringptr,   {&tls_privatekey} },
   { "tls_remember_esmtp",       opt_bool,        {&tls_remember_esmtp} },
   { "tls_require_ciphers",      opt_stringptr,   {&tls_require_ciphers} },
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   { "tls_resumption_hosts",     opt_stringptr,   {&tls_resumption_hosts} },
 # endif
   { "tls_try_verify_hosts",     opt_stringptr,   {&tls_try_verify_hosts} },
diff --git a/src/src/receive.c b/src/src/receive.c
index 0fbd35f..df8719e 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -3994,7 +3994,7 @@ g = add_host_info_for_log(g);
 if (LOGGING(tls_cipher) && tls_in.cipher)
   {
   g = string_append(g, 2, US" X=", tls_in.cipher);
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
     g = string_catn(g, US"*", 1);
 # endif
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index b3d1acb..412ef4d 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -1801,7 +1801,7 @@ s_tlslog(gstring * g)
 if (LOGGING(tls_cipher) && tls_in.cipher)
   {
   g = string_append(g, 2, US" X=", tls_in.cipher);
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
     g = string_catn(g, US"*", 1);
 #endif
diff --git a/src/src/spool_in.c b/src/src/spool_in.c
index a0147d5..4b70780 100644
--- a/src/src/spool_in.c
+++ b/src/src/spool_in.c
@@ -683,7 +683,7 @@ for (;;)
     tls_in.sni = string_unprinting(string_copy_taint(q+4, tainted));
       else if (Ustrncmp(q, "ocsp", 4) == 0)
     tls_in.ocsp = q[5] - '0';
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
       else if (Ustrncmp(q, "resumption", 10) == 0)
     tls_in.resumption = q[11] - 'A';
 # endif
diff --git a/src/src/spool_out.c b/src/src/spool_out.c
index 539ad3d..5d658fd 100644
--- a/src/src/spool_out.c
+++ b/src/src/spool_out.c
@@ -261,7 +261,7 @@ if (tls_in.ourcert)
     fprintf(fp, "-tls_ourcert %s\n", CS big_buffer);
   }
 if (tls_in.ocsp)     fprintf(fp, "-tls_ocsp %d\n",   tls_in.ocsp);
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
 fprintf(fp, "-tls_resumption %c\n", 'A' + tls_in.resumption);
 # endif
 if (tls_in.ver) spool_var_write(fp, US"tls_ver", tls_in.ver);
diff --git a/src/src/structs.h b/src/src/structs.h
index e1d989a..9aab603 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -644,7 +644,7 @@ typedef struct address_item {
 #ifdef SUPPORT_I18N
     BOOL af_utf8_downcvt:1;        /* downconvert was done for delivery */
 #endif
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
     BOOL af_tls_resume:1;        /* TLS used a resumed session */
 #endif
   } flags;
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 24114f0..c8017a7 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -111,7 +111,7 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
 # endif
 #endif


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
# if GNUTLS_VERSION_NUMBER < 0x030603
# error GNUTLS version too early for session-resumption
# endif
@@ -131,7 +131,7 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
void
options_tls(void)
{
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
# endif
# ifdef EXIM_HAVE_TLS1_3
@@ -266,7 +266,7 @@ static BOOL gnutls_buggy_ocsp = FALSE;
static BOOL exim_testharness_disable_ocsp_validity_check = FALSE;
#endif

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
static gnutls_datum_t server_sessticket_key;
#endif

@@ -326,7 +326,7 @@ static void exim_gnutls_logger_cb(int level, const char *message);

static int exim_sni_handling_cb(gnutls_session_t session);

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
static int
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
unsigned incoming, const gnutls_datum_t * msg);
@@ -337,7 +337,7 @@ tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
void
tls_daemon_init(void)
{
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
/* We are dependent on the GnuTLS implementation of the Session Ticket
encryption; both the strength and the key rotation period. We hope that
the strength at least matches that of the ciphersuite (but GnuTLS does not
@@ -1003,7 +1003,7 @@ So we need to spot the Certificate handshake message, parse it and spot any stat
This is different to tls1.2 - where it is a separate record (wireshake term) / handshake message (gnutls term).
*/

-#if defined(EXPERIMENTAL_TLS_RESUME) || defined(SUPPORT_GNUTLS_EXT_RAW_PARSE)
+#if !defined(DISABLE_TLS_RESUME) || defined(SUPPORT_GNUTLS_EXT_RAW_PARSE)
 /* Callback for certificate-status, on server. We sent stapled OCSP. */
 static int
 tls_server_certstatus_cb(gnutls_session_t session, unsigned int htype,
@@ -1035,7 +1035,7 @@ switch (htype)
 # endif
   case GNUTLS_HANDSHAKE_CERTIFICATE_STATUS:
     return tls_server_certstatus_cb(sess, htype, when, incoming, msg);
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
     return tls_server_ticket_cb(sess, htype, when, incoming, msg);
 # endif
@@ -2328,7 +2328,7 @@ else
 }



-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
static int
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
unsigned incoming, const gnutls_datum_t * msg)
@@ -2442,7 +2442,7 @@ DEBUG(D_tls) debug_printf("initialising GnuTLS as a server\n");
#endif
}

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tls_server_resume_prehandshake(state);
#endif

@@ -2550,7 +2550,7 @@ if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET)
tls_in.ext_master_secret = TRUE;
#endif

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tls_server_resume_posthandshake(state);
#endif

@@ -2683,7 +2683,7 @@ return TRUE;



-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
/* On the client, get any stashed session for the given IP from hints db
and apply it to the ssl-connection for attempted resumption. Although
there is a gnutls_session_ticket_enable_client() interface it is
@@ -2816,7 +2816,7 @@ if (gnutls_session_is_resumed(state->session))

 tls_save_session(tlsp, state->session, host);
 }
-#endif    /* EXPERIMENTAL_TLS_RESUME */
+#endif    /* !DISABLE_TLS_RESUME */



/*************************************************
@@ -2970,7 +2970,7 @@ if (request_ocsp)
}
#endif

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tls_client_resume_prehandshake(state, tlsp, host, ob);
#endif

@@ -3070,7 +3070,7 @@ if (request_ocsp)
}
#endif

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tls_client_resume_posthandshake(state, tlsp, host);
#endif

diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 0caf1c0..673768a 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -116,7 +116,7 @@ change this guard and punt the issue for a while longer. */
# define DISABLE_OCSP
#endif

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
# if OPENSSL_VERSION_NUMBER < 0x0101010L
# error OpenSSL version too old for session-resumption
# endif
@@ -292,7 +292,7 @@ for (struct exim_openssl_option * o = exim_openssl_options;
builtin_macro_create(buf);
}

-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
# endif
# ifdef SSL_OP_NO_TLSv1_3
@@ -422,7 +422,7 @@ static int tls_server_stapling_cb(SSL *s, void *arg);


/* Daemon-called, before every connection, key create/rotate */
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
static void tk_init(void);
static int tls_exdata_idx = -1;
#endif
@@ -430,7 +430,7 @@ static int tls_exdata_idx = -1;
void
tls_daemon_init(void)
{
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tk_init();
#endif
return;
@@ -891,7 +891,7 @@ fclose(fp);
#endif


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
/* Manage the keysets used for encrypting the session tickets, on the server. */

 typedef struct {            /* Session ticket encryption key */
@@ -2176,12 +2176,12 @@ availability of the option value macros from OpenSSL.  */
 if (!tls_openssl_options_parse(openssl_options, &init_options))
   return tls_error(US"openssl_options parsing failed", host, NULL, errstr);


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
 tlsp->resumption = RESUME_SUPPORTED;
 #endif
 if (init_options)
   {
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   /* Should the server offer session resumption? */
   if (!host && verify_check_host(&tls_resumption_hosts) == OK)
     {
@@ -2685,12 +2685,12 @@ else if (verify_check_host(&tls_try_verify_hosts) == OK)
   server_verify_optional = TRUE;
   }


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
 SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_key_callback);
 /* despite working, appears to always return failure, so ignoring */
 #endif
 #ifdef OPENSSL_HAVE_NUM_TICKETS
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
 SSL_CTX_set_num_tickets(server_ctx, tls_in.host_resumable ? 1 : 0);
 # else
 SSL_CTX_set_num_tickets(server_ctx, 0);    /* send no TLS1.3 stateful-tickets */
@@ -2796,7 +2796,7 @@ DEBUG(D_tls) debug_printf("SSL_accept was successful\n");
 ERR_clear_error();    /* Even success can leave errors in the stack. Seen with
             anon-authentication ciphersuite negotiated. */


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
if (SSL_session_reused(server_ssl))
{
tls_in.resumption |= RESUME_USED;
@@ -2983,7 +2983,7 @@ return DEFER;



-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
/* On the client, get any stashed session for the given IP from hints db
and apply it to the ssl-connection for attempted resumption. */

@@ -3145,7 +3145,7 @@ if (SSL_session_reused(exim_client_ctx->ssl))
   tlsp->resumption |= RESUME_USED;
   }
 }
-#endif    /* EXPERIMENTAL_TLS_RESUME */
+#endif    /* !DISABLE_TLS_RESUME */



 /*************************************************
@@ -3294,7 +3294,7 @@ else
     client_static_cbinfo, errstr) != OK)
     return FALSE;


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
#endif

@@ -3365,7 +3365,7 @@ if (request_ocsp)
}
#endif

-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
 if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
       errstr))
   return FALSE;
@@ -3406,7 +3406,7 @@ DEBUG(D_tls)
 #endif
   }


-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
tls_client_resume_posthandshake(exim_client_ctx, tlsp);
#endif

diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 8492a7f..f47c6d9 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -127,7 +127,7 @@ optionlist smtp_transport_options[] = {
   { "tls_dh_min_bits",      opt_int,       LOFF(tls_dh_min_bits) },
   { "tls_privatekey",       opt_stringptr, LOFF(tls_privatekey) },
   { "tls_require_ciphers",  opt_stringptr, LOFF(tls_require_ciphers) },
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   { "tls_resumption_hosts", opt_stringptr, LOFF(tls_resumption_hosts) },
 # endif
   { "tls_sni",              opt_stringptr, LOFF(tls_sni) },
@@ -233,7 +233,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   .tls_verify_certificates =    US"system",
   .tls_dh_min_bits =        EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
   .tls_tempfail_tryclear =    TRUE,
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   .tls_resumption_hosts =    NULL,
 # endif
   .tls_verify_hosts =        NULL,
@@ -1970,7 +1970,7 @@ tls_out.peerdn = NULL;
 tls_out.sni = NULL;
 #endif
 tls_out.ocsp = OCSP_NOT_REQ;
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
 tls_out.resumption = 0;
 #endif
 tls_out.ver = NULL;
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index 6e63a00..037105a 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -84,7 +84,7 @@ typedef struct {
   uschar *tls_crl;
   uschar *tls_privatekey;
   uschar *tls_require_ciphers;
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
   uschar *tls_resumption_hosts;
 # endif
   uschar *tls_sni;