]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/tls-openssl.c
Merge branch '4.next'
[user/henk/code/exim.git] / src / src / tls-openssl.c
index fd257f3c6aaacb5e64aea6584778718ecabb0972..bc454c8a136d3e71a5b4d9e0ac1a83944b2e7ab3 100644 (file)
@@ -2,7 +2,8 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2014 */
+/* Copyright (c) University of Cambridge 1995 - 2019 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Portions Copyright (c) The OpenSSL Project 1999 */
@@ -22,18 +23,301 @@ functions from the OpenSSL library. */
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
-#ifdef EXPERIMENTAL_OCSP
-#include <openssl/ocsp.h>
+#ifndef OPENSSL_NO_ECDH
+# include <openssl/ec.h>
+#endif
+#ifndef DISABLE_OCSP
+# include <openssl/ocsp.h>
+#endif
+#ifdef SUPPORT_DANE
+# include "danessl.h"
 #endif
 
-#ifdef EXPERIMENTAL_OCSP
-#define EXIM_OCSP_SKEW_SECONDS (300L)
-#define EXIM_OCSP_MAX_AGE (-1L)
+
+#ifndef DISABLE_OCSP
+# define EXIM_OCSP_SKEW_SECONDS (300L)
+# define EXIM_OCSP_MAX_AGE (-1L)
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
-#define EXIM_HAVE_OPENSSL_TLSEXT
+# define EXIM_HAVE_OPENSSL_TLSEXT
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+# define EXIM_HAVE_RSA_GENKEY_EX
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# define EXIM_HAVE_OCSP_RESP_COUNT
+# define OPENSSL_AUTO_SHA256
+#else
+# define EXIM_HAVE_EPHEM_RSA_KEX
+# define EXIM_HAVE_RAND_PSEUDO
+#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+# define EXIM_HAVE_SHA256
+#endif
+
+/* X509_check_host provides sane certificate hostname checking, but was added
+to OpenSSL late, after other projects forked off the code-base.  So in
+addition to guarding against the base version number, beware that LibreSSL
+does not (at this time) support this function.
+
+If LibreSSL gains a different API, perhaps via libtls, then we'll probably
+opt to disentangle and ask a LibreSSL user to provide glue for a third
+crypto provider for libtls instead of continuing to tie the OpenSSL glue
+into even twistier knots.  If LibreSSL gains the same API, we can just
+change this guard and punt the issue for a while longer. */
+
+#ifndef LIBRESSL_VERSION_NUMBER
+# if OPENSSL_VERSION_NUMBER >= 0x010100000L
+#  define EXIM_HAVE_OPENSSL_CHECKHOST
+#  define EXIM_HAVE_OPENSSL_DH_BITS
+#  define EXIM_HAVE_OPENSSL_TLS_METHOD
+#  define EXIM_HAVE_OPENSSL_KEYLOG
+#  define EXIM_HAVE_OPENSSL_CIPHER_GET_ID
+#  define EXIM_HAVE_SESSION_TICKET
+#  define EXIM_HAVE_OPESSL_TRACE
+#  define EXIM_HAVE_OPESSL_GET0_SERIAL
+#  ifndef DISABLE_OCSP
+#   define EXIM_HAVE_OCSP
+#  endif
+#  define EXIM_HAVE_ALPN /* fail ret from hshake-cb is ignored by LibreSSL */
+# else
+#  define EXIM_NEED_OPENSSL_INIT
+# endif
+# if OPENSSL_VERSION_NUMBER >= 0x010000000L \
+    && (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
+#  define EXIM_HAVE_OPENSSL_CHECKHOST
+# endif
+#endif
+
+#if LIBRESSL_VERSION_NUMBER >= 0x3040000fL
+# define EXIM_HAVE_OPENSSL_CIPHER_GET_ID
+#endif
+
+#if !defined(LIBRESSL_VERSION_NUMBER) \
+    || LIBRESSL_VERSION_NUMBER >= 0x20010000L
+# if !defined(OPENSSL_NO_ECDH)
+#  if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#   define EXIM_HAVE_ECDH
+#  endif
+#  if OPENSSL_VERSION_NUMBER >= 0x10002000L
+#   define EXIM_HAVE_OPENSSL_EC_NIST2NID
+#  endif
+# endif
+#endif
+
+#ifndef LIBRESSL_VERSION_NUMBER
+# if OPENSSL_VERSION_NUMBER >= 0x010101000L
+#  define OPENSSL_HAVE_KEYLOG_CB
+#  define OPENSSL_HAVE_NUM_TICKETS
+#  define EXIM_HAVE_OPENSSL_CIPHER_STD_NAME
+# else
+#  define OPENSSL_BAD_SRVR_OURCERT
+# endif
+#endif
+
+#if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP)
+# warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
+# define DISABLE_OCSP
+#endif
+
+#ifndef DISABLE_TLS_RESUME
+# if OPENSSL_VERSION_NUMBER < 0x0101010L
+#  error OpenSSL version too old for session-resumption
+# endif
+#endif
+
+#ifdef EXIM_HAVE_OPENSSL_CHECKHOST
+# include <openssl/x509v3.h>
+#endif
+
+#ifndef EXIM_HAVE_OPENSSL_CIPHER_STD_NAME
+# ifndef EXIM_HAVE_OPENSSL_CIPHER_GET_ID
+#  define SSL_CIPHER_get_id(c) (c->id)
+# endif
+# ifndef MACRO_PREDEF
+#  include "tls-cipher-stdname.c"
+# endif
+#endif
+
+/*************************************************
+*        OpenSSL option parse                    *
+*************************************************/
+
+typedef struct exim_openssl_option {
+  uschar *name;
+  long    value;
+} exim_openssl_option;
+/* We could use a macro to expand, but we need the ifdef and not all the
+options document which version they were introduced in.  Policylet: include
+all options unless explicitly for DTLS, let the administrator choose which
+to apply.
+
+This list is current as of:
+  ==>  1.1.1c  <==
+
+XXX could we autobuild this list, as with predefined-macros?
+Seems just parsing ssl.h for SSL_OP_.* would be enough (except to exclude DTLS).
+Also allow a numeric literal?
+*/
+static exim_openssl_option exim_openssl_options[] = {
+/* KEEP SORTED ALPHABETICALLY! */
+#ifdef SSL_OP_ALL
+  { US"all", (long) SSL_OP_ALL },
+#endif
+#ifdef SSL_OP_ALLOW_NO_DHE_KEX
+  { US"allow_no_dhe_kex", SSL_OP_ALLOW_NO_DHE_KEX },
+#endif
+#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+  { US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
+#endif
+#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
+  { US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
+#endif
+#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
+  { US"cryptopro_tlsext_bug", SSL_OP_CRYPTOPRO_TLSEXT_BUG },
+#endif
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+  { US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
+#endif
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+  { US"enable_middlebox_compat", SSL_OP_ENABLE_MIDDLEBOX_COMPAT },
+#endif
+#ifdef SSL_OP_EPHEMERAL_RSA
+  { US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
+#endif
+#ifdef SSL_OP_LEGACY_SERVER_CONNECT
+  { US"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT },
+#endif
+#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+  { US"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
+#endif
+#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
+  { US"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG },
+#endif
+#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
+  { US"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING },
+#endif
+#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
+  { US"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG },
+#endif
+#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+  { US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
+#endif
+#ifdef SSL_OP_NO_ANTI_REPLAY
+  { US"no_anti_replay", SSL_OP_NO_ANTI_REPLAY },
+#endif
+#ifdef SSL_OP_NO_COMPRESSION
+  { US"no_compression", SSL_OP_NO_COMPRESSION },
+#endif
+#ifdef SSL_OP_NO_ENCRYPT_THEN_MAC
+  { US"no_encrypt_then_mac", SSL_OP_NO_ENCRYPT_THEN_MAC },
+#endif
+#ifdef SSL_OP_NO_RENEGOTIATION
+  { US"no_renegotiation", SSL_OP_NO_RENEGOTIATION },
+#endif
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+  { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
+#endif
+#ifdef SSL_OP_NO_SSLv2
+  { US"no_sslv2", SSL_OP_NO_SSLv2 },
+#endif
+#ifdef SSL_OP_NO_SSLv3
+  { US"no_sslv3", SSL_OP_NO_SSLv3 },
+#endif
+#ifdef SSL_OP_NO_TICKET
+  { US"no_ticket", SSL_OP_NO_TICKET },
+#endif
+#ifdef SSL_OP_NO_TLSv1
+  { US"no_tlsv1", SSL_OP_NO_TLSv1 },
+#endif
+#ifdef SSL_OP_NO_TLSv1_1
+# if SSL_OP_NO_TLSv1_1 == 0x00000400L
+  /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */
+#  warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring
+# else
+  { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 },
+# endif
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+  { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 },
+#endif
+#ifdef SSL_OP_NO_TLSv1_3
+  { US"no_tlsv1_3", SSL_OP_NO_TLSv1_3 },
+#endif
+#ifdef SSL_OP_PRIORITIZE_CHACHA
+  { US"prioritize_chacha", SSL_OP_PRIORITIZE_CHACHA },
+#endif
+#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
+  { US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
+#endif
+#ifdef SSL_OP_SINGLE_DH_USE
+  { US"single_dh_use", SSL_OP_SINGLE_DH_USE },
+#endif
+#ifdef SSL_OP_SINGLE_ECDH_USE
+  { US"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE },
+#endif
+#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+  { US"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
+#endif
+#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+  { US"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
 #endif
+#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
+  { US"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG },
+#endif
+#ifdef SSL_OP_TLS_D5_BUG
+  { US"tls_d5_bug", SSL_OP_TLS_D5_BUG },
+#endif
+#ifdef SSL_OP_TLS_ROLLBACK_BUG
+  { US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
+#endif
+#ifdef SSL_OP_TLSEXT_PADDING
+  { US"tlsext_padding", SSL_OP_TLSEXT_PADDING },
+#endif
+};
+
+#ifndef MACRO_PREDEF
+static int exim_openssl_options_size = nelem(exim_openssl_options);
+static long init_options = 0;
+#endif
+
+#ifdef MACRO_PREDEF
+void
+options_tls(void)
+{
+uschar buf[64];
+
+for (struct exim_openssl_option * o = exim_openssl_options;
+     o < exim_openssl_options + nelem(exim_openssl_options); o++)
+  {
+  /* Trailing X is workaround for problem with _OPT_OPENSSL_NO_TLSV1
+  being a ".ifdef _OPT_OPENSSL_NO_TLSV1_3" match */
+
+  spf(buf, sizeof(buf), US"_OPT_OPENSSL_%T_X", o->name);
+  builtin_macro_create(buf);
+  }
+
+# ifndef DISABLE_TLS_RESUME
+builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
+# endif
+# ifdef SSL_OP_NO_TLSv1_3
+builtin_macro_create(US"_HAVE_TLS1_3");
+# endif
+# ifdef OPENSSL_BAD_SRVR_OURCERT
+builtin_macro_create(US"_TLS_BAD_MULTICERT_IN_OURCERT");
+# endif
+# ifdef EXIM_HAVE_OCSP
+builtin_macro_create(US"_HAVE_TLS_OCSP");
+builtin_macro_create(US"_HAVE_TLS_OCSP_LIST");
+# endif
+# ifdef EXIM_HAVE_ALPN
+builtin_macro_create(US"_HAVE_TLS_ALPN");
+# endif
+}
+#else
+
+/******************************************************************************/
 
 /* Structure for collecting random data for seeding. */
 
@@ -53,7 +337,9 @@ static const uschar *sid_ctx = US"exim";
 Simple case: client, `client_ctx`
  As a client, we can be doing a callout or cut-through delivery while receiving
  a message.  So we have a client context, which should have options initialised
- from the SMTP Transport.
+ from the SMTP Transport.  We may also concurrently want to make TLS connections
+ to utility daemons, so client-contexts are allocated and passed around in call
+ args rather than using a gobal.
 
 Server:
  There are two cases: with and without ServerNameIndication from the client.
@@ -67,34 +353,53 @@ Server:
  configuration.
 */
 
-static SSL_CTX *client_ctx = NULL;
-static SSL_CTX *server_ctx = NULL;
-static SSL     *client_ssl = NULL;
-static SSL     *server_ssl = NULL;
+typedef struct {
+  SSL_CTX *    ctx;
+  SSL *                ssl;
+  gstring *    corked;
+} exim_openssl_client_tls_ctx;
+
+
+/* static SSL_CTX *server_ctx = NULL; */
+/* static SSL     *server_ssl = NULL; */
 
 #ifdef EXIM_HAVE_OPENSSL_TLSEXT
 static SSL_CTX *server_sni = NULL;
 #endif
+#ifdef EXIM_HAVE_ALPN
+static BOOL server_seen_alpn = FALSE;
+#endif
 
 static char ssl_errstring[256];
 
-static int  ssl_session_timeout = 200;
+static int  ssl_session_timeout = 7200;                /* Two hours */
 static BOOL client_verify_optional = FALSE;
 static BOOL server_verify_optional = FALSE;
 
 static BOOL reexpand_tls_files_for_sni = FALSE;
 
 
-typedef struct tls_ext_ctx_cb {
-  uschar *certificate;
-  uschar *privatekey;
-#ifdef EXPERIMENTAL_OCSP
-  BOOL is_server;
+typedef struct ocsp_resp {
+  struct ocsp_resp *   next;
+  OCSP_RESPONSE *      resp;
+} ocsp_resplist;
+
+typedef struct exim_openssl_state {
+  exim_tlslib_state    lib_state;
+#define lib_ctx                        libdata0
+#define lib_ssl                        libdata1
+
+  tls_support *        tlsp;
+  uschar *     certificate;
+  uschar *     privatekey;
+  BOOL         is_server;
+#ifndef DISABLE_OCSP
+  STACK_OF(X509) *verify_stack;                /* chain for verifying the proof */
   union {
     struct {
       uschar        *file;
-      uschar        *file_expanded;
-      OCSP_RESPONSE *response;
+      const uschar  *file_expanded;
+      ocsp_resplist *olist;
     } server;
     struct {
       X509_STORE    *verify_store;     /* non-null if status requested */
@@ -102,32 +407,57 @@ typedef struct tls_ext_ctx_cb {
     } client;
   } u_ocsp;
 #endif
-  uschar *dhparam;
+  uschar *     dhparam;
   /* these are cached from first expand */
-  uschar *server_cipher_list;
+  uschar *     server_cipher_list;
   /* only passed down to tls_error: */
-  host_item *host;
-} tls_ext_ctx_cb;
+  host_item *  host;
+  const uschar * verify_cert_hostnames;
+#ifndef DISABLE_EVENT
+  uschar *     event_action;
+#endif
+} exim_openssl_state_st;
 
 /* 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. */
-tls_ext_ctx_cb *client_static_cbinfo = NULL;
-tls_ext_ctx_cb *server_static_cbinfo = NULL;
+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, BOOL optional,
-    int (*cert_vfy_cb)(int, X509_STORE_CTX *) );
+setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
+    uschar ** errstr );
 
 /* Callbacks */
-#ifdef EXIM_HAVE_OPENSSL_TLSEXT
-static int tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg);
-#endif
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
 static int tls_server_stapling_cb(SSL *s, void *arg);
 #endif
 
 
+
+/* Daemon-called, before every connection, key create/rotate */
+#ifndef DISABLE_TLS_RESUME
+static void tk_init(void);
+static int tls_exdata_idx = -1;
+#endif
+
+static void
+tls_per_lib_daemon_tick(void)
+{
+#ifndef DISABLE_TLS_RESUME
+tk_init();
+#endif
+}
+
+/* Called once at daemon startup */
+
+static void
+tls_per_lib_daemon_init(void)
+{
+tls_daemon_creds_reload();
+}
+
+
 /*************************************************
 *               Handle TLS error                 *
 *************************************************/
@@ -144,261 +474,107 @@ Argument:
   host      NULL if setting up a server;
             the connected host if setting up a client
   msg       error message or NULL if we should ask OpenSSL
+  errstr    pointer to output error message
 
 Returns:    OK/DEFER/FAIL
 */
 
 static int
-tls_error(uschar *prefix, host_item *host, uschar *msg)
+tls_error(uschar * prefix, const host_item * host, uschar * msg, uschar ** errstr)
 {
-if (msg == NULL)
+if (!msg)
   {
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  msg = (uschar *)ssl_errstring;
+  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+  msg = US ssl_errstring;
   }
 
-if (host == NULL)
-  {
-  uschar *conn_info = smtp_get_connection_info();
-  if (Ustrncmp(conn_info, US"SMTP ", 5) == 0)
-    conn_info += 5;
-  log_write(0, LOG_MAIN, "TLS error on %s (%s): %s",
-    conn_info, prefix, msg);
-  return DEFER;
-  }
-else
-  {
-  log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s): %s",
-    host->name, host->address, prefix, msg);
-  return FAIL;
-  }
+msg = string_sprintf("(%s): %s", prefix, msg);
+DEBUG(D_tls) debug_printf("TLS error '%s'\n", msg);
+if (errstr) *errstr = msg;
+return host ? FAIL : DEFER;
 }
 
 
 
-/*************************************************
-*        Callback to generate RSA key            *
-*************************************************/
+/**************************************************
+* General library initalisation                   *
+**************************************************/
 
-/*
-Arguments:
-  s          SSL connection
-  export     not used
-  keylength  keylength
+static BOOL
+lib_rand_init(void * addr)
+{
+randstuff r;
+if (!RAND_status()) return TRUE;
 
-Returns:     pointer to generated key
-*/
+gettimeofday(&r.tv, NULL);
+r.p = getpid();
+RAND_seed(US (&r), sizeof(r));
+RAND_seed(US big_buffer, big_buffer_size);
+if (addr) RAND_seed(US addr, sizeof(addr));
 
-static RSA *
-rsa_callback(SSL *s, int export, int keylength)
-{
-RSA *rsa_key;
-export = export;     /* Shut picky compilers up */
-DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength);
-rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
-if (rsa_key == NULL)
-  {
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s",
-    ssl_errstring);
-  return NULL;
-  }
-return rsa_key;
+return RAND_status();
 }
 
 
-
-/* Extreme debug
-#if defined(EXPERIMENTAL_OCSP)
-void
-x509_store_dump_cert_s_names(X509_STORE * store)
+static void
+tls_openssl_init(void)
 {
-STACK_OF(X509_OBJECT) * roots= store->objs;
-int i;
-static uschar name[256];
+static BOOL once = FALSE;
+if (once) return;
+once = TRUE;
 
-for(i= 0; i<sk_X509_OBJECT_num(roots); i++)
-  {
-  X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i);
-  if(tmp_obj->type == X509_LU_X509)
-    {
-    X509 * current_cert= tmp_obj->data.x509;
-    X509_NAME_oneline(X509_get_subject_name(current_cert), CS name, sizeof(name));
-    debug_printf(" %s\n", name);
-    }
-  }
-}
+#ifdef EXIM_NEED_OPENSSL_INIT
+SSL_load_error_strings();          /* basic set up */
+OpenSSL_add_ssl_algorithms();
 #endif
-*/
 
+#if defined(EXIM_HAVE_SHA256) && !defined(OPENSSL_AUTO_SHA256)
+/* SHA256 is becoming ever more popular. This makes sure it gets added to the
+list of available digests. */
+EVP_add_digest(EVP_sha256());
+#endif
 
-/*************************************************
-*        Callback for verification               *
-*************************************************/
+(void) lib_rand_init(NULL);
+(void) tls_openssl_options_parse(openssl_options, &init_options);
+}
 
-/* The SSL library does certificate verification if set up to do so. This
-callback has the current yes/no state is in "state". If verification succeeded,
-we set up the tls_peerdn string. If verification failed, what happens depends
-on whether the client is required to present a verifiable certificate or not.
 
-If verification is optional, we change the state to yes, but still log the
-verification error. For some reason (it really would help to have proper
-documentation of OpenSSL), this callback function then gets called again, this
-time with state = 1. In fact, that's useful, because we can set up the peerdn
-value, but we must take care not to set the private verified flag on the second
-time through.
 
-Note: this function is not called if the client fails to present a certificate
-when asked. We get here only if a certificate has been received. Handling of
-optional verification for this case is done when requesting SSL to verify, by
-setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT in the non-optional case.
+/*************************************************
+*                Initialize for DH               *
+*************************************************/
+
+/* If dhparam is set, expand it, and load up the parameters for DH encryption.
 
 Arguments:
-  state      current yes/no state as 1/0
-  x509ctx    certificate information.
-  client     TRUE for client startup, FALSE for server startup
+  sctx      The current SSL CTX (inbound or outbound)
+  dhparam   DH parameter file or fixed parameter identity string
+  host      connected host, if client; NULL if server
+  errstr    error string pointer
 
-Returns:     1 if verified, 0 if not
+Returns:    TRUE if OK (nothing to set up, or setup worked)
 */
 
-static int
-verify_callback(int state, X509_STORE_CTX *x509ctx, tls_support *tlsp, BOOL *calledp, BOOL *optionalp)
+static BOOL
+init_dh(SSL_CTX *sctx, uschar *dhparam, const host_item *host, uschar ** errstr)
 {
-static uschar txt[256];
+BIO *bio;
+DH *dh;
+uschar *dhexpanded;
+const char *pem;
+int dh_bitsize;
 
-X509_NAME_oneline(X509_get_subject_name(x509ctx->current_cert),
-  CS txt, sizeof(txt));
-
-if (state == 0)
-  {
-  log_write(0, LOG_MAIN, "SSL verify error: depth=%d error=%s cert=%s",
-    x509ctx->error_depth,
-    X509_verify_cert_error_string(x509ctx->error),
-    txt);
-  tlsp->certificate_verified = FALSE;
-  *calledp = TRUE;
-  if (!*optionalp)
-    {
-    tlsp->peercert = X509_dup(x509ctx->current_cert);
-    return 0;                      /* reject */
-    }
-  DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
-    "tls_try_verify_hosts)\n");
-  return 1;                          /* accept */
-  }
-
-if (x509ctx->error_depth != 0)
-  {
-  DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d cert=%s\n",
-     x509ctx->error_depth, txt);
-#ifdef EXPERIMENTAL_OCSP
-  if (tlsp == &tls_out && client_static_cbinfo->u_ocsp.client.verify_store)
-    {  /* client, wanting stapling  */
-    /* Add the server cert's signing chain as the one
-    for the verification of the OCSP stapled information. */
-  
-    if (!X509_STORE_add_cert(client_static_cbinfo->u_ocsp.client.verify_store,
-                             x509ctx->current_cert))
-      ERR_clear_error();
-    }
-#endif
-  }
-else
-  {
-  DEBUG(D_tls) debug_printf("SSL%s peer: %s\n",
-    *calledp ? "" : " authenticated", txt);
-  tlsp->peerdn = txt;
-  tlsp->peercert = X509_dup(x509ctx->current_cert);
-  }
-
-/*XXX JGH: this looks bogus - we set "verified" first time through, which
-will be for the root CS cert (calls work down the chain).  Why should it
-not be on the last call, where we're setting peerdn?
-
-To test: set up a chain anchored by a good root-CA but with a bad server cert.
-Does certificate_verified get set?
-*/
-if (!*calledp) tlsp->certificate_verified = TRUE;
-*calledp = TRUE;
-
-return 1;   /* accept */
-}
-
-static int
-verify_callback_client(int state, X509_STORE_CTX *x509ctx)
-{
-return verify_callback(state, x509ctx, &tls_out, &client_verify_callback_called, &client_verify_optional);
-}
-
-static int
-verify_callback_server(int state, X509_STORE_CTX *x509ctx)
-{
-return verify_callback(state, x509ctx, &tls_in, &server_verify_callback_called, &server_verify_optional);
-}
-
-
-
-/*************************************************
-*           Information callback                 *
-*************************************************/
-
-/* The SSL library functions call this from time to time to indicate what they
-are doing. We copy the string to the debugging output when TLS debugging has
-been requested.
-
-Arguments:
-  s         the SSL connection
-  where
-  ret
-
-Returns:    nothing
-*/
-
-static void
-info_callback(SSL *s, int where, int ret)
-{
-where = where;
-ret = ret;
-DEBUG(D_tls) debug_printf("SSL info: %s\n", SSL_state_string_long(s));
-}
-
-
-
-/*************************************************
-*                Initialize for DH               *
-*************************************************/
-
-/* If dhparam is set, expand it, and load up the parameters for DH encryption.
-
-Arguments:
-  dhparam   DH parameter file or fixed parameter identity string
-  host      connected host, if client; NULL if server
-
-Returns:    TRUE if OK (nothing to set up, or setup worked)
-*/
-
-static BOOL
-init_dh(SSL_CTX *sctx, uschar *dhparam, host_item *host)
-{
-BIO *bio;
-DH *dh;
-uschar *dhexpanded;
-const char *pem;
-
-if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded))
+if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
   return FALSE;
 
-if (dhexpanded == NULL || *dhexpanded == '\0')
-  {
+if (!dhexpanded || !*dhexpanded)
   bio = BIO_new_mem_buf(CS std_dh_prime_default(), -1);
-  }
 else if (dhexpanded[0] == '/')
   {
-  bio = BIO_new_file(CS dhexpanded, "r");
-  if (bio == NULL)
+  if (!(bio = BIO_new_file(CS dhexpanded, "r")))
     {
     tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
-          host, US strerror(errno));
+          host, US strerror(errno), errstr);
     return FALSE;
     }
   }
@@ -410,40 +586,51 @@ else
     return TRUE;
     }
 
-  pem = std_dh_prime_named(dhexpanded);
-  if (!pem)
+  if (!(pem = std_dh_prime_named(dhexpanded)))
     {
     tls_error(string_sprintf("Unknown standard DH prime \"%s\"", dhexpanded),
-        host, US strerror(errno));
+        host, US strerror(errno), errstr);
     return FALSE;
     }
   bio = BIO_new_mem_buf(CS pem, -1);
   }
 
-dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-if (dh == NULL)
+if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)))
   {
   BIO_free(bio);
   tls_error(string_sprintf("Could not read tls_dhparams \"%s\"", dhexpanded),
-      host, NULL);
+      host, NULL, errstr);
   return FALSE;
   }
 
+/* note: our default limit of 2236 is not a multiple of 8; the limit comes from
+ * an NSS limit, and the GnuTLS APIs handle bit-sizes fine, so we went with
+ * 2236.  But older OpenSSL can only report in bytes (octets), not bits.
+ * If someone wants to dance at the edge, then they can raise the limit or use
+ * current libraries. */
+#ifdef EXIM_HAVE_OPENSSL_DH_BITS
+/* Added in commit 26c79d5641d; `git describe --contains` says OpenSSL_1_1_0-pre1~1022
+ * This predates OpenSSL_1_1_0 (before a, b, ...) so is in all 1.1.0 */
+dh_bitsize = DH_bits(dh);
+#else
+dh_bitsize = 8 * DH_size(dh);
+#endif
+
 /* Even if it is larger, we silently return success rather than cause things
  * to fail out, so that a too-large DH will not knock out all TLS; it's a
  * debatable choice. */
-if ((8*DH_size(dh)) > tls_dh_max_bits)
+if (dh_bitsize > tls_dh_max_bits)
   {
   DEBUG(D_tls)
-    debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d",
-        8*DH_size(dh), tls_dh_max_bits);
+    debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d\n",
+        dh_bitsize, tls_dh_max_bits);
   }
 else
   {
   SSL_CTX_set_tmp_dh(sctx, dh);
   DEBUG(D_tls)
     debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
-      dhexpanded ? dhexpanded : US"default", 8*DH_size(dh));
+      dhexpanded ? dhexpanded : US"default", dh_bitsize);
   }
 
 DH_free(dh);
@@ -455,142 +642,119 @@ return TRUE;
 
 
 
-#ifdef EXPERIMENTAL_OCSP
 /*************************************************
-*       Load OCSP information into state         *
+*               Initialize for ECDH              *
 *************************************************/
 
-/* Called to load the server OCSP response from the given file into memory, once
-caller has determined this is needed.  Checks validity.  Debugs a message
-if invalid.
+/* Load parameters for ECDH encryption.
 
-ASSUMES: single response, for single cert.
+For now, we stick to NIST P-256 because: it's simple and easy to configure;
+it avoids any patent issues that might bite redistributors; despite events in
+the news and concerns over curve choices, we're not cryptographers, we're not
+pretending to be, and this is "good enough" to be better than no support,
+protecting against most adversaries.  Given another year or two, there might
+be sufficient clarity about a "right" way forward to let us make an informed
+decision, instead of a knee-jerk reaction.
+
+Longer-term, we should look at supporting both various named curves and
+external files generated with "openssl ecparam", much as we do for init_dh().
+We should also support "none" as a value, to explicitly avoid initialisation.
+
+Patches welcome.
 
 Arguments:
-  sctx            the SSL_CTX* to update
-  cbinfo          various parts of session state
-  expanded        the filename putatively holding an OCSP response
+  sctx      The current SSL CTX (inbound or outbound)
+  host      connected host, if client; NULL if server
+  errstr    error string pointer
 
+Returns:    TRUE if OK (nothing to set up, or setup worked)
 */
 
-static void
-ocsp_load_response(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo, const uschar *expanded)
+static BOOL
+init_ecdh(SSL_CTX * sctx, host_item * host, uschar ** errstr)
 {
-BIO *bio;
-OCSP_RESPONSE *resp;
-OCSP_BASICRESP *basic_response;
-OCSP_SINGLERESP *single_response;
-ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
-X509_STORE *store;
-unsigned long verify_flags;
-int status, reason, i;
+#ifdef OPENSSL_NO_ECDH
+return TRUE;
+#else
 
-cbinfo->u_ocsp.server.file_expanded = string_copy(expanded);
-if (cbinfo->u_ocsp.server.response)
-  {
-  OCSP_RESPONSE_free(cbinfo->u_ocsp.server.response);
-  cbinfo->u_ocsp.server.response = NULL;
-  }
+EC_KEY * ecdh;
+uschar * exp_curve;
+int nid;
+BOOL rv;
 
-bio = BIO_new_file(CS cbinfo->u_ocsp.server.file_expanded, "rb");
-if (!bio)
-  {
-  DEBUG(D_tls) debug_printf("Failed to open OCSP response file \"%s\"\n",
-      cbinfo->u_ocsp.server.file_expanded);
-  return;
-  }
+if (host)      /* No ECDH setup for clients, only for servers */
+  return TRUE;
 
-resp = d2i_OCSP_RESPONSE_bio(bio, NULL);
-BIO_free(bio);
-if (!resp)
-  {
-  DEBUG(D_tls) debug_printf("Error reading OCSP response.\n");
-  return;
-  }
+# ifndef EXIM_HAVE_ECDH
+DEBUG(D_tls)
+  debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
+return TRUE;
+# else
 
-status = OCSP_response_status(resp);
-if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
-  {
-  DEBUG(D_tls) debug_printf("OCSP response not valid: %s (%d)\n",
-      OCSP_response_status_str(status), status);
-  goto bad;
-  }
+if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
+  return FALSE;
+if (!exp_curve || !*exp_curve)
+  return TRUE;
 
-basic_response = OCSP_response_get1_basic(resp);
-if (!basic_response)
+/* "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)
+ * OpenSSL >= 1.1.0: we do not set anything, the libray does autoselection
+ *                   https://github.com/openssl/openssl/commit/fe6ef2472db933f01b59cad82aa925736935984b
+ */
+if (Ustrcmp(exp_curve, "auto") == 0)
   {
-  DEBUG(D_tls)
-    debug_printf("OCSP response parse error: unable to extract basic response.\n");
-  goto bad;
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+  DEBUG(D_tls) debug_printf(
+    "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");
+  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");
+  return TRUE;
+# endif
+#endif
   }
 
-store = SSL_CTX_get_cert_store(sctx);
-verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */
-
-/* May need to expose ability to adjust those flags?
-OCSP_NOSIGS OCSP_NOVERIFY OCSP_NOCHAIN OCSP_NOCHECKS OCSP_NOEXPLICIT
-OCSP_TRUSTOTHER OCSP_NOINTERN */
-
-i = OCSP_basic_verify(basic_response, NULL, store, verify_flags);
-if (i <= 0)
+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
+   )
   {
-  DEBUG(D_tls) {
-    ERR_error_string(ERR_get_error(), ssl_errstring);
-    debug_printf("OCSP response verify failure: %s\n", US ssl_errstring);
-    }
-  goto bad;
+  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
+    host, NULL, errstr);
+  return FALSE;
   }
 
-/* Here's the simplifying assumption: there's only one response, for the
-one certificate we use, and nothing for anything else in a chain.  If this
-proves false, we need to extract a cert id from our issued cert
-(tls_certificate) and use that for OCSP_resp_find_status() (which finds the
-right cert in the stack and then calls OCSP_single_get0_status()).
-
-I'm hoping to avoid reworking a bunch more of how we handle state here. */
-single_response = OCSP_resp_get0(basic_response, 0);
-if (!single_response)
+if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
   {
-  DEBUG(D_tls)
-    debug_printf("Unable to get first response from OCSP basic response.\n");
-  goto bad;
+  tls_error(US"Unable to create ec curve", host, NULL, errstr);
+  return FALSE;
   }
 
-status = OCSP_single_get0_status(single_response, &reason, &rev, &thisupd, &nextupd);
-if (status != V_OCSP_CERTSTATUS_GOOD)
-  {
-  DEBUG(D_tls) debug_printf("OCSP response bad cert status: %s (%d) %s (%d)\n",
-      OCSP_cert_status_str(status), status,
-      OCSP_crl_reason_str(reason), reason);
-  goto bad;
-  }
+/* The "tmp" in the name here refers to setting a temporary key
+not to the stability of the interface. */
 
-if (!OCSP_check_validity(thisupd, nextupd, EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
-  {
-  DEBUG(D_tls) debug_printf("OCSP status invalid times.\n");
-  goto bad;
-  }
+if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
+  tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), host, NULL, errstr);
+else
+  DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
 
-supply_response:
-cbinfo->u_ocsp.server.response = resp;
-return;
+EC_KEY_free(ecdh);
+return !rv;
 
-bad:
-if (running_in_test_harness)
-  {
-  extern char ** environ;
-  uschar ** p;
-  for (p = USS environ; *p != NULL; p++)
-    if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0)
-      {
-      DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n");
-      goto supply_response;
-      }
-  }
-return;
+# endif        /*EXIM_HAVE_ECDH*/
+#endif /*OPENSSL_NO_ECDH*/
 }
-#endif /*EXPERIMENTAL_OCSP*/
-
 
 
 
@@ -598,1054 +762,3343 @@ return;
 *        Expand key and cert file specs          *
 *************************************************/
 
-/* Called once during tls_init and possibly again during TLS setup, for a
-new context, if Server Name Indication was used and tls_sni was seen in
-the certificate string.
-
+/*
 Arguments:
-  sctx            the SSL_CTX* to update
-  cbinfo          various parts of session state
+  s          SSL connection (not used)
+  export     not used
+  keylength  keylength
 
-Returns:          OK/DEFER/FAIL
+Returns:     pointer to generated key
 */
 
-static int
-tls_expand_session_files(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo)
+static RSA *
+rsa_callback(SSL *s, int export, int keylength)
 {
-uschar *expanded;
+RSA *rsa_key;
+#ifdef EXIM_HAVE_RSA_GENKEY_EX
+BIGNUM *bn = BN_new();
+#endif
 
-if (cbinfo->certificate == NULL)
-  return OK;
+DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength);
 
-if (Ustrstr(cbinfo->certificate, US"tls_sni") ||
-    Ustrstr(cbinfo->certificate, US"tls_in_sni") ||
-    Ustrstr(cbinfo->certificate, US"tls_out_sni")
+#ifdef EXIM_HAVE_RSA_GENKEY_EX
+if (  !BN_set_word(bn, (unsigned long)RSA_F4)
+   || !(rsa_key = RSA_new())
+   || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL)
    )
-  reexpand_tls_files_for_sni = TRUE;
-
-if (!expand_check(cbinfo->certificate, US"tls_certificate", &expanded))
-  return DEFER;
+#else
+if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL)))
+#endif
 
-if (expanded != NULL)
   {
-  DEBUG(D_tls) debug_printf("tls_certificate file %s\n", expanded);
-  if (!SSL_CTX_use_certificate_chain_file(sctx, CS expanded))
-    return tls_error(string_sprintf(
-      "SSL_CTX_use_certificate_chain_file file=%s", expanded),
-        cbinfo->host, NULL);
+  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+  log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s",
+    ssl_errstring);
+  return NULL;
   }
+return rsa_key;
+}
 
-if (cbinfo->privatekey != NULL &&
-    !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded))
-  return DEFER;
-
-/* If expansion was forced to fail, key_expanded will be NULL. If the result
-of the expansion is an empty string, ignore it also, and assume the private
-key is in the same file as the certificate. */
 
-if (expanded != NULL && *expanded != 0)
-  {
-  DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", expanded);
-  if (!SSL_CTX_use_PrivateKey_file(sctx, CS expanded, SSL_FILETYPE_PEM))
-    return tls_error(string_sprintf(
-      "SSL_CTX_use_PrivateKey_file file=%s", expanded), cbinfo->host, NULL);
-  }
 
-#ifdef EXPERIMENTAL_OCSP
-if (cbinfo->is_server &&  cbinfo->u_ocsp.server.file != NULL)
-  {
-  if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded))
-    return DEFER;
+/* Create and install a selfsigned certificate, for use in server mode */
+/*XXX we could arrange to call this during prelo for a null tls_certificate option.
+The normal cache inval + relo will suffice.
+Just need a timer for inval. */
 
-  if (expanded != NULL && *expanded != 0)
-    {
-    DEBUG(D_tls) debug_printf("tls_ocsp_file %s\n", expanded);
-    if (cbinfo->u_ocsp.server.file_expanded &&
-        (Ustrcmp(expanded, cbinfo->u_ocsp.server.file_expanded) == 0))
-      {
-      DEBUG(D_tls)
-        debug_printf("tls_ocsp_file value unchanged, using existing values.\n");
-      } else {
-        ocsp_load_response(sctx, cbinfo, expanded);
-      }
-    }
-  }
-#endif
+static int
+tls_install_selfsign(SSL_CTX * sctx, uschar ** errstr)
+{
+X509 * x509 = NULL;
+EVP_PKEY * pkey;
+RSA * rsa;
+X509_NAME * name;
+uschar * where;
+
+DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n");
+where = US"allocating pkey";
+if (!(pkey = EVP_PKEY_new()))
+  goto err;
+
+where = US"allocating cert";
+if (!(x509 = X509_new()))
+  goto err;
+
+where = US"generating pkey";
+if (!(rsa = rsa_callback(NULL, 0, 2048)))
+  goto err;
+
+where = US"assigning pkey";
+if (!EVP_PKEY_assign_RSA(pkey, rsa))
+  goto err;
+
+X509_set_version(x509, 2);                             /* N+1 - version 3 */
+ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
+X509_gmtime_adj(X509_get_notBefore(x509), 0);
+X509_gmtime_adj(X509_get_notAfter(x509), (long)2 * 60 * 60);   /* 2 hour */
+X509_set_pubkey(x509, pkey);
+
+name = X509_get_subject_name(x509);
+X509_NAME_add_entry_by_txt(name, "C",
+                         MBSTRING_ASC, CUS "UK", -1, -1, 0);
+X509_NAME_add_entry_by_txt(name, "O",
+                         MBSTRING_ASC, CUS "Exim Developers", -1, -1, 0);
+X509_NAME_add_entry_by_txt(name, "CN",
+                         MBSTRING_ASC, CUS smtp_active_hostname, -1, -1, 0);
+X509_set_issuer_name(x509, name);
+
+where = US"signing cert";
+if (!X509_sign(x509, pkey, EVP_md5()))
+  goto err;
+
+where = US"installing selfsign cert";
+if (!SSL_CTX_use_certificate(sctx, x509))
+  goto err;
+
+where = US"installing selfsign key";
+if (!SSL_CTX_use_PrivateKey(sctx, pkey))
+  goto err;
 
 return OK;
+
+err:
+  (void) tls_error(where, NULL, NULL, errstr);
+  if (x509) X509_free(x509);
+  if (pkey) EVP_PKEY_free(pkey);
+  return DEFER;
 }
 
 
 
 
+
+
+
 /*************************************************
-*            Callback to handle SNI              *
+*           Information callback                 *
 *************************************************/
 
-/* Called when acting as server during the TLS session setup if a Server Name
-Indication extension was sent by the client.
-
-API documentation is OpenSSL s_server.c implementation.
+/* The SSL library functions call this from time to time to indicate what they
+are doing. We copy the string to the debugging output when TLS debugging has
+been requested.
 
 Arguments:
-  s               SSL* of the current session
-  ad              unknown (part of OpenSSL API) (unused)
-  arg             Callback of "our" registered data
+  s         the SSL connection
+  where
+  ret
 
-Returns:          SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK}
+Returns:    nothing
 */
 
-#ifdef EXIM_HAVE_OPENSSL_TLSEXT
-static int
-tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
+static void
+info_callback(SSL *s, int where, int ret)
 {
-const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
-tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
-int rc;
-int old_pool = store_pool;
+DEBUG(D_tls)
+  {
+  const uschar * str;
 
-if (!servername)
-  return SSL_TLSEXT_ERR_OK;
+  if (where & SSL_ST_CONNECT)
+     str = US"SSL_connect";
+  else if (where & SSL_ST_ACCEPT)
+     str = US"SSL_accept";
+  else
+     str = US"SSL info (undefined)";
+
+  if (where & SSL_CB_LOOP)
+     debug_printf("%s: %s\n", str, SSL_state_string_long(s));
+  else if (where & SSL_CB_ALERT)
+    debug_printf("SSL3 alert %s:%s:%s\n",
+         str = where & SSL_CB_READ ? US"read" : US"write",
+         SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
+  else if (where & SSL_CB_EXIT)
+    {
+    if (ret == 0)
+      debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s));
+    else if (ret < 0)
+      debug_printf("%s: error in %s\n", str, SSL_state_string_long(s));
+    }
+  else if (where & SSL_CB_HANDSHAKE_START)
+     debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s));
+  else if (where & SSL_CB_HANDSHAKE_DONE)
+     debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s));
+  }
+}
 
-DEBUG(D_tls) debug_printf("Received TLS SNI \"%s\"%s\n", servername,
-    reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)");
+#ifdef OPENSSL_HAVE_KEYLOG_CB
+static void
+keylog_callback(const SSL *ssl, const char *line)
+{
+char * filename;
+FILE * fp;
+DEBUG(D_tls) debug_printf("%.200s\n", line);
+if (!(filename = getenv("SSLKEYLOGFILE"))) return;
+if (!(fp = fopen(filename, "a"))) return;
+fprintf(fp, "%s\n", line);
+fclose(fp);
+}
+#endif
 
-/* Make the extension value available for expansion */
-store_pool = POOL_PERM;
-tls_in.sni = string_copy(US servername);
-store_pool = old_pool;
 
-if (!reexpand_tls_files_for_sni)
-  return SSL_TLSEXT_ERR_OK;
 
-/* Can't find an SSL_CTX_clone() or equivalent, so we do it manually;
-not confident that memcpy wouldn't break some internal reference counting.
-Especially since there's a references struct member, which would be off. */
 
-server_sni = SSL_CTX_new(SSLv23_server_method());
-if (!server_sni)
+
+#ifndef DISABLE_EVENT
+static int
+verify_event(tls_support * tlsp, X509 * cert, int depth, const uschar * dn,
+  BOOL *calledp, const BOOL *optionalp, const uschar * what)
+{
+uschar * ev;
+uschar * yield;
+X509 * old_cert;
+
+ev = tlsp == &tls_out ? client_static_state->event_action : event_action;
+if (ev)
   {
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring);
-  return SSL_TLSEXT_ERR_NOACK;
+  DEBUG(D_tls) debug_printf("verify_event: %s %d\n", what, depth);
+  old_cert = tlsp->peercert;
+  tlsp->peercert = X509_dup(cert);
+  /* NB we do not bother setting peerdn */
+  if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth))))
+    {
+    log_write(0, LOG_MAIN, "[%s] %s verify denied by event-action: "
+               "depth=%d cert=%s: %s",
+             tlsp == &tls_out ? deliver_host_address : sender_host_address,
+             what, depth, dn, yield);
+    *calledp = TRUE;
+    if (!*optionalp)
+      {
+      if (old_cert) tlsp->peercert = old_cert; /* restore 1st failing cert */
+      return 1;                            /* reject (leaving peercert set) */
+      }
+    DEBUG(D_tls) debug_printf("Event-action verify failure overridden "
+      "(host in tls_try_verify_hosts)\n");
+    tlsp->verify_override = TRUE;
+    }
+  X509_free(tlsp->peercert);
+  tlsp->peercert = old_cert;
   }
+return 0;
+}
+#endif
 
-/* Not sure how many of these are actually needed, since SSL object
-already exists.  Might even need this selfsame callback, for reneg? */
+/*************************************************
+*        Callback for verification               *
+*************************************************/
+
+/* The SSL library does certificate verification if set up to do so. This
+callback has the current yes/no state is in "state". If verification succeeded,
+we set the certificate-verified flag. If verification failed, what happens
+depends on whether the client is required to present a verifiable certificate
+or not.
+
+If verification is optional, we change the state to yes, but still log the
+verification error. For some reason (it really would help to have proper
+documentation of OpenSSL), this callback function then gets called again, this
+time with state = 1.  We must take care not to set the private verified flag on
+the second time through.
+
+Note: this function is not called if the client fails to present a certificate
+when asked. We get here only if a certificate has been received. Handling of
+optional verification for this case is done when requesting SSL to verify, by
+setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT in the non-optional case.
+
+May be called multiple times for different issues with a certificate, even
+for a given "depth" in the certificate chain.
+
+Arguments:
+  preverify_ok current yes/no state as 1/0
+  x509ctx      certificate information.
+  tlsp         per-direction (client vs. server) support data
+  calledp      has-been-called flag
+  optionalp    verification-is-optional flag
+
+Returns:     0 if verification should fail, otherwise 1
+*/
+
+static int
+verify_callback(int preverify_ok, X509_STORE_CTX * x509ctx,
+  tls_support * tlsp, BOOL * calledp, BOOL * optionalp)
+{
+X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
+int depth = X509_STORE_CTX_get_error_depth(x509ctx);
+uschar dn[256];
 
-SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(server_ctx));
-SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(server_ctx));
-SSL_CTX_set_options(server_sni, SSL_CTX_get_options(server_ctx));
-SSL_CTX_set_timeout(server_sni, SSL_CTX_get_timeout(server_ctx));
-SSL_CTX_set_tlsext_servername_callback(server_sni, tls_servername_cb);
-SSL_CTX_set_tlsext_servername_arg(server_sni, cbinfo);
-if (cbinfo->server_cipher_list)
-  SSL_CTX_set_cipher_list(server_sni, CS cbinfo->server_cipher_list);
-#ifdef EXPERIMENTAL_OCSP
-if (cbinfo->u_ocsp.server.file)
+if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)))
   {
-  SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
-  SSL_CTX_set_tlsext_status_arg(server_sni, cbinfo);
+  DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n");
+  log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
+    tlsp == &tls_out ? deliver_host_address : sender_host_address);
+  return 0;
   }
-#endif
+dn[sizeof(dn)-1] = '\0';
 
-rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE, verify_callback_server);
-if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+tlsp->verify_override = FALSE;
+if (preverify_ok == 0)
+  {
+  uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])",
+      *verify_mode, sender_host_address)
+    : US"";
+  log_write(0, LOG_MAIN, "[%s] SSL verify error%s: depth=%d error=%s cert=%s",
+    tlsp == &tls_out ? deliver_host_address : sender_host_address,
+    extra, depth,
+    X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)), dn);
+  *calledp = TRUE;
+  if (!*optionalp)
+    {
+    if (!tlsp->peercert)
+      tlsp->peercert = X509_dup(cert); /* record failing cert */
+    return 0;                          /* reject */
+    }
+  DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
+    "tls_try_verify_hosts)\n");
+  tlsp->verify_override = TRUE;
+  }
 
-/* do this after setup_certs, because this can require the certs for verifying
-OCSP information. */
-rc = tls_expand_session_files(server_sni, cbinfo);
-if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+else if (depth != 0)
+  {
+  DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, dn);
+#ifndef DISABLE_OCSP
+  if (tlsp == &tls_out && client_static_state->u_ocsp.client.verify_store)
+    {  /* client, wanting stapling  */
+    /* Add the server cert's signing chain as the one
+    for the verification of the OCSP stapled information. */
 
-rc = init_dh(server_sni, cbinfo->dhparam, NULL);
-if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+    if (!X509_STORE_add_cert(client_static_state->u_ocsp.client.verify_store,
+                             cert))
+      ERR_clear_error();
+    sk_X509_push(client_static_state->verify_stack, cert);
+    }
+#endif
+#ifndef DISABLE_EVENT
+    if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL"))
+      return 0;                                /* reject, with peercert set */
+#endif
+  }
+else
+  {
+  const uschar * verify_cert_hostnames;
 
-DEBUG(D_tls) debug_printf("Switching SSL context.\n");
-SSL_set_SSL_CTX(s, server_sni);
+  if (  tlsp == &tls_out
+     && ((verify_cert_hostnames = client_static_state->verify_cert_hostnames)))
+       /* client, wanting hostname check */
+    {
 
-return SSL_TLSEXT_ERR_OK;
-}
-#endif /* EXIM_HAVE_OPENSSL_TLSEXT */
+#ifdef EXIM_HAVE_OPENSSL_CHECKHOST
+# ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
+#  define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0
+# endif
+# ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
+#  define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0
+# endif
+    int sep = 0;
+    const uschar * list = verify_cert_hostnames;
+    uschar * name;
+    int rc;
+    while ((name = string_nextinlist(&list, &sep, NULL, 0)))
+      if ((rc = X509_check_host(cert, CCS name, 0,
+                 X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
+                 | X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS,
+                 NULL)))
+       {
+       if (rc < 0)
+         {
+         log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
+           tlsp == &tls_out ? deliver_host_address : sender_host_address);
+         name = NULL;
+         }
+       break;
+       }
+    if (!name)
+#else
+    if (!tls_is_name_for_cert(verify_cert_hostnames, cert))
+#endif
+      {
+      uschar * extra = verify_mode
+        ? string_sprintf(" (during %c-verify for [%s])",
+         *verify_mode, sender_host_address)
+       : US"";
+      log_write(0, LOG_MAIN,
+       "[%s] SSL verify error%s: certificate name mismatch: DN=\"%s\" H=\"%s\"",
+       tlsp == &tls_out ? deliver_host_address : sender_host_address,
+       extra, dn, verify_cert_hostnames);
+      *calledp = TRUE;
+      if (!*optionalp)
+       {
+       if (!tlsp->peercert)
+         tlsp->peercert = X509_dup(cert);      /* record failing cert */
+       return 0;                               /* reject */
+       }
+      DEBUG(D_tls) debug_printf("SSL verify name failure overridden (host in "
+       "tls_try_verify_hosts)\n");
+      tlsp->verify_override = TRUE;
+      }
+    }
 
+#ifndef DISABLE_EVENT
+  if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL"))
+    return 0;                          /* reject, with peercert set */
+#endif
 
+  DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n",
+    *calledp ? "" : " authenticated", dn);
+  *calledp = TRUE;
+  }
 
+return 1;   /* accept, at least for this level */
+}
 
-#ifdef EXPERIMENTAL_OCSP
+static int
+verify_callback_client(int preverify_ok, X509_STORE_CTX *x509ctx)
+{
+return verify_callback(preverify_ok, x509ctx, &tls_out,
+  &client_verify_callback_called, &client_verify_optional);
+}
 
-/*************************************************
-*        Callback to handle OCSP Stapling        *
-*************************************************/
+static int
+verify_callback_server(int preverify_ok, X509_STORE_CTX *x509ctx)
+{
+return verify_callback(preverify_ok, x509ctx, &tls_in,
+  &server_verify_callback_called, &server_verify_optional);
+}
 
-/* Called when acting as server during the TLS session setup if the client
-requests OCSP information with a Certificate Status Request.
 
-Documentation via openssl s_server.c and the Apache patch from the OpenSSL
-project.
+#ifdef SUPPORT_DANE
 
+/* This gets called *by* the dane library verify callback, which interposes
+itself.
 */
-
 static int
-tls_server_stapling_cb(SSL *s, void *arg)
+verify_callback_client_dane(int preverify_ok, X509_STORE_CTX * x509ctx)
 {
-const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
-uschar *response_der;
-int response_der_len;
+X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
+uschar dn[256];
+int depth = X509_STORE_CTX_get_error_depth(x509ctx);
+#ifndef DISABLE_EVENT
+BOOL dummy_called, optional = FALSE;
+#endif
 
-if (log_extra_selector & LX_tls_cipher)
-  log_write(0, LOG_MAIN, "[%s] Recieved OCSP stapling req;%s responding",
-    sender_host_address, cbinfo->u_ocsp.server.response ? "":" not");
-else
-  DEBUG(D_tls) debug_printf("Received TLS status request (OCSP stapling); %s response.",
-    cbinfo->u_ocsp.server.response ? "have" : "lack");
+if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)))
+  {
+  DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n");
+  log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
+    deliver_host_address);
+  return 0;
+  }
+dn[sizeof(dn)-1] = '\0';
 
-tls_in.ocsp = OCSP_NOT_RESP;
-if (!cbinfo->u_ocsp.server.response)
-  return SSL_TLSEXT_ERR_NOACK;
+DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n",
+  preverify_ok ? "ok":"BAD", depth, dn);
 
-response_der = NULL;
-response_der_len = i2d_OCSP_RESPONSE(cbinfo->u_ocsp.server.response,
-                     &response_der);
-if (response_der_len <= 0)
-  return SSL_TLSEXT_ERR_NOACK;
+#ifndef DISABLE_EVENT
+  if (verify_event(&tls_out, cert, depth, dn,
+         &dummy_called, &optional, US"DANE"))
+    return 0;                          /* reject, with peercert set */
+#endif
 
-SSL_set_tlsext_status_ocsp_resp(server_ssl, response_der, response_der_len);
-tls_in.ocsp = OCSP_VFIED;
-return SSL_TLSEXT_ERR_OK;
+if (preverify_ok == 1)
+  {
+  tls_out.dane_verified = TRUE;
+#ifndef DISABLE_OCSP
+  if (client_static_state->u_ocsp.client.verify_store)
+    {  /* client, wanting stapling  */
+    /* Add the server cert's signing chain as the one
+    for the verification of the OCSP stapled information. */
+
+    if (!X509_STORE_add_cert(client_static_state->u_ocsp.client.verify_store,
+                             cert))
+      ERR_clear_error();
+    sk_X509_push(client_static_state->verify_stack, cert);
+    }
+#endif
+  }
+else
+  {
+  int err = X509_STORE_CTX_get_error(x509ctx);
+  DEBUG(D_tls)
+    debug_printf(" - err %d '%s'\n", err, X509_verify_cert_error_string(err));
+  if (err == X509_V_ERR_APPLICATION_VERIFICATION)
+    preverify_ok = 1;
+  }
+return preverify_ok;
 }
 
+#endif /*SUPPORT_DANE*/
+
+
+#ifndef DISABLE_OCSP
+/*************************************************
+*       Load OCSP information into state         *
+*************************************************/
+/* Called to load the server OCSP response from the given file into memory, once
+caller has determined this is needed.  Checks validity.  Debugs a message
+if invalid.
+
+ASSUMES: single response, for single cert.
+
+Arguments:
+  state           various parts of session state
+  filename        the filename putatively holding an OCSP response
+  is_pem         file is PEM format; otherwise is DER
+*/
 
 static void
-time_print(BIO * bp, const char * str, ASN1_GENERALIZEDTIME * time)
+ocsp_load_response(exim_openssl_state_st * state, const uschar * filename,
+  BOOL is_pem)
 {
-BIO_printf(bp, "\t%s: ", str);
-ASN1_GENERALIZEDTIME_print(bp, time);
-BIO_puts(bp, "\n");
-}
+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;
 
-static int
-tls_client_stapling_cb(SSL *s, void *arg)
-{
-tls_ext_ctx_cb * cbinfo = arg;
-const unsigned char * p;
-int len;
-OCSP_RESPONSE * rsp;
-OCSP_BASICRESP * bs;
-int i;
+DEBUG(D_tls)
+  debug_printf("tls_ocsp_file (%s)  '%s'\n", is_pem ? "PEM" : "DER", filename);
 
-DEBUG(D_tls) debug_printf("Received TLS status response (OCSP stapling):");
-len = SSL_get_tlsext_status_ocsp_resp(s, &p);
-if(!p)
- {
-  /* Expect this when we requested ocsp but got none */
-  if (  cbinfo->u_ocsp.client.verify_required
-     && log_extra_selector & LX_tls_cipher)
-    log_write(0, LOG_MAIN, "Received TLS status callback, null content");
-  else
-    DEBUG(D_tls) debug_printf(" null\n");
-  return cbinfo->u_ocsp.client.verify_required ? 0 : 1;
- }
-tls_out.ocsp = OCSP_NOT_VFY;
-if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
- {
-  if (log_extra_selector & LX_tls_cipher)
-    log_write(0, LOG_MAIN, "Received TLS status response, parse error");
-  else
-    DEBUG(D_tls) debug_printf(" parse error\n");
-  return 0;
- }
+if (!filename || !*filename) return;
 
-if(!(bs = OCSP_response_get1_basic(rsp)))
+ERR_clear_error();
+if (!(bio = BIO_new_file(CS filename, "rb")))
   {
-  if (log_extra_selector & LX_tls_cipher)
-    log_write(0, LOG_MAIN, "Received TLS status response, error parsing response");
-  else
-    DEBUG(D_tls) debug_printf(" error parsing response\n");
-  OCSP_RESPONSE_free(rsp);
-  return 0;
+  log_write(0, LOG_MAIN|LOG_PANIC,
+    "Failed to open OCSP response file \"%s\": %.100s",
+    filename, ERR_reason_error_string(ERR_get_error()));
+  return;
   }
 
-/* We'd check the nonce here if we'd put one in the request. */
-/* However that would defeat cacheability on the server so we don't. */
+if (is_pem)
+  {
+  uschar * data, * freep;
+  char * dummy;
+  long len;
+  if (!PEM_read_bio(bio, &dummy, &dummy, &data, &len))
+    {
+    log_write(0, LOG_MAIN|LOG_PANIC, "Failed to read PEM file \"%s\": %.100s",
+      filename, ERR_reason_error_string(ERR_get_error()));
+    return;
+    }
+  freep = data;
+  resp = d2i_OCSP_RESPONSE(NULL, CUSS &data, len);
+  OPENSSL_free(freep);
+  }
+else
+  resp = d2i_OCSP_RESPONSE_bio(bio, NULL);
+BIO_free(bio);
 
+if (!resp)
+  {
+  log_write(0, LOG_MAIN|LOG_PANIC, "Error reading OCSP response from \"%s\": %s",
+      filename, ERR_reason_error_string(ERR_get_error()));
+  return;
+  }
 
-/* This section of code reworked from OpenSSL apps source;
-   The OpenSSL Project retains copyright:
-   Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+if ((status = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+  {
+  DEBUG(D_tls) debug_printf("OCSP response not valid: %s (%d)\n",
+      OCSP_response_status_str(status), status);
+  goto bad;
+  }
+
+#ifdef notdef
+  {
+  BIO * bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
+  OCSP_RESPONSE_print(bp, resp, 0);  /* extreme debug: stapling content */
+  BIO_free(bp);
+  }
+#endif
+
+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 */
+
+/* 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.
+
+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.
+
+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) ? ]
+We do not free the stack since it could be needed a second time for
+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)
+  {
+  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;
+  }
+
+/* Here's the simplifying assumption: there's only one response, for the
+one certificate we use, and nothing for anything else in a chain.  If this
+proves false, we need to extract a cert id from our issued cert
+(tls_certificate) and use that for OCSP_resp_find_status() (which finds the
+right cert in the stack and then calls OCSP_single_get0_status()).
+
+I'm hoping to avoid reworking a bunch more of how we handle state here.
+
+XXX that will change when we add support for (TLS1.3) whole-chain stapling
 */
+
+if (!(single_response = OCSP_resp_get0(basic_response, 0)))
   {
-    BIO * bp = NULL;
-    OCSP_CERTID *id;
-    int status, reason;
-    ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+  DEBUG(D_tls)
+    debug_printf("Unable to get first response from OCSP basic response.\n");
+  goto bad;
+  }
+
+status = OCSP_single_get0_status(single_response, &reason, &rev, &thisupd, &nextupd);
+if (status != V_OCSP_CERTSTATUS_GOOD)
+  {
+  DEBUG(D_tls) debug_printf("OCSP response bad cert status: %s (%d) %s (%d)\n",
+      OCSP_cert_status_str(status), status,
+      OCSP_crl_reason_str(reason), reason);
+  goto bad;
+  }
+
+if (!OCSP_check_validity(thisupd, nextupd, EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
+  {
+  DEBUG(D_tls) debug_printf("OCSP status invalid times.\n");
+  goto bad;
+  }
+
+supply_response:
+  /* Add the resp to the list used by tls_server_stapling_cb() */
+  {
+  ocsp_resplist ** op = &state->u_ocsp.server.olist, * oentry;
+  while (oentry = *op)
+    op = &oentry->next;
+  *op = oentry = store_get(sizeof(ocsp_resplist), FALSE);
+  oentry->next = NULL;
+  oentry->resp = resp;
+  }
+return;
+
+bad:
+  if (f.running_in_test_harness)
+    {
+    extern char ** environ;
+    if (environ) for (uschar ** p = USS environ; *p; p++)
+      if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0)
+       {
+       DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n");
+       goto supply_response;
+       }
+    }
+return;
+}
+
+
+static void
+ocsp_free_response_list(exim_openssl_state_st * cbinfo)
+{
+for (ocsp_resplist * olist = cbinfo->u_ocsp.server.olist; olist;
+     olist = olist->next)
+  OCSP_RESPONSE_free(olist->resp);
+cbinfo->u_ocsp.server.olist = NULL;
+}
+#endif /*!DISABLE_OCSP*/
+
+
+
+
+
+static int
+tls_add_certfile(SSL_CTX * sctx, exim_openssl_state_st * cbinfo, uschar * file,
+  uschar ** errstr)
+{
+DEBUG(D_tls) debug_printf("tls_certificate file '%s'\n", file);
+if (!SSL_CTX_use_certificate_chain_file(sctx, CS file))
+  return tls_error(string_sprintf(
+    "SSL_CTX_use_certificate_chain_file file=%s", file),
+      cbinfo->host, NULL, errstr);
+return 0;
+}
+
+static int
+tls_add_pkeyfile(SSL_CTX * sctx, exim_openssl_state_st * cbinfo, uschar * file,
+  uschar ** errstr)
+{
+DEBUG(D_tls) debug_printf("tls_privatekey file  '%s'\n", file);
+if (!SSL_CTX_use_PrivateKey_file(sctx, CS file, SSL_FILETYPE_PEM))
+  return tls_error(string_sprintf(
+    "SSL_CTX_use_PrivateKey_file file=%s", file), cbinfo->host, NULL, errstr);
+return 0;
+}
+
+
+
+
+/* Called once during tls_init and possibly again during TLS setup, for a
+new context, if Server Name Indication was used and tls_sni was seen in
+the certificate string.
+
+Arguments:
+  sctx            the SSL_CTX* to update
+  state           various parts of session state
+  errstr         error string pointer
+
+Returns:          OK/DEFER/FAIL
+*/
+
+static int
+tls_expand_session_files(SSL_CTX * sctx, exim_openssl_state_st * state,
+  uschar ** errstr)
+{
+uschar * expanded;
+
+if (!state->certificate)
+  {
+  if (!state->is_server)               /* client */
+    return OK;
+                                       /* server */
+  if (tls_install_selfsign(sctx, errstr) != OK)
+    return DEFER;
+  }
+else
+  {
+  int err;
+
+  if ( !reexpand_tls_files_for_sni
+     && (  Ustrstr(state->certificate, US"tls_sni")
+       || Ustrstr(state->certificate, US"tls_in_sni")
+       || Ustrstr(state->certificate, US"tls_out_sni")
+     )  )
+    reexpand_tls_files_for_sni = TRUE;
+
+  if (!expand_check(state->certificate, US"tls_certificate", &expanded, errstr))
+    return DEFER;
+
+  if (expanded)
+    if (state->is_server)
+      {
+      const uschar * file_list = expanded;
+      int sep = 0;
+      uschar * file;
+#ifndef DISABLE_OCSP
+      const uschar * olist = state->u_ocsp.server.file;
+      int osep = 0;
+      uschar * ofile;
+      BOOL fmt_pem = FALSE;
+
+      if (olist)
+       if (!expand_check(olist, US"tls_ocsp_file", USS &olist, errstr))
+         return DEFER;
+      if (olist && !*olist)
+       olist = NULL;
+
+      if (  state->u_ocsp.server.file_expanded && olist
+        && (Ustrcmp(olist, state->u_ocsp.server.file_expanded) == 0))
+       {
+       DEBUG(D_tls) debug_printf(" - value unchanged, using existing values\n");
+       olist = NULL;
+       }
+      else
+       {
+       ocsp_free_response_list(state);
+       state->u_ocsp.server.file_expanded = olist;
+       }
+#endif
+
+      while (file = string_nextinlist(&file_list, &sep, NULL, 0))
+       {
+       if ((err = tls_add_certfile(sctx, state, file, errstr)))
+         return err;
+
+#ifndef DISABLE_OCSP
+       if (olist)
+         if ((ofile = string_nextinlist(&olist, &osep, NULL, 0)))
+           {
+           if (Ustrncmp(ofile, US"PEM ", 4) == 0)
+             {
+             fmt_pem = TRUE;
+             ofile += 4;
+             }
+           else if (Ustrncmp(ofile, US"DER ", 4) == 0)
+             {
+             fmt_pem = FALSE;
+             ofile += 4;
+             }
+           ocsp_load_response(state, ofile, fmt_pem);
+           }
+         else
+           DEBUG(D_tls) debug_printf("ran out of ocsp file list\n");
+#endif
+       }
+      }
+    else       /* would there ever be a need for multiple client certs? */
+      if ((err = tls_add_certfile(sctx, state, expanded, errstr)))
+       return err;
+
+  if (  state->privatekey
+     && !expand_check(state->privatekey, US"tls_privatekey", &expanded, errstr))
+    return DEFER;
+
+  /* If expansion was forced to fail, key_expanded will be NULL. If the result
+  of the expansion is an empty string, ignore it also, and assume the private
+  key is in the same file as the certificate. */
+
+  if (expanded && *expanded)
+    if (state->is_server)
+      {
+      const uschar * file_list = expanded;
+      int sep = 0;
+      uschar * file;
+
+      while (file = string_nextinlist(&file_list, &sep, NULL, 0))
+       if ((err = tls_add_pkeyfile(sctx, state, file, errstr)))
+         return err;
+      }
+    else       /* would there ever be a need for multiple client certs? */
+      if ((err = tls_add_pkeyfile(sctx, state, expanded, errstr)))
+       return err;
+  }
+
+return OK;
+}
+
+
+
+
+/**************************************************
+* One-time init credentials for server and client *
+**************************************************/
+
+static int
+server_load_ciphers(SSL_CTX * ctx, exim_openssl_state_st * state,
+  uschar * ciphers, uschar ** errstr)
+{
+for (uschar * s = ciphers; *s; s++ ) if (*s == '_') *s = '-';
+DEBUG(D_tls) debug_printf("required ciphers: %s\n", ciphers);
+if (!SSL_CTX_set_cipher_list(ctx, CS ciphers))
+  return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
+state->server_cipher_list = ciphers;
+return OK;
+}
+
+
+
+static int
+lib_ctx_new(SSL_CTX ** ctxp, host_item * host, uschar ** errstr)
+{
+SSL_CTX * ctx;
+#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
+if (!(ctx = SSL_CTX_new(host ? TLS_client_method() : TLS_server_method())))
+#else
+if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())))
+#endif
+  return tls_error(US"SSL_CTX_new", host, NULL, errstr);
+
+/* Set up the information callback, which outputs if debugging is at a suitable
+level. */
+
+DEBUG(D_tls)
+  {
+  SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
+#if defined(EXIM_HAVE_OPESSL_TRACE) && !defined(OPENSSL_NO_SSL_TRACE)
+  /* this needs a debug build of OpenSSL */
+  SSL_CTX_set_msg_callback(ctx, (void (*)())SSL_trace);
+#endif
+#ifdef OPENSSL_HAVE_KEYLOG_CB
+  SSL_CTX_set_keylog_callback(ctx, (void (*)())keylog_callback);
+#endif
+  }
+
+/* Automatically re-try reads/writes after renegotiation. */
+(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+*ctxp = ctx;
+return OK;
+}
+
+
+static unsigned
+tls_server_creds_init(void)
+{
+SSL_CTX * ctx;
+uschar * dummy_errstr;
+unsigned lifetime = 0;
+
+tls_openssl_init();
+
+state_server.lib_state = null_tls_preload;
+
+if (lib_ctx_new(&ctx, NULL, &dummy_errstr) != OK)
+  return 0;
+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");
+  if (init_dh(ctx, tls_dhparam, NULL, &dummy_errstr))
+    state_server.lib_state.dh = TRUE;
+  }
+if (opt_unset_or_noexpand(tls_eccurve))
+  {
+  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for server\n");
+  if (init_ecdh(ctx, NULL, &dummy_errstr))
+    state_server.lib_state.ecdh = TRUE;
+  }
+
+#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 */
+
+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)
+     && tls_set_watch(tls_verify_certificates, FALSE)
+     && 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;
+    }
+  }
+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))
+  {
+  DEBUG(D_tls) debug_printf("TLS: preloading cipher list for server\n");
+  if (server_load_ciphers(ctx, &state_server, tls_require_ciphers,
+                         &dummy_errstr) == OK)
+    state_server.lib_state.pri_string = TRUE;
+  }
+else
+  DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n");
+return lifetime;
+}
+
+
+
+
+/* Preload whatever creds are static, onto a transport.  The client can then
+just copy the pointer as it starts up.
+Called from the daemon after a cache-invalidate with watch set; called from
+a queue-run startup with watch clear. */
+
+static void
+tls_client_creds_init(transport_instance * t, BOOL watch)
+{
+smtp_transport_options_block * ob = t->options_block;
+exim_openssl_state_st tpt_dummy_state;
+host_item * dummy_host = (host_item *)1;
+uschar * dummy_errstr;
+SSL_CTX * ctx;
+
+tls_openssl_init();
+
+ob->tls_preload = null_tls_preload;
+if (lib_ctx_new(&ctx, dummy_host, &dummy_errstr) != OK)
+  return;
+ob->tls_preload.lib_ctx = ctx;
+
+tpt_dummy_state.lib_state = ob->tls_preload;
+
+if (opt_unset_or_noexpand(tls_dhparam))
+  {
+  DEBUG(D_tls) debug_printf("TLS: preloading DH params for transport '%s'\n", t->name);
+  if (init_dh(ctx, tls_dhparam, NULL, &dummy_errstr))
+    ob->tls_preload.dh = TRUE;
+  }
+if (opt_unset_or_noexpand(tls_eccurve))
+  {
+  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for transport '%s'\n", t->name);
+  if (init_ecdh(ctx, NULL, &dummy_errstr))
+    ob->tls_preload.ecdh = TRUE;
+  }
+
+#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
+if (  opt_set_and_noexpand(ob->tls_certificate)
+   && opt_unset_or_noexpand(ob->tls_privatekey))
+  {
+  if (  !watch
+     || (  tls_set_watch(ob->tls_certificate, FALSE)
+       && tls_set_watch(ob->tls_privatekey, FALSE)
+     )  )
+    {
+    uschar * pkey = ob->tls_privatekey;
+
+    DEBUG(D_tls)
+      debug_printf("TLS: preloading client certs for transport '%s'\n",t->name);
+
+    if (  tls_add_certfile(ctx, &tpt_dummy_state, ob->tls_certificate,
+                                   &dummy_errstr) == 0
+       && tls_add_pkeyfile(ctx, &tpt_dummy_state,
+                                   pkey ? pkey : ob->tls_certificate,
+                                   &dummy_errstr) == 0
+       )
+      ob->tls_preload.conn_certs = TRUE;
+    }
+  }
+else
+  DEBUG(D_tls)
+    debug_printf("TLS: not preloading client certs, for transport '%s'\n", t->name);
+
+
+if (  opt_set_and_noexpand(ob->tls_verify_certificates)
+   && opt_unset_or_noexpand(ob->tls_crl))
+  {
+  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)
+     )
+    {
+    DEBUG(D_tls)
+      debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
+
+    if (setup_certs(ctx, ob->tls_verify_certificates,
+         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);
+
+#endif /*EXIM_HAVE_INOTIFY*/
+}
+
+
+#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
+/* Invalidate the creds cached, by dropping the current ones.
+Call when we notice one of the source files has changed. */
+static void
+tls_server_creds_invalidate(void)
+{
+SSL_CTX_free(state_server.lib_state.lib_ctx);
+state_server.lib_state = null_tls_preload;
+}
+
+
+static void
+tls_client_creds_invalidate(transport_instance * t)
+{
+smtp_transport_options_block * ob = t->options_block;
+SSL_CTX_free(ob->tls_preload.lib_ctx);
+ob->tls_preload = null_tls_preload;
+}
+
+#else
+
+static void
+tls_server_creds_invalidate(void)
+{ return; }
+
+static void
+tls_client_creds_invalidate(transport_instance * t)
+{ return; }
+
+#endif /*EXIM_HAVE_INOTIFY*/
+
+
+/* Extreme debug
+#ifndef DISABLE_OCSP
+void
+x509_store_dump_cert_s_names(X509_STORE * store)
+{
+STACK_OF(X509_OBJECT) * roots= store->objs;
+static uschar name[256];
+
+for (int i= 0; i < sk_X509_OBJECT_num(roots); i++)
+  {
+  X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i);
+  if(tmp_obj->type == X509_LU_X509)
+    {
+    X509_NAME * sn = X509_get_subject_name(tmp_obj->data.x509);
+    if (X509_NAME_oneline(sn, CS name, sizeof(name)))
+      {
+      name[sizeof(name)-1] = '\0';
+      debug_printf(" %s\n", name);
+      }
+    }
+  }
+}
+#endif
+*/
+
+
+#ifndef DISABLE_TLS_RESUME
+/* Manage the keysets used for encrypting the session tickets, on the server. */
+
+typedef struct {                       /* Session ticket encryption key */
+  uschar       name[16];
+
+  const EVP_CIPHER *   aes_cipher;
+  uschar               aes_key[32];    /* size needed depends on cipher. aes_128 implies 128/8 = 16? */
+  const EVP_MD *       hmac_hash;
+  uschar               hmac_key[16];
+  time_t               renew;
+  time_t               expire;
+} exim_stek;
+
+static exim_stek exim_tk;      /* current key */
+static exim_stek exim_tk_old;  /* previous key */
+
+static void
+tk_init(void)
+{
+time_t t = time(NULL);
+
+if (exim_tk.name[0])
+  {
+  if (exim_tk.renew >= t) return;
+  exim_tk_old = exim_tk;
+  }
+
+if (f.running_in_test_harness) ssl_session_timeout = 6;
+
+DEBUG(D_tls) debug_printf("OpenSSL: %s STEK\n", exim_tk.name[0] ? "rotating" : "creating");
+if (RAND_bytes(exim_tk.aes_key, sizeof(exim_tk.aes_key)) <= 0) return;
+if (RAND_bytes(exim_tk.hmac_key, sizeof(exim_tk.hmac_key)) <= 0) return;
+if (RAND_bytes(exim_tk.name+1, sizeof(exim_tk.name)-1) <= 0) return;
+
+exim_tk.name[0] = 'E';
+exim_tk.aes_cipher = EVP_aes_256_cbc();
+exim_tk.hmac_hash = EVP_sha256();
+exim_tk.expire = t + ssl_session_timeout;
+exim_tk.renew = t + ssl_session_timeout/2;
+}
+
+static exim_stek *
+tk_current(void)
+{
+if (!exim_tk.name[0]) return NULL;
+return &exim_tk;
+}
+
+static exim_stek *
+tk_find(const uschar * name)
+{
+return memcmp(name, exim_tk.name, sizeof(exim_tk.name)) == 0 ? &exim_tk
+  : memcmp(name, exim_tk_old.name, sizeof(exim_tk_old.name)) == 0 ? &exim_tk_old
+  : NULL;
+}
+
+/* Callback for session tickets, on server */
+static int
+ticket_key_callback(SSL * ssl, uschar key_name[16],
+  uschar * iv, EVP_CIPHER_CTX * c_ctx, HMAC_CTX * hctx, int enc)
+{
+tls_support * tlsp = state_server.tlsp;
+exim_stek * key;
+
+if (enc)
+  {
+  DEBUG(D_tls) debug_printf("ticket_key_callback: create new session\n");
+  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
+
+  if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0)
+    return -1; /* insufficient random */
+
+  if (!(key = tk_current()))   /* current key doesn't exist or isn't valid */
+     return 0;                 /* key couldn't be created */
+  memcpy(key_name, key->name, 16);
+  DEBUG(D_tls) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - time(NULL));
+
+  /*XXX will want these dependent on the ssl session strength */
+  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
+               key->hmac_hash, NULL);
+  EVP_EncryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv);
+
+  DEBUG(D_tls) debug_printf("ticket created\n");
+  return 1;
+  }
+else
+  {
+  time_t now = time(NULL);
+
+  DEBUG(D_tls) debug_printf("ticket_key_callback: retrieve session\n");
+  tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
+
+  if (!(key = tk_find(key_name)) || key->expire < now)
+    {
+    DEBUG(D_tls)
+      {
+      debug_printf("ticket not usable (%s)\n", key ? "expired" : "not found");
+      if (key) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - now);
+      }
+    return 0;
+    }
+
+  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
+               key->hmac_hash, NULL);
+  EVP_DecryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv);
+
+  DEBUG(D_tls) debug_printf("ticket usable, STEK expire " TIME_T_FMT "\n", key->expire - now);
+
+  /* The ticket lifetime and renewal are the same as the STEK lifetime and
+  renewal, which is overenthusiastic.  A factor of, say, 3x longer STEK would
+  be better.  To do that we'd have to encode ticket lifetime in the name as
+  we don't yet see the restored session.  Could check posthandshake for TLS1.3
+  and trigger a new ticket then, but cannot do that for TLS1.2 */
+  return key->renew < now ? 2 : 1;
+  }
+}
+#endif
+
+
+
+static void
+setup_cert_verify(SSL_CTX * ctx, BOOL optional,
+    int (*cert_vfy_cb)(int, X509_STORE_CTX *))
+{
+/* If verification is optional, don't fail if no certificate */
+
+SSL_CTX_set_verify(ctx,
+    SSL_VERIFY_PEER | (optional ? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
+    cert_vfy_cb);
+}
+
+
+/*************************************************
+*            Callback to handle SNI              *
+*************************************************/
+
+/* Called when acting as server during the TLS session setup if a Server Name
+Indication extension was sent by the client.
+
+API documentation is OpenSSL s_server.c implementation.
+
+Arguments:
+  s               SSL* of the current session
+  ad              unknown (part of OpenSSL API) (unused)
+  arg             Callback of "our" registered data
+
+Returns:          SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK}
+
+XXX might need to change to using ClientHello callback,
+per https://www.openssl.org/docs/manmaster/man3/SSL_client_hello_cb_fn.html
+*/
+
+#ifdef EXIM_HAVE_OPENSSL_TLSEXT
+static int
+tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
+{
+const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+exim_openssl_state_st *state = (exim_openssl_state_st *) arg;
+int rc;
+int old_pool = store_pool;
+uschar * dummy_errstr;
+
+if (!servername)
+  return SSL_TLSEXT_ERR_OK;
+
+DEBUG(D_tls) debug_printf("Received TLS SNI \"%s\"%s\n", servername,
+    reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)");
+
+/* Make the extension value available for expansion */
+store_pool = POOL_PERM;
+tls_in.sni = string_copy_taint(US servername, TRUE);
+store_pool = old_pool;
+
+if (!reexpand_tls_files_for_sni)
+  return SSL_TLSEXT_ERR_OK;
+
+/* Can't find an SSL_CTX_clone() or equivalent, so we do it manually;
+not confident that memcpy wouldn't break some internal reference counting.
+Especially since there's a references struct member, which would be off. */
+
+if (lib_ctx_new(&server_sni, NULL, &dummy_errstr) != OK)
+  goto bad;
+
+/* Not sure how many of these are actually needed, since SSL object
+already exists.  Might even need this selfsame callback, for reneg? */
+
+  {
+  SSL_CTX * ctx = state_server.lib_state.lib_ctx;
+  SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(ctx));
+  SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(ctx));
+  SSL_CTX_set_options(server_sni, SSL_CTX_get_options(ctx));
+  SSL_CTX_set_timeout(server_sni, SSL_CTX_get_timeout(ctx));
+  SSL_CTX_set_tlsext_servername_callback(server_sni, tls_servername_cb);
+  SSL_CTX_set_tlsext_servername_arg(server_sni, state);
+  }
+
+if (  !init_dh(server_sni, state->dhparam, NULL, &dummy_errstr)
+   || !init_ecdh(server_sni, NULL, &dummy_errstr)
+   )
+  goto bad;
+
+if (  state->server_cipher_list
+   && !SSL_CTX_set_cipher_list(server_sni, CS state->server_cipher_list))
+  goto bad;
+
+#ifndef DISABLE_OCSP
+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,
+                       &dummy_errstr)) != OK)
+    goto bad;
+
+  if (expcerts && *expcerts)
+    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;
+
+DEBUG(D_tls) debug_printf("Switching SSL context.\n");
+SSL_set_SSL_CTX(s, server_sni);
+return SSL_TLSEXT_ERR_OK;
+
+bad: return SSL_TLSEXT_ERR_ALERT_FATAL;
+}
+#endif /* EXIM_HAVE_OPENSSL_TLSEXT */
+
+
+
+
+#ifdef EXIM_HAVE_ALPN
+/*************************************************
+*        Callback to handle ALPN                 *
+*************************************************/
+
+/* Called on server if tls_alpn nonblank after expansion,
+when client offers ALPN, after the SNI callback.
+If set and not matching the list then we dump the connection */
+
+static int
+tls_server_alpn_cb(SSL *ssl, const uschar ** out, uschar * outlen,
+  const uschar * in, unsigned int inlen, void * arg)
+{
+server_seen_alpn = TRUE;
+DEBUG(D_tls)
+  {
+  debug_printf("Received TLS ALPN offer:");
+  for (int pos = 0, siz; pos < inlen; pos += siz+1)
+    {
+    siz = in[pos];
+    if (pos + 1 + siz > inlen) siz = inlen - pos - 1;
+    debug_printf(" '%.*s'", siz, in + pos + 1);
+    }
+  debug_printf(".  Our list: '%s'\n", tls_alpn);
+  }
+
+/* Look for an acceptable ALPN */
+
+if (  inlen > 1                /* at least one name */
+   && in[0]+1 == inlen /* filling the vector, so exactly one name */
+   )
+  {
+  const uschar * list = tls_alpn;
+  int sep = 0;
+  for (uschar * name; name = string_nextinlist(&list, &sep, NULL, 0); )
+    if (Ustrncmp(in+1, name, in[0]) == 0)
+      {
+      *out = in;                       /* we checked for exactly one, so can just point to it */
+      *outlen = inlen;
+      return SSL_TLSEXT_ERR_OK;                /* use ALPN */
+      }
+  }
+
+/* More than one name from clilent, 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");
+return SSL_TLSEXT_ERR_ALERT_FATAL;
+}
+#endif /* EXIM_HAVE_ALPN */
+
+
+
+#ifndef DISABLE_OCSP
+
+/*************************************************
+*        Callback to handle OCSP Stapling        *
+*************************************************/
+
+/* Called when acting as server during the TLS session setup if the client
+requests OCSP information with a Certificate Status Request.
+
+Documentation via openssl s_server.c and the Apache patch from the OpenSSL
+project.
+
+*/
+
+static int
+tls_server_stapling_cb(SSL *s, void *arg)
+{
+const exim_openssl_state_st * state = arg;
+ocsp_resplist * olist = state->u_ocsp.server.olist;
+uschar * response_der; /*XXX blob */
+int response_der_len;
+
+DEBUG(D_tls)
+  debug_printf("Received TLS status request (OCSP stapling); %s response list\n",
+    olist ? "have" : "lack");
+
+tls_in.ocsp = OCSP_NOT_RESP;
+if (!olist)
+  return SSL_TLSEXT_ERR_NOACK;
+
+#ifdef EXIM_HAVE_OPESSL_GET0_SERIAL
+ {
+  const X509 * cert_sent = SSL_get_certificate(s);
+  const ASN1_INTEGER * cert_serial = X509_get0_serialNumber(cert_sent);
+  const BIGNUM * cert_bn = ASN1_INTEGER_to_BN(cert_serial, NULL);
+  const X509_NAME * cert_issuer = X509_get_issuer_name(cert_sent);
+  uschar * chash;
+  uint chash_len;
+
+  for (; olist; olist = olist->next)
+    {
+    OCSP_BASICRESP * bs = OCSP_response_get1_basic(olist->resp);
+    const OCSP_SINGLERESP * single = OCSP_resp_get0(bs, 0);
+    const OCSP_CERTID * cid = OCSP_SINGLERESP_get0_id(single);
+    ASN1_INTEGER * res_cert_serial;
+    const BIGNUM * resp_bn;
+    ASN1_OCTET_STRING * res_cert_iNameHash;
+
+
+    (void) OCSP_id_get0_info(&res_cert_iNameHash, NULL, NULL, &res_cert_serial,
+      (OCSP_CERTID *) cid);
+    resp_bn = ASN1_INTEGER_to_BN(res_cert_serial, NULL);
+
+    DEBUG(D_tls)
+      {
+      debug_printf("cert serial: %s\n", BN_bn2hex(cert_bn));
+      debug_printf("resp serial: %s\n", BN_bn2hex(resp_bn));
+      }
+
+    if (BN_cmp(cert_bn, resp_bn) == 0)
+      {
+      DEBUG(D_tls) debug_printf("matched serial for ocsp\n");
+
+      /*XXX TODO: check the rest of the list for duplicate matches.
+      If any, need to also check the Issuer Name hash.
+      Without this, we will provide the wrong status in the case of
+      duplicate id. */
+
+      break;
+      }
+    DEBUG(D_tls) debug_printf("not match serial for ocsp\n");
+    }
+  if (!olist)
+    {
+    DEBUG(D_tls) debug_printf("failed to find match for ocsp\n");
+    return SSL_TLSEXT_ERR_NOACK;
+    }
+ }
+#else
+if (olist->next)
+  {
+  DEBUG(D_tls) debug_printf("OpenSSL version too early to support multi-leaf OCSP\n");
+  return SSL_TLSEXT_ERR_NOACK;
+  }
+#endif
+
+/*XXX could we do the i2d earlier, rather than during the callback? */
+response_der = NULL;
+response_der_len = i2d_OCSP_RESPONSE(olist->resp, &response_der);
+if (response_der_len <= 0)
+  return SSL_TLSEXT_ERR_NOACK;
+
+SSL_set_tlsext_status_ocsp_resp(state_server.lib_state.lib_ssl,
+                               response_der, response_der_len);
+tls_in.ocsp = OCSP_VFIED;
+return SSL_TLSEXT_ERR_OK;
+}
+
+
+static void
+time_print(BIO * bp, const char * str, ASN1_GENERALIZEDTIME * time)
+{
+BIO_printf(bp, "\t%s: ", str);
+ASN1_GENERALIZEDTIME_print(bp, time);
+BIO_puts(bp, "\n");
+}
+
+static int
+tls_client_stapling_cb(SSL *s, void *arg)
+{
+exim_openssl_state_st * cbinfo = arg;
+const unsigned char * p;
+int len;
+OCSP_RESPONSE * rsp;
+OCSP_BASICRESP * bs;
+int i;
+
+DEBUG(D_tls) debug_printf("Received TLS status callback (OCSP stapling):\n");
+len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+if(!p)
+ {
+  /* Expect this when we requested ocsp but got none */
+  if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher))
+    log_write(0, LOG_MAIN, "Required TLS certificate status not received");
+  else
+    DEBUG(D_tls) debug_printf(" null\n");
+  return cbinfo->u_ocsp.client.verify_required ? 0 : 1;
+ }
+
+if (!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
+  {
+  tls_out.ocsp = OCSP_FAILED;  /*XXX should use tlsp-> to permit concurrent outbound */
+  if (LOGGING(tls_cipher))
+    log_write(0, LOG_MAIN, "Received TLS cert status response, parse error");
+  else
+    DEBUG(D_tls) debug_printf(" parse error\n");
+  return 0;
+  }
+
+if (!(bs = OCSP_response_get1_basic(rsp)))
+  {
+  tls_out.ocsp = OCSP_FAILED;
+  if (LOGGING(tls_cipher))
+    log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response");
+  else
+    DEBUG(D_tls) debug_printf(" error parsing response\n");
+  OCSP_RESPONSE_free(rsp);
+  return 0;
+  }
+
+/* We'd check the nonce here if we'd put one in the request. */
+/* However that would defeat cacheability on the server so we don't. */
+
+/* This section of code reworked from OpenSSL apps source;
+   The OpenSSL Project retains copyright:
+   Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+*/
+  {
+    BIO * bp = NULL;
+#ifndef EXIM_HAVE_OCSP_RESP_COUNT
+    STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
+#endif
+
+    DEBUG(D_tls) bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
+
+    /*OCSP_RESPONSE_print(bp, rsp, 0);   extreme debug: stapling content */
+
+    /* Use the chain that verified the server cert to verify the stapled info */
+    /* DEBUG(D_tls) x509_store_dump_cert_s_names(cbinfo->u_ocsp.client.verify_store); */
+
+    if ((i = OCSP_basic_verify(bs, cbinfo->verify_stack,
+             cbinfo->u_ocsp.client.verify_store, OCSP_NOEXPLICIT)) <= 0)
+      if (ERR_peek_error())
+       {
+       tls_out.ocsp = OCSP_FAILED;
+       if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN,
+               "Received TLS cert status response, itself unverifiable: %s",
+               ERR_reason_error_string(ERR_peek_error()));
+       BIO_printf(bp, "OCSP response verify failure\n");
+       ERR_print_errors(bp);
+       OCSP_RESPONSE_print(bp, rsp, 0);
+       goto failed;
+       }
+      else
+       DEBUG(D_tls) debug_printf("no explicit trust for OCSP signing"
+         " in the root CA certificate; ignoring\n");
+
+    DEBUG(D_tls) debug_printf("OCSP response well-formed and signed OK\n");
+
+    /*XXX So we have a good stapled OCSP status.  How do we know
+    it is for the cert of interest?  OpenSSL 1.1.0 has a routine
+    OCSP_resp_find_status() which matches on a cert id, which presumably
+    we should use. Making an id needs OCSP_cert_id_new(), which takes
+    issuerName, issuerKey, serialNumber.  Are they all in the cert?
+
+    For now, carry on blindly accepting the resp. */
+
+    for (int idx =
+#ifdef EXIM_HAVE_OCSP_RESP_COUNT
+           OCSP_resp_count(bs) - 1;
+#else
+           sk_OCSP_SINGLERESP_num(sresp) - 1;
+#endif
+        idx >= 0; idx--)
+      {
+      OCSP_SINGLERESP * single = OCSP_resp_get0(bs, idx);
+      int status, reason;
+      ASN1_GENERALIZEDTIME * rev, * thisupd, * nextupd;
+
+  /*XXX so I can see putting a loop in here to handle a rsp with >1 singleresp
+  - but what happens with a GnuTLS-style input?
+
+  we could do with a debug label for each singleresp
+  - it has a certID with a serialNumber, but I see no API to get that
+  */
+      status = OCSP_single_get0_status(single, &reason, &rev,
+                 &thisupd, &nextupd);
+
+      DEBUG(D_tls) time_print(bp, "This OCSP Update", thisupd);
+      DEBUG(D_tls) if(nextupd) time_print(bp, "Next OCSP Update", nextupd);
+      if (!OCSP_check_validity(thisupd, nextupd,
+           EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
+       {
+       tls_out.ocsp = OCSP_FAILED;
+       DEBUG(D_tls) ERR_print_errors(bp);
+       log_write(0, LOG_MAIN, "Server OSCP dates invalid");
+       goto failed;
+       }
+
+      DEBUG(D_tls) BIO_printf(bp, "Certificate status: %s\n",
+                   OCSP_cert_status_str(status));
+      switch(status)
+       {
+       case V_OCSP_CERTSTATUS_GOOD:
+         continue;     /* the idx loop */
+       case V_OCSP_CERTSTATUS_REVOKED:
+         log_write(0, LOG_MAIN, "Server certificate revoked%s%s",
+             reason != -1 ? "; reason: " : "",
+             reason != -1 ? OCSP_crl_reason_str(reason) : "");
+         DEBUG(D_tls) time_print(bp, "Revocation Time", rev);
+         break;
+       default:
+         log_write(0, LOG_MAIN,
+             "Server certificate status unknown, in OCSP stapling");
+         break;
+       }
+
+      goto failed;
+      }
+
+    i = 1;
+    tls_out.ocsp = OCSP_VFIED;
+    goto good;
+
+  failed:
+    tls_out.ocsp = OCSP_FAILED;
+    i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
+  good:
+    BIO_free(bp);
+  }
+
+OCSP_RESPONSE_free(rsp);
+return i;
+}
+#endif /*!DISABLE_OCSP*/
+
+
+/*************************************************
+*            Initialize for TLS                  *
+*************************************************/
+/* Called from both server and client code, to do preliminary initialization
+of the library.  We allocate and return a context structure.
+
+Arguments:
+  host            connected host, if client; NULL if server
+  ob             transport options block, if client; NULL if server
+  ocsp_file       file of stapling info (server); flag for require ocsp (client)
+  addr            address if client; NULL if server (for some randomness)
+  caller_state    place to put pointer to allocated state-struct
+  errstr         error string pointer
+
+Returns:          OK/DEFER/FAIL
+*/
+
+static int
+tls_init(host_item * host, smtp_transport_options_block * ob,
+#ifndef DISABLE_OCSP
+  uschar *ocsp_file,
+#endif
+  address_item *addr, exim_openssl_state_st ** caller_state,
+  tls_support * tlsp,
+  uschar ** errstr)
+{
+SSL_CTX * ctx;
+exim_openssl_state_st * state;
+int rc;
+
+if (host)                      /* client */
+  {
+  state = store_malloc(sizeof(exim_openssl_state_st));
+  memset(state, 0, sizeof(*state));
+  state->certificate = ob->tls_certificate;
+  state->privatekey =  ob->tls_privatekey;
+  state->is_server = FALSE;
+  state->dhparam = NULL;
+  state->lib_state = ob->tls_preload;
+  }
+else                           /* server */
+  {
+  state = &state_server;
+  state->certificate = tls_certificate;
+  state->privatekey =  tls_privatekey;
+  state->is_server = TRUE;
+  state->dhparam = tls_dhparam;
+  state->lib_state = state_server.lib_state;
+  }
+
+state->tlsp = tlsp;
+state->host = host;
+
+if (!state->lib_state.pri_string)
+  state->server_cipher_list = NULL;
+
+#ifndef DISABLE_EVENT
+state->event_action = NULL;
+#endif
+
+tls_openssl_init();
+
+/* It turns out that we need to seed the random number generator this early in
+order to get the full complement of ciphers to work. It took me roughly a day
+of work to discover this by experiment.
+
+On systems that have /dev/urandom, SSL may automatically seed itself from
+there. Otherwise, we have to make something up as best we can. Double check
+afterwards.
+
+Although we likely called this before, at daemon startup, this is a chance
+to mix in further variable info (time, pid) if needed. */
+
+if (!lib_rand_init(addr))
+  return tls_error(US"RAND_status", host,
+    US"unable to seed random number generator", errstr);
+
+/* Apply administrator-supplied work-arounds.
+Historically we applied just one requested option,
+SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS, but when bug 994 requested a second, we
+moved to an administrator-controlled list of options to specify and
+grandfathered in the first one as the default value for "openssl_options".
+
+No OpenSSL version number checks: the options we accept depend upon the
+availability of the option value macros from OpenSSL.  */
+
+if (!init_options)
+  if (!tls_openssl_options_parse(openssl_options, &init_options))
+    return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
+
+/* Create a context.
+The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant
+negotiation in the different methods; as far as I can tell, the only
+*_{server,client}_method which allows negotiation is SSLv23, which exists even
+when OpenSSL is built without SSLv2 support.
+By disabling with openssl_options, we can let admins re-enable with the
+existing knob. */
+
+if (!(ctx = state->lib_state.lib_ctx))
+  {
+  if ((rc = lib_ctx_new(&ctx, host, errstr)) != OK)
+    return rc;
+  state->lib_state.lib_ctx = ctx;
+  }
+
+#ifndef DISABLE_TLS_RESUME
+tlsp->resumption = RESUME_SUPPORTED;
+#endif
+if (init_options)
+  {
+#ifndef DISABLE_TLS_RESUME
+  /* Should the server offer session resumption? */
+  if (!host && verify_check_host(&tls_resumption_hosts) == OK)
+    {
+    DEBUG(D_tls) debug_printf("tls_resumption_hosts overrides openssl_options\n");
+    init_options &= ~SSL_OP_NO_TICKET;
+    tlsp->resumption |= RESUME_SERVER_TICKET; /* server will give ticket on request */
+    tlsp->host_resumable = TRUE;
+    }
+#endif
+
+  DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
+  if (!(SSL_CTX_set_options(ctx, init_options)))
+    return tls_error(string_sprintf(
+          "SSL_CTX_set_option(%#lx)", init_options), host, NULL, errstr);
+  }
+else
+  DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
+
+/* We'd like to disable session cache unconditionally, but foolish Outlook
+Express clients then give up the first TLS connection and make a second one
+(which works).  Only when there is an IMAP service on the same machine.
+Presumably OE is trying to use the cache for A on B.  Leave it enabled for
+now, until we work out a decent way of presenting control to the config.  It
+will never be used because we use a new context every time. */
+#ifdef notdef
+(void) SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+#endif
+
+/* Initialize with DH parameters if supplied */
+/* Initialize ECDH temp key parameter selection */
+
+if (state->lib_state.dh)
+  { DEBUG(D_tls) debug_printf("TLS: DH params were preloaded\n"); }
+else
+  if (!init_dh(ctx, state->dhparam, host, errstr)) return DEFER;
+
+if (state->lib_state.ecdh)
+  { DEBUG(D_tls) debug_printf("TLS: ECDH curve was preloaded\n"); }
+else
+  if (!init_ecdh(ctx, host, errstr)) return DEFER;
+
+/* Set up certificate and key (and perhaps OCSP info) */
+
+if (state->lib_state.conn_certs)
+  {
+  DEBUG(D_tls)
+    debug_printf("TLS: %s certs were preloaded\n", host ? "client":"server");
+  }
+else
+  {
+#ifndef DISABLE_OCSP
+  if (!host)
+    {
+    state->u_ocsp.server.file = ocsp_file;
+    state->u_ocsp.server.file_expanded = NULL;
+    state->u_ocsp.server.olist = NULL;
+    }
+#endif
+  if ((rc = tls_expand_session_files(ctx, state, errstr)) != OK) return rc;
+  }
+
+/* If we need to handle SNI or OCSP, do so */
+
+#ifdef EXIM_HAVE_OPENSSL_TLSEXT
+# ifndef DISABLE_OCSP
+  if (!(state->verify_stack = sk_X509_new_null()))
+    {
+    DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n");
+    return FAIL;
+    }
+# endif
+
+if (!host)             /* server */
+  {
+# ifndef DISABLE_OCSP
+  /* We check u_ocsp.server.file, not server.olist, because we care about if
+  the option exists, not what the current expansion might be, as SNI might
+  change the certificate and OCSP file in use between now and the time the
+  callback is invoked. */
+  if (state->u_ocsp.server.file)
+    {
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
+    SSL_CTX_set_tlsext_status_arg(ctx, state);
+    }
+# endif
+  /* We always do this, so that $tls_sni is available even if not used in
+  tls_certificate */
+  SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
+  SSL_CTX_set_tlsext_servername_arg(ctx, state);
+
+# ifdef EXIM_HAVE_ALPN
+  if (tls_alpn && *tls_alpn)
+    {
+    uschar * exp_alpn;
+    if (  expand_check(tls_alpn, US"tls_alpn", &exp_alpn, errstr)
+       && *exp_alpn && !isblank(*exp_alpn))
+      {
+      tls_alpn = exp_alpn;     /* subprocess so ok to overwrite */
+      SSL_CTX_set_alpn_select_cb(ctx, tls_server_alpn_cb, state);
+      }
+    else
+      tls_alpn = NULL;
+    }
+# endif
+  }
+# ifndef DISABLE_OCSP
+else                   /* client */
+  if(ocsp_file)                /* wanting stapling */
+    {
+    if (!(state->u_ocsp.client.verify_store = X509_STORE_new()))
+      {
+      DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
+      return FAIL;
+      }
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
+    SSL_CTX_set_tlsext_status_arg(ctx, state);
+    }
+# endif
+#endif
+
+state->verify_cert_hostnames = NULL;
+
+#ifdef EXIM_HAVE_EPHEM_RSA_KEX
+/* Set up the RSA callback */
+SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
+#endif
+
+/* Finally, set the session cache timeout, and we are done.
+The period appears to be also used for (server-generated) session tickets */
+
+SSL_CTX_set_timeout(ctx, ssl_session_timeout);
+DEBUG(D_tls) debug_printf("Initialized TLS\n");
+
+*caller_state = state;
+
+return OK;
+}
+
+
+
+
+/*************************************************
+*           Get name of cipher in use            *
+*************************************************/
+
+/*
+Argument:   pointer to an SSL structure for the connection
+           pointer to number of bits for cipher
+Returns:    pointer to allocated string in perm-pool
+*/
+
+static uschar *
+construct_cipher_name(SSL * ssl, const uschar * ver, int * bits)
+{
+int pool = store_pool;
+/* With OpenSSL 1.0.0a, 'c' needs to be const but the documentation doesn't
+yet reflect that.  It should be a safe change anyway, even 0.9.8 versions have
+the accessor functions use const in the prototype. */
+
+const SSL_CIPHER * c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
+uschar * s;
+
+SSL_CIPHER_get_bits(c, bits);
+
+store_pool = POOL_PERM;
+s = string_sprintf("%s:%s:%u", ver, SSL_CIPHER_get_name(c), *bits);
+store_pool = pool;
+DEBUG(D_tls) debug_printf("Cipher: %s\n", s);
+return s;
+}
+
+
+/* Get IETF-standard name for ciphersuite.
+Argument:   pointer to an SSL structure for the connection
+Returns:    pointer to string
+*/
+
+static const uschar *
+cipher_stdname_ssl(SSL * ssl)
+{
+#ifdef EXIM_HAVE_OPENSSL_CIPHER_STD_NAME
+return CUS SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl));
+#else
+ushort id = 0xffff & SSL_CIPHER_get_id(SSL_get_current_cipher(ssl));
+return cipher_stdname(id >> 8, id & 0xff);
+#endif
+}
+
+
+static const uschar *
+tlsver_name(SSL * ssl)
+{
+uschar * s, * p;
+int pool = store_pool;
+
+store_pool = POOL_PERM;
+s = string_copy(US SSL_get_version(ssl));
+store_pool = pool;
+if ((p = Ustrchr(s, 'v')))     /* TLSv1.2 -> TLS1.2 */
+  for (;; p++) if (!(*p = p[1])) break;
+return CUS s;
+}
+
+
+static void
+peer_cert(SSL * ssl, tls_support * tlsp, uschar * peerdn, unsigned siz)
+{
+/*XXX we might consider a list-of-certs variable for the cert chain.
+SSL_get_peer_cert_chain(SSL*).  We'd need a new variable type and support
+in list-handling functions, also consider the difference between the entire
+chain and the elements sent by the peer. */
+
+tlsp->peerdn = NULL;
+
+/* Will have already noted peercert on a verify fail; possibly not the leaf */
+if (!tlsp->peercert)
+  tlsp->peercert = SSL_get_peer_certificate(ssl);
+/* Beware anonymous ciphers which lead to server_cert being NULL */
+if (tlsp->peercert)
+  if (!X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, siz))
+    { DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); }
+  else
+    {
+    int oldpool = store_pool;
+
+    peerdn[siz-1] = '\0';              /* paranoia */
+    store_pool = POOL_PERM;
+    tlsp->peerdn = string_copy(peerdn);
+    store_pool = oldpool;
+
+    /* We used to set CV in the cert-verify callbacks (either plain or dane)
+    but they don't get called on session-resumption.  So use the official
+    interface, which uses the resumed value.  Unfortunately this claims verified
+    when it actually failed but we're in try-verify mode, due to us wanting the
+    knowlege that it failed so needing to have the callback and forcing a
+    permissive return.  If we don't force it, the TLS startup is failed.
+    The extra bit of information is set in verify_override in the cb, stashed
+    for resumption next to the TLS session, and used here. */
+
+    if (!tlsp->verify_override)
+      tlsp->certificate_verified =
+#ifdef SUPPORT_DANE
+       tlsp->dane_verified ||
+#endif
+       SSL_get_verify_result(ssl) == X509_V_OK;
+    }
+}
+
+
+
+
+
+/*************************************************
+*        Set up for verifying certificates       *
+*************************************************/
+
+#ifndef DISABLE_OCSP
+/* Load certs from file, return TRUE on success */
+
+static BOOL
+chain_from_pem_file(const uschar * file, STACK_OF(X509) ** vp)
+{
+BIO * bp;
+STACK_OF(X509) * verify_stack = *vp;
+
+if (verify_stack)
+  while (sk_X509_num(verify_stack) > 0)
+    X509_free(sk_X509_pop(verify_stack));
+else
+  verify_stack = sk_X509_new_null();
+
+if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
+for (X509 * x; x = PEM_read_bio_X509(bp, NULL, 0, NULL); )
+  sk_X509_push(verify_stack, x);
+BIO_free(bp);
+*vp = verify_stack;
+return TRUE;
+}
+#endif
+
+
+
+/* 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
+  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,
+    uschar ** errstr)
+{
+uschar *expcerts, *expcrl;
+
+if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr))
+  return DEFER;
+DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", 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);
+
+  if (Ustrcmp(expcerts, "system") != 0 && Ustrncmp(expcerts, "system,", 7) != 0)
+    {
+    struct stat statbuf;
+
+    if (Ustat(expcerts, &statbuf) < 0)
+      {
+      log_write(0, LOG_MAIN|LOG_PANIC,
+       "failed to stat %s for certificates", expcerts);
+      return DEFER;
+      }
+    else
+      {
+      uschar *file, *dir;
+      if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+       { file = NULL; dir = expcerts; }
+      else
+       {
+       STACK_OF(X509) * verify_stack =
+#ifndef DISABLE_OCSP
+         !host ? state_server.verify_stack :
+#endif
+         NULL;
+       STACK_OF(X509) ** vp = &verify_stack;
+
+       file = expcerts; dir = NULL;
+#ifndef DISABLE_OCSP
+       /* In the server if we will be offering an OCSP proof, load chain from
+       file for verifying the OCSP proof at load time. */
+
+/*XXX Glitch!   The file here is tls_verify_certs: the chain for verifying the client cert.
+This is inconsistent with the need to verify the OCSP proof of the server cert.
+*/
+       if (  !host
+          && statbuf.st_size > 0
+          && state_server.u_ocsp.server.file
+          && !chain_from_pem_file(file, vp)
+          )
+         {
+         log_write(0, LOG_MAIN|LOG_PANIC,
+           "failed to load cert chain from %s", file);
+         return DEFER;
+         }
+#endif
+       }
+
+      /* If a certificate file is empty, the load function fails with an
+      unhelpful error message. If we skip it, we get the correct behaviour (no
+      certificates are recognized, but the error message is still misleading (it
+      says no certificate was supplied).  But this is better. */
+
+      if (  (!file || statbuf.st_size > 0)
+         && !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
+         return tls_error(US"SSL_CTX_load_verify_locations",
+                           host, NULL, errstr);
+
+      /* On the server load the list of CAs for which we will accept certs, for
+      sending to the client.  This is only for the one-file
+      tls_verify_certificates variant.
+      If a list isn't loaded into the server, but some verify locations are set,
+      the server end appears to make a wildcard request for client certs.
+      Meanwhile, the client library as default behaviour *ignores* the list
+      we send over the wire - see man SSL_CTX_set_client_cert_cb.
+      Because of this, and that the dir variant is likely only used for
+      the public-CA bundle (not for a private CA), not worth fixing.  */
+
+      if (file)
+       {
+       STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
+       int i = sk_X509_NAME_num(names);
+
+       if (!host) SSL_CTX_set_client_CA_list(sctx, names);
+       DEBUG(D_tls) debug_printf("Added %d additional certificate authorit%s\n",
+                                   i, i>1 ? "ies":"y");
+       }
+      else
+       DEBUG(D_tls)
+         debug_printf("Added dir for additional certificate authorities\n");
+      }
+    }
+
+  /* Handle a certificate revocation list. */
+
+#if OPENSSL_VERSION_NUMBER > 0x00907000L
+
+  /* This bit of code is now the version supplied by Lars Mainka. (I have
+  merely reformatted it into the Exim code style.)
+
+  "From here I changed the code to add support for multiple crl's
+  in pem format in one file or to support hashed directory entries in
+  pem format instead of a file. This method now uses the library function
+  X509_STORE_load_locations to add the CRL location to the SSL context.
+  OpenSSL will then handle the verify against CA certs and CRLs by
+  itself in the verify callback." */
+
+  if (!expand_check(crl, US"tls_crl", &expcrl, errstr)) return DEFER;
+  if (expcrl && *expcrl)
+    {
+    struct stat statbufcrl;
+    if (Ustat(expcrl, &statbufcrl) < 0)
+      {
+      log_write(0, LOG_MAIN|LOG_PANIC,
+        "failed to stat %s for certificates revocation lists", expcrl);
+      return DEFER;
+      }
+    else
+      {
+      /* is it a file or directory? */
+      uschar *file, *dir;
+      X509_STORE *cvstore = SSL_CTX_get_cert_store(sctx);
+      if ((statbufcrl.st_mode & S_IFMT) == S_IFDIR)
+        {
+        file = NULL;
+        dir = expcrl;
+        DEBUG(D_tls) debug_printf("SSL CRL value is a directory %s\n", dir);
+        }
+      else
+        {
+        file = expcrl;
+        dir = NULL;
+        DEBUG(D_tls) debug_printf("SSL CRL value is a file %s\n", file);
+        }
+      if (X509_STORE_load_locations(cvstore, CS file, CS dir) == 0)
+        return tls_error(US"X509_STORE_load_locations", host, NULL, errstr);
+
+      /* setting the flags to check against the complete crl chain */
+
+      X509_STORE_set_flags(cvstore,
+        X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+      }
+    }
+
+#endif  /* OPENSSL_VERSION_NUMBER > 0x00907000L */
+  }
+
+return OK;
+}
+
+
+
+/*************************************************
+*       Start a TLS session in a server          *
+*************************************************/
+/* This is called when Exim is running as a server, after having received
+the STARTTLS command. It must respond to that command, and then negotiate
+a TLS session.
+
+Arguments:
+  errstr           pointer to error message
+
+Returns:            OK on success
+                    DEFER for errors before the start of the negotiation
+                    FAIL for errors during the negotiation; the server can't
+                      continue running.
+*/
+
+int
+tls_server_start(uschar ** errstr)
+{
+int rc;
+uschar * expciphers;
+exim_openssl_state_st * dummy_statep;
+SSL_CTX * ctx;
+SSL * ssl;
+static uschar peerdn[256];
+
+/* Check for previous activation */
+
+if (tls_in.active.sock >= 0)
+  {
+  tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr);
+  smtp_printf("554 Already in TLS\r\n", FALSE);
+  return FAIL;
+  }
+
+/* Initialize the SSL library. If it fails, it will already have logged
+the error. */
+
+rc = tls_init(NULL, NULL,
+#ifndef DISABLE_OCSP
+    tls_ocsp_file,
+#endif
+    NULL, &dummy_statep, &tls_in, errstr);
+if (rc != OK) return rc;
+ctx = state_server.lib_state.lib_ctx;
+
+/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
+were historically separated by underscores. So that I can use either form in my
+tests, and also for general convenience, we turn underscores into hyphens here.
+
+XXX SSL_CTX_set_cipher_list() is replaced by SSL_CTX_set_ciphersuites()
+for TLS 1.3 .  Since we do not call it at present we get the default list:
+TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
+*/
+
+if (state_server.lib_state.pri_string)
+  { DEBUG(D_tls) debug_printf("TLS: cipher list was preloaded\n"); }
+else 
+  {
+  if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, errstr))
+    return FAIL;
+
+  if (  expciphers
+     && (rc = server_load_ciphers(ctx, &state_server, expciphers, errstr)) != OK)
+    return rc;
+  }
+
+/* If this is a host for which certificate verification is mandatory or
+optional, set up appropriately. */
+
+tls_in.certificate_verified = FALSE;
+#ifdef SUPPORT_DANE
+tls_in.dane_verified = FALSE;
+#endif
+server_verify_callback_called = FALSE;
+
+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);
+
+  if (state_server.lib_state.cabundle)
+    { DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); }
+  else
+    if ((rc = setup_certs(ctx, expcerts, tls_crl, NULL, errstr)) != OK)
+      return rc;
+
+  if (expcerts && *expcerts)
+    setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
+  }
+skip_certs: ;
+
+#ifndef DISABLE_TLS_RESUME
+SSL_CTX_set_tlsext_ticket_key_cb(ctx, ticket_key_callback);
+/* despite working, appears to always return failure, so ignoring */
+#endif
+#ifdef OPENSSL_HAVE_NUM_TICKETS
+# ifndef DISABLE_TLS_RESUME
+SSL_CTX_set_num_tickets(ctx, tls_in.host_resumable ? 1 : 0);
+# else
+SSL_CTX_set_num_tickets(ctx, 0);       /* send no TLS1.3 stateful-tickets */
+# endif
+#endif
+
+
+/* Prepare for new connection */
+
+if (!(ssl = SSL_new(ctx)))
+  return tls_error(US"SSL_new", NULL, NULL, errstr);
+state_server.lib_state.lib_ssl = ssl;
+
+/* Warning: we used to SSL_clear(ssl) here, it was removed.
+ *
+ * With the SSL_clear(), we get strange interoperability bugs with
+ * OpenSSL 1.0.1b and TLS1.1/1.2.  It looks as though this may be a bug in
+ * OpenSSL itself, as a clear should not lead to inability to follow protocols.
+ *
+ * The SSL_clear() call is to let an existing SSL* be reused, typically after
+ * session shutdown.  In this case, we have a brand new object and there's no
+ * obvious reason to immediately clear it.  I'm guessing that this was
+ * originally added because of incomplete initialisation which the clear fixed,
+ * in some historic release.
+ */
+
+/* Set context and tell client to go ahead, except in the case of TLS startup
+on connection, where outputting anything now upsets the clients and tends to
+make them disconnect. We need to have an explicit fflush() here, to force out
+the response. Other smtp_printf() calls do not need it, because in non-TLS
+mode, the fflush() happens when smtp_getc() is called. */
+
+SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx));
+if (!tls_in.on_connect)
+  {
+  smtp_printf("220 TLS go ahead\r\n", FALSE);
+  fflush(smtp_out);
+  }
+
+/* Now negotiate the TLS session. We put our own timer on it, since it seems
+that the OpenSSL library doesn't. */
+
+SSL_set_wfd(ssl, fileno(smtp_out));
+SSL_set_rfd(ssl, fileno(smtp_in));
+SSL_set_accept_state(ssl);
+
+DEBUG(D_tls) debug_printf("Calling SSL_accept\n");
 
-    DEBUG(D_tls) bp = BIO_new_fp(stderr, BIO_NOCLOSE);
+ERR_clear_error();
+sigalrm_seen = FALSE;
+if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
+rc = SSL_accept(ssl);
+ALARM_CLR(0);
 
-    /*OCSP_RESPONSE_print(bp, rsp, 0);   extreme debug: stapling content */
+if (rc <= 0)
+  {
+  int error = SSL_get_error(ssl, rc);
+  switch(error)
+    {
+    case SSL_ERROR_NONE:
+      break;
 
-    /* Use the chain that verified the server cert to verify the stapled info */
-    /* DEBUG(D_tls) x509_store_dump_cert_s_names(cbinfo->u_ocsp.client.verify_store); */
+    case SSL_ERROR_ZERO_RETURN:
+      DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
+      (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
 
-    if ((i = OCSP_basic_verify(bs, NULL,
-             cbinfo->u_ocsp.client.verify_store, 0)) <= 0)
-      {
-      BIO_printf(bp, "OCSP response verify failure\n");
-      ERR_print_errors(bp);
-      i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
-      goto out;
-      }
+      if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN)
+           SSL_shutdown(ssl);
 
-    BIO_printf(bp, "OCSP response well-formed and signed OK\n");
+      tls_close(NULL, TLS_NO_SHUTDOWN);
+      return FAIL;
 
+    /* Handle genuine errors */
+    case SSL_ERROR_SSL:
       {
-      STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
-      OCSP_SINGLERESP * single;
-
-      if (sk_OCSP_SINGLERESP_num(sresp) != 1)
-        {
-        log_write(0, LOG_MAIN, "OCSP stapling "
-           "with multiple responses not handled");
-       i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
-        goto out;
-        }
-      single = OCSP_resp_get0(bs, 0);
-      status = OCSP_single_get0_status(single, &reason, &rev,
-                 &thisupd, &nextupd);
+      uschar * s = NULL;
+      int r = ERR_GET_REASON(ERR_peek_error());
+      if (  r == SSL_R_WRONG_VERSION_NUMBER
+#ifdef SSL_R_VERSION_TOO_LOW
+         || r == SSL_R_VERSION_TOO_LOW
+#endif
+         || r == SSL_R_UNKNOWN_PROTOCOL || r == SSL_R_UNSUPPORTED_PROTOCOL)
+       s = string_sprintf("%s (%s)", s, SSL_get_version(ssl));
+      (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : s, errstr);
+      return FAIL;
       }
 
-    DEBUG(D_tls) time_print(bp, "This OCSP Update", thisupd);
-    DEBUG(D_tls) if(nextupd) time_print(bp, "Next OCSP Update", nextupd);
-    if (!OCSP_check_validity(thisupd, nextupd,
-         EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
-      {
-      DEBUG(D_tls) ERR_print_errors(bp);
-      log_write(0, LOG_MAIN, "Server OSCP dates invalid");
-      i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
-      }
-    else
-      {
-      DEBUG(D_tls) BIO_printf(bp, "Certificate status: %s\n",
-                   OCSP_cert_status_str(status));
-      switch(status)
+    default:
+      DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
+      if (error == SSL_ERROR_SYSCALL)
        {
-       case V_OCSP_CERTSTATUS_GOOD:
-         i = 1;
-         tls_out.ocsp = OCSP_VFIED;
-         break;
-       case V_OCSP_CERTSTATUS_REVOKED:
-         log_write(0, LOG_MAIN, "Server certificate revoked%s%s",
-             reason != -1 ? "; reason: " : "",
-             reason != -1 ? OCSP_crl_reason_str(reason) : "");
-         DEBUG(D_tls) time_print(bp, "Revocation Time", rev);
-         i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
-         break;
-       default:
-         log_write(0, LOG_MAIN,
-             "Server certificate status unknown, in OCSP stapling");
-         i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
-         break;
+       if (!errno)
+         {
+         *errstr = US"SSL_accept: TCP connection closed by peer";
+         return FAIL;
+         }
+       DEBUG(D_tls) debug_printf(" - syscall %s\n", strerror(errno));
        }
-      }
-  out:
-    BIO_free(bp);
+      (void) tls_error(US"SSL_accept", NULL,
+                     sigalrm_seen ? US"timed out"
+                     : ERR_peek_error() ? NULL : string_sprintf("ret %d", error),
+                     errstr);
+      return FAIL;
+    }
   }
 
-OCSP_RESPONSE_free(rsp);
-return i;
-}
-#endif /*EXPERIMENTAL_OCSP*/
+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. */
 
+#ifndef DISABLE_TLS_RESUME
+if (SSL_session_reused(ssl))
+  {
+  tls_in.resumption |= RESUME_USED;
+  DEBUG(D_tls) debug_printf("Session reused\n");
+  }
+#endif
 
+#ifdef EXIM_HAVE_ALPN
+/* If require-alpn, check server_seen_alpn here.  Else abort TLS */
+if (!tls_alpn || !*tls_alpn)
+  { DEBUG(D_tls) debug_printf("TLS: was not watching for ALPN\n"); }
+else if (!server_seen_alpn)
+  if (verify_check_host(&hosts_require_alpn) == OK)
+    {
+    /* We'd like to send a definitive Alert but OpenSSL provides no facility */
+    SSL_shutdown(ssl);
+    tls_error(US"handshake", NULL, US"ALPN required but not negotiated", errstr);
+    return FAIL;
+    }
+  else
+    { DEBUG(D_tls) debug_printf("TLS: no ALPN presented in handshake\n"); }
+else DEBUG(D_tls)
+  {
+  const uschar * name;
+  unsigned len;
+  SSL_get0_alpn_selected(ssl, &name, &len);
+  if (len && name)
+    debug_printf("ALPN negotiated: '%.*s'\n", (int)*name, name+1);
+  else
+    debug_printf("ALPN: no protocol negotiated\n");
+  }
+#endif
 
-/*************************************************
-*            Initialize for TLS                  *
-*************************************************/
 
-/* Called from both server and client code, to do preliminary initialization of
-the library.
+/* TLS has been set up. Record data for the connection,
+adjust the input functions to read via TLS, and initialize things. */
 
-Arguments:
-  host            connected host, if client; NULL if server
-  dhparam         DH parameter file
-  certificate     certificate file
-  privatekey      private key
-  ocsp_file       file of stapling info (server); flag for require ocsp (client)
-  addr            address if client; NULL if server (for some randomness)
+#ifdef SSL_get_extms_support
+tls_in.ext_master_secret = SSL_get_extms_support(ssl) == 1;
+#endif
+peer_cert(ssl, &tls_in, peerdn, sizeof(peerdn));
 
-Returns:          OK/DEFER/FAIL
-*/
+tls_in.ver = tlsver_name(ssl);
+tls_in.cipher = construct_cipher_name(ssl, tls_in.ver, &tls_in.bits);
+tls_in.cipher_stdname = cipher_stdname_ssl(ssl);
 
-static int
-tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
-  uschar *privatekey,
-#ifdef EXPERIMENTAL_OCSP
-  uschar *ocsp_file,
-#endif
-  address_item *addr, tls_ext_ctx_cb ** cbp)
-{
-long init_options;
-int rc;
-BOOL okay;
-tls_ext_ctx_cb *cbinfo;
+DEBUG(D_tls)
+  {
+  uschar buf[2048];
+  if (SSL_get_shared_ciphers(ssl, CS buf, sizeof(buf)))
+    debug_printf("Shared ciphers: %s\n", buf);
 
-cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
-cbinfo->certificate = certificate;
-cbinfo->privatekey = privatekey;
-#ifdef EXPERIMENTAL_OCSP
-if ((cbinfo->is_server = host==NULL))
+#ifdef EXIM_HAVE_OPENSSL_KEYLOG
   {
-  cbinfo->u_ocsp.server.file = ocsp_file;
-  cbinfo->u_ocsp.server.file_expanded = NULL;
-  cbinfo->u_ocsp.server.response = NULL;
+  BIO * bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
+  SSL_SESSION_print_keylog(bp, SSL_get_session(ssl));
+  BIO_free(bp);
   }
-else
-  cbinfo->u_ocsp.client.verify_store = NULL;
 #endif
-cbinfo->dhparam = dhparam;
-cbinfo->host = host;
-
-SSL_load_error_strings();          /* basic set up */
-OpenSSL_add_ssl_algorithms();
 
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-/* SHA256 is becoming ever more popular. This makes sure it gets added to the
-list of available digests. */
-EVP_add_digest(EVP_sha256());
+#ifdef EXIM_HAVE_SESSION_TICKET
+  {
+  SSL_SESSION * ss = SSL_get_session(ssl);
+  if (SSL_SESSION_has_ticket(ss))      /* 1.1.0 */
+    debug_printf("The session has a ticket, life %lu seconds\n",
+      SSL_SESSION_get_ticket_lifetime_hint(ss));
+  }
 #endif
+  }
 
-/* Create a context.
-The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant
-negotiation in the different methods; as far as I can tell, the only
-*_{server,client}_method which allows negotiation is SSLv23, which exists even
-when OpenSSL is built without SSLv2 support.
-By disabling with openssl_options, we can let admins re-enable with the
-existing knob. */
-
-*ctxp = SSL_CTX_new((host == NULL)?
-  SSLv23_server_method() : SSLv23_client_method());
+/* Record the certificate we presented */
+  {
+  X509 * crt = SSL_get_certificate(ssl);
+  tls_in.ourcert = crt ? X509_dup(crt) : NULL;
+  }
 
-if (*ctxp == NULL) return tls_error(US"SSL_CTX_new", host, NULL);
+/* Channel-binding info for authenticators
+See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ */
+  {
+  uschar c, * s;
+  size_t len = SSL_get_peer_finished(ssl, &c, 0);
+  int old_pool = store_pool;
+
+  SSL_get_peer_finished(ssl, s = store_get((int)len, FALSE), len);
+  store_pool = POOL_PERM;
+    tls_in.channelbinding = b64encode_taint(CUS s, (int)len, FALSE);
+  store_pool = old_pool;
+  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p\n", tls_in.channelbinding);
+  }
 
-/* It turns out that we need to seed the random number generator this early in
-order to get the full complement of ciphers to work. It took me roughly a day
-of work to discover this by experiment.
+/* Only used by the server-side tls (tls_in), including tls_getc.
+   Client-side (tls_out) reads (seem to?) go via
+   smtp_read_response()/ip_recv().
+   Hence no need to duplicate for _in and _out.
+ */
+if (!ssl_xfer_buffer) ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
+ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
+ssl_xfer_eof = ssl_xfer_error = FALSE;
 
-On systems that have /dev/urandom, SSL may automatically seed itself from
-there. Otherwise, we have to make something up as best we can. Double check
-afterwards. */
+receive_getc = tls_getc;
+receive_getbuf = tls_getbuf;
+receive_get_cache = tls_get_cache;
+receive_ungetc = tls_ungetc;
+receive_feof = tls_feof;
+receive_ferror = tls_ferror;
+receive_smtp_buffered = tls_smtp_buffered;
 
-if (!RAND_status())
-  {
-  randstuff r;
-  gettimeofday(&r.tv, NULL);
-  r.p = getpid();
+tls_in.active.sock = fileno(smtp_out);
+tls_in.active.tls_ctx = NULL;  /* not using explicit ctx for server-side */
+return OK;
+}
 
-  RAND_seed((uschar *)(&r), sizeof(r));
-  RAND_seed((uschar *)big_buffer, big_buffer_size);
-  if (addr != NULL) RAND_seed((uschar *)addr, sizeof(addr));
 
-  if (!RAND_status())
-    return tls_error(US"RAND_status", host,
-      US"unable to seed random number generator");
-  }
 
-/* Set up the information callback, which outputs if debugging is at a suitable
-level. */
 
-SSL_CTX_set_info_callback(*ctxp, (void (*)())info_callback);
+static int
+tls_client_basic_ctx_init(SSL_CTX * ctx,
+    host_item * host, smtp_transport_options_block * ob, exim_openssl_state_st * state,
+    uschar ** errstr)
+{
+int rc;
 
-/* Automatically re-try reads/writes after renegotiation. */
-(void) SSL_CTX_set_mode(*ctxp, SSL_MODE_AUTO_RETRY);
+/* Back-compatible old behaviour if tls_verify_certificates is set but both
+tls_verify_hosts and tls_try_verify_hosts are not set. Check only the specified
+host patterns if one of them is set with content. */
+
+if (  (  (  !ob->tls_verify_hosts || !ob->tls_verify_hosts
+        || Ustrcmp(ob->tls_try_verify_hosts, ":") == 0
+        )
+      && (  !ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts
+        || Ustrcmp(ob->tls_try_verify_hosts, ":") == 0
+         )
+      )
+   || verify_check_given_host(CUSS &ob->tls_verify_hosts, host) == OK
+   )
+  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;
 
-/* Apply administrator-supplied work-arounds.
-Historically we applied just one requested option,
-SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS, but when bug 994 requested a second, we
-moved to an administrator-controlled list of options to specify and
-grandfathered in the first one as the default value for "openssl_options".
+  {
+  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);
 
-No OpenSSL version number checks: the options we accept depend upon the
-availability of the option value macros from OpenSSL.  */
+  if (state->lib_state.cabundle)
+    { DEBUG(D_tls) debug_printf("TLS: CA bundle was preloaded\n"); }
+  else
+    if ((rc = setup_certs(ctx, expcerts, ob->tls_crl, host, errstr)) != OK)
+      return rc;
 
-okay = tls_openssl_options_parse(openssl_options, &init_options);
-if (!okay)
-  return tls_error(US"openssl_options parsing failed", host, NULL);
+  if (expcerts && *expcerts)
+    setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
+  }
 
-if (init_options)
+if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
   {
-  DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
-  if (!(SSL_CTX_set_options(*ctxp, init_options)))
-    return tls_error(string_sprintf(
-          "SSL_CTX_set_option(%#lx)", init_options), host, NULL);
+  state->verify_cert_hostnames =
+#ifdef SUPPORT_I18N
+    string_domain_utf8_to_alabel(host->certname, NULL);
+#else
+    host->certname;
+#endif
+  DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
+                   state->verify_cert_hostnames);
   }
-else
-  DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
-
-/* Initialize with DH parameters if supplied */
+return OK;
+}
 
-if (!init_dh(*ctxp, dhparam, host)) return DEFER;
 
-/* Set up certificate and key (and perhaps OCSP info) */
+#ifdef SUPPORT_DANE
+static int
+dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa, uschar ** errstr)
+{
+dns_scan dnss;
+const char * hostnames[2] = { CS host->name, NULL };
+int found = 0;
 
-rc = tls_expand_session_files(*ctxp, cbinfo);
-if (rc != OK) return rc;
+if (DANESSL_init(ssl, NULL, hostnames) != 1)
+  return tls_error(US"hostnames load", host, NULL, errstr);
 
-/* If we need to handle SNI, do so */
-#ifdef EXIM_HAVE_OPENSSL_TLSEXT
-if (host == NULL)              /* server */
+for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
+     rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
+    ) if (rr->type == T_TLSA && rr->size > 3)
   {
-# ifdef EXPERIMENTAL_OCSP
-  /* We check u_ocsp.server.file, not server.response, because we care about if
-  the option exists, not what the current expansion might be, as SNI might
-  change the certificate and OCSP file in use between now and the time the
-  callback is invoked. */
-  if (cbinfo->u_ocsp.server.file)
-    {
-    SSL_CTX_set_tlsext_status_cb(server_ctx, tls_server_stapling_cb);
-    SSL_CTX_set_tlsext_status_arg(server_ctx, cbinfo);
-    }
-# endif
-  /* We always do this, so that $tls_sni is available even if not used in
-  tls_certificate */
-  SSL_CTX_set_tlsext_servername_callback(*ctxp, tls_servername_cb);
-  SSL_CTX_set_tlsext_servername_arg(*ctxp, cbinfo);
-  }
-# ifdef EXPERIMENTAL_OCSP
-else                   /* client */
-  if(ocsp_file)                /* wanting stapling */
-    {
-    if (!(cbinfo->u_ocsp.client.verify_store = X509_STORE_new()))
-      {
-      DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
-      return FAIL;
-      }
-    SSL_CTX_set_tlsext_status_cb(*ctxp, tls_client_stapling_cb);
-    SSL_CTX_set_tlsext_status_arg(*ctxp, cbinfo);
-    }
-# endif
-#endif
+  const uschar * p = rr->data;
+  uint8_t usage, selector, mtype;
+  const char * mdname;
 
-/* Set up the RSA callback */
+  usage = *p++;
 
-SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
+  /* Only DANE-TA(2) and DANE-EE(3) are supported */
+  if (usage != 2 && usage != 3) continue;
 
-/* Finally, set the timeout, and we are done */
+  selector = *p++;
+  mtype = *p++;
 
-SSL_CTX_set_timeout(*ctxp, ssl_session_timeout);
-DEBUG(D_tls) debug_printf("Initialized TLS\n");
+  switch (mtype)
+    {
+    default: continue; /* Only match-types 0, 1, 2 are supported */
+    case 0:  mdname = NULL; break;
+    case 1:  mdname = "sha256"; break;
+    case 2:  mdname = "sha512"; break;
+    }
 
-*cbp = cbinfo;
+  found++;
+  switch (DANESSL_add_tlsa(ssl, usage, selector, mdname, p, rr->size - 3))
+    {
+    default:
+      return tls_error(US"tlsa load", host, NULL, errstr);
+    case 0:    /* action not taken */
+    case 1:    break;
+    }
 
-return OK;
-}
+  tls_out.tlsa_usage |= 1<<usage;
+  }
 
+if (found)
+  return OK;
 
+log_write(0, LOG_MAIN, "DANE error: No usable TLSA records");
+return DEFER;
+}
+#endif /*SUPPORT_DANE*/
 
 
-/*************************************************
-*           Get name of cipher in use            *
-*************************************************/
 
-/*
-Argument:   pointer to an SSL structure for the connection
-            buffer to use for answer
-            size of buffer
-           pointer to number of bits for cipher
-Returns:    nothing
-*/
+#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. */
 
 static void
-construct_cipher_name(SSL *ssl, uschar *cipherbuf, int bsize, int *bits)
+tls_retrieve_session(tls_support * tlsp, SSL * ssl, const uschar * key)
 {
-/* With OpenSSL 1.0.0a, this needs to be const but the documentation doesn't
-yet reflect that.  It should be a safe change anyway, even 0.9.8 versions have
-the accessor functions use const in the prototype. */
-const SSL_CIPHER *c;
-const uschar *ver;
-
-ver = (const uschar *)SSL_get_version(ssl);
-
-c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
-SSL_CIPHER_get_bits(c, bits);
+tlsp->resumption |= RESUME_SUPPORTED;
+if (tlsp->host_resumable)
+  {
+  dbdata_tls_session * dt;
+  int len;
+  open_db dbblock, * dbm_file;
 
-string_format(cipherbuf, bsize, "%s:%s:%u", ver,
-  SSL_CIPHER_get_name(c), *bits);
+  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
+  DEBUG(D_tls) debug_printf("checking for resumable session for %s\n", key);
+  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
+    {
+    /* key for the db is the IP */
+    if ((dt = dbfn_read_with_length(dbm_file, key, &len)))
+      {
+      SSL_SESSION * ss = NULL;
+      const uschar * sess_asn1 = dt->session;
 
-DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf);
+      len -= sizeof(dbdata_tls_session);
+      if (!(d2i_SSL_SESSION(&ss, &sess_asn1, (long)len)))
+       {
+       DEBUG(D_tls)
+         {
+         ERR_error_string_n(ERR_get_error(),
+           ssl_errstring, sizeof(ssl_errstring));
+         debug_printf("decoding session: %s\n", ssl_errstring);
+         }
+       }
+      else
+       {
+       unsigned long lifetime =
+#ifdef EXIM_HAVE_SESSION_TICKET
+         SSL_SESSION_get_ticket_lifetime_hint(ss);
+#else                  /* Use, fairly arbitrilarily, what we as server would */
+         f.running_in_test_harness ? 6 : ssl_session_timeout;
+#endif
+       if (lifetime + dt->time_stamp < time(NULL))
+         {
+         DEBUG(D_tls) debug_printf("session expired\n");
+         dbfn_delete(dbm_file, key);
+         }
+       else if (!SSL_set_session(ssl, ss))
+         {
+         DEBUG(D_tls)
+           {
+           ERR_error_string_n(ERR_get_error(),
+             ssl_errstring, sizeof(ssl_errstring));
+           debug_printf("applying session to ssl: %s\n", ssl_errstring);
+           }
+         }
+       else
+         {
+         DEBUG(D_tls) debug_printf("good session\n");
+         tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
+         tlsp->verify_override = dt->verify_override;
+         tlsp->ocsp = dt->ocsp;
+         }
+       }
+      }
+    else
+      DEBUG(D_tls) debug_printf("no session record\n");
+    dbfn_close(dbm_file);
+    }
+  }
 }
 
 
+/* On the client, save the session for later resumption */
 
+static int
+tls_save_session_cb(SSL * ssl, SSL_SESSION * ss)
+{
+exim_openssl_state_st * cbinfo = SSL_get_ex_data(ssl, tls_exdata_idx);
+tls_support * tlsp;
 
+DEBUG(D_tls) debug_printf("tls_save_session_cb\n");
 
-/*************************************************
-*        Set up for verifying certificates       *
-*************************************************/
+if (!cbinfo || !(tlsp = cbinfo->tlsp)->host_resumable) return 0;
 
-/* Called by both client and server startup
+# ifdef OPENSSL_HAVE_NUM_TICKETS
+if (SSL_SESSION_is_resumable(ss))      /* 1.1.1 */
+# endif
+  {
+  int len = i2d_SSL_SESSION(ss, NULL);
+  int dlen = sizeof(dbdata_tls_session) + len;
+  dbdata_tls_session * dt = store_get(dlen, TRUE);
+  uschar * s = dt->session;
+  open_db dbblock, * dbm_file;
 
-Arguments:
-  sctx          SSL_CTX* to initialise
-  certs         certs file or NULL
-  crl           CRL file or NULL
-  host          NULL in a server; the remote host in a client
-  optional      TRUE if called from a server for a host in tls_try_verify_hosts;
-                otherwise passed as FALSE
-  cert_vfy_cb  Callback function for certificate verification
+  DEBUG(D_tls) debug_printf("session is resumable\n");
+  tlsp->resumption |= RESUME_SERVER_TICKET;    /* server gave us a ticket */
 
-Returns:        OK/DEFER/FAIL
-*/
+  dt->verify_override = tlsp->verify_override;
+  dt->ocsp = tlsp->ocsp;
+  (void) i2d_SSL_SESSION(ss, &s);              /* s gets bumped to end */
 
-static int
-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
-    int (*cert_vfy_cb)(int, X509_STORE_CTX *) )
-{
-uschar *expcerts, *expcrl;
+  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
+    {
+    const uschar * key = cbinfo->host->address;
+    dbfn_delete(dbm_file, key);
+    dbfn_write(dbm_file, key, dt, dlen);
+    dbfn_close(dbm_file);
+    DEBUG(D_tls) debug_printf("wrote session (len %u) to db\n",
+                 (unsigned)dlen);
+    }
+  }
+return 1;
+}
 
-if (!expand_check(certs, US"tls_verify_certificates", &expcerts))
-  return DEFER;
 
-if (expcerts != NULL && *expcerts != '\0')
+static void
+tls_client_ctx_resume_prehandshake(
+  exim_openssl_client_tls_ctx * exim_client_ctx, tls_support * tlsp,
+  smtp_transport_options_block * ob, host_item * host)
+{
+/* Should the client request a session resumption ticket? */
+if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
   {
-  struct stat statbuf;
-  if (!SSL_CTX_set_default_verify_paths(sctx))
-    return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
-
-  if (Ustat(expcerts, &statbuf) < 0)
-    {
-    log_write(0, LOG_MAIN|LOG_PANIC,
-      "failed to stat %s for certificates", expcerts);
-    return DEFER;
-    }
-  else
-    {
-    uschar *file, *dir;
-    if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
-      { file = NULL; dir = expcerts; }
-    else
-      { file = expcerts; dir = NULL; }
+  tlsp->host_resumable = TRUE;
 
-    /* If a certificate file is empty, the next function fails with an
-    unhelpful error message. If we skip it, we get the correct behaviour (no
-    certificates are recognized, but the error message is still misleading (it
-    says no certificate was supplied.) But this is better. */
+  SSL_CTX_set_session_cache_mode(exim_client_ctx->ctx,
+       SSL_SESS_CACHE_CLIENT
+       | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
+  SSL_CTX_sess_set_new_cb(exim_client_ctx->ctx, tls_save_session_cb);
+  }
+}
 
-    if ((file == NULL || statbuf.st_size > 0) &&
-          !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
-      return tls_error(US"SSL_CTX_load_verify_locations", host, NULL);
+static BOOL
+tls_client_ssl_resume_prehandshake(SSL * ssl, tls_support * tlsp,
+  host_item * host, uschar ** errstr)
+{
+if (tlsp->host_resumable)
+  {
+  DEBUG(D_tls)
+    debug_printf("tls_resumption_hosts overrides openssl_options, enabling tickets\n");
+  SSL_clear_options(ssl, SSL_OP_NO_TICKET);
 
-    if (file != NULL)
-      {
-      SSL_CTX_set_client_CA_list(sctx, SSL_load_client_CA_file(CS file));
-      }
+  tls_exdata_idx = SSL_get_ex_new_index(0, 0, 0, 0, 0);
+  if (!SSL_set_ex_data(ssl, tls_exdata_idx, client_static_state))
+    {
+    tls_error(US"set ex_data", host, NULL, errstr);
+    return FALSE;
     }
+  debug_printf("tls_exdata_idx %d cbinfo %p\n", tls_exdata_idx, client_static_state);
+  }
 
-  /* Handle a certificate revocation list. */
-
-  #if OPENSSL_VERSION_NUMBER > 0x00907000L
+tlsp->resumption = RESUME_SUPPORTED;
+/* Pick up a previous session, saved on an old ticket */
+tls_retrieve_session(tlsp, ssl, host->address);
+return TRUE;
+}
 
-  /* This bit of code is now the version supplied by Lars Mainka. (I have
-   * merely reformatted it into the Exim code style.)
+static void
+tls_client_resume_posthandshake(exim_openssl_client_tls_ctx * exim_client_ctx,
+  tls_support * tlsp)
+{
+if (SSL_session_reused(exim_client_ctx->ssl))
+  {
+  DEBUG(D_tls) debug_printf("The session was reused\n");
+  tlsp->resumption |= RESUME_USED;
+  }
+}
+#endif /* !DISABLE_TLS_RESUME */
 
-   * "From here I changed the code to add support for multiple crl's
-   * in pem format in one file or to support hashed directory entries in
-   * pem format instead of a file. This method now uses the library function
-   * X509_STORE_load_locations to add the CRL location to the SSL context.
-   * OpenSSL will then handle the verify against CA certs and CRLs by
-   * itself in the verify callback." */
 
-  if (!expand_check(crl, US"tls_crl", &expcrl)) return DEFER;
-  if (expcrl != NULL && *expcrl != 0)
-    {
-    struct stat statbufcrl;
-    if (Ustat(expcrl, &statbufcrl) < 0)
-      {
-      log_write(0, LOG_MAIN|LOG_PANIC,
-        "failed to stat %s for certificates revocation lists", expcrl);
-      return DEFER;
-      }
-    else
-      {
-      /* is it a file or directory? */
-      uschar *file, *dir;
-      X509_STORE *cvstore = SSL_CTX_get_cert_store(sctx);
-      if ((statbufcrl.st_mode & S_IFMT) == S_IFDIR)
-        {
-        file = NULL;
-        dir = expcrl;
-        DEBUG(D_tls) debug_printf("SSL CRL value is a directory %s\n", dir);
-        }
-      else
-        {
-        file = expcrl;
-        dir = NULL;
-        DEBUG(D_tls) debug_printf("SSL CRL value is a file %s\n", file);
-        }
-      if (X509_STORE_load_locations(cvstore, CS file, CS dir) == 0)
-        return tls_error(US"X509_STORE_load_locations", host, NULL);
+#ifdef EXIM_HAVE_ALPN
+/* Expand and convert an Exim list to an ALPN list.  False return for fail.
+NULL plist return for silent no-ALPN.
+*/
 
-      /* setting the flags to check against the complete crl chain */
+static BOOL
+tls_alpn_plist(const uschar * tls_alpn, const uschar ** plist, unsigned * plen,
+  uschar ** errstr)
+{
+uschar * exp_alpn;
 
-      X509_STORE_set_flags(cvstore,
-        X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
-      }
-    }
+if (!expand_check(tls_alpn, US"tls_alpn", &exp_alpn, errstr))
+  return FALSE;
 
-  #endif  /* OPENSSL_VERSION_NUMBER > 0x00907000L */
+if (!exp_alpn)
+  {
+  DEBUG(D_tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n");
+  *plist = NULL;
+  }
+else
+  {
+  /* The server implementation only accepts exactly one protocol name
+  but it's little extra code complexity in the client. */
 
-  /* If verification is optional, don't fail if no certificate */
+  const uschar * list = exp_alpn;
+  uschar * p = store_get(Ustrlen(exp_alpn), is_tainted(exp_alpn)), * s, * t;
+  int sep = 0;
+  uschar len;
 
-  SSL_CTX_set_verify(sctx,
-    SSL_VERIFY_PEER | (optional? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
-    cert_vfy_cb);
+  for (t = p; s = string_nextinlist(&list, &sep, NULL, 0); t += len)
+    {
+    *t++ = len = (uschar) Ustrlen(s);
+    memcpy(t, s, len);
+    }
+  *plist = (*plen = t - p) ? p : NULL;
   }
-
-return OK;
+return TRUE;
 }
-
+#endif /* EXIM_HAVE_ALPN */
 
 
 /*************************************************
-*       Start a TLS session in a server          *
+*    Start a TLS session in a client             *
 *************************************************/
 
-/* This is called when Exim is running as a server, after having received
-the STARTTLS command. It must respond to that command, and then negotiate
-a TLS session.
+/* Called from the smtp transport after STARTTLS has been accepted.
 
 Arguments:
-  require_ciphers   allowed ciphers
-
-Returns:            OK on success
-                    DEFER for errors before the start of the negotiation
-                    FAIL for errors during the negotation; the server can't
-                      continue running.
+  cctx         connection context
+  conn_args    connection details
+  cookie       datum for randomness; can be NULL
+  tlsp         record details of TLS channel configuration here; must be non-NULL
+  errstr       error string pointer
+
+Returns:       TRUE for success with TLS session context set in connection context,
+               FALSE on error
 */
 
-int
-tls_server_start(const uschar *require_ciphers)
+BOOL
+tls_client_start(client_conn_ctx * cctx, smtp_connect_args * conn_args,
+  void * cookie, tls_support * tlsp, uschar ** errstr)
 {
+host_item * host = conn_args->host;            /* for msgs and option-tests */
+transport_instance * tb = conn_args->tblock;   /* always smtp or NULL */
+smtp_transport_options_block * ob = tb
+  ? (smtp_transport_options_block *)tb->options_block
+  : &smtp_transport_option_defaults;
+exim_openssl_client_tls_ctx * exim_client_ctx;
+uschar * expciphers;
 int rc;
-uschar *expciphers;
-tls_ext_ctx_cb *cbinfo;
-static uschar cipherbuf[256];
+static uschar peerdn[256];
 
-/* Check for previous activation */
+#ifndef DISABLE_OCSP
+BOOL request_ocsp = FALSE;
+BOOL require_ocsp = FALSE;
+#endif
+
+rc = store_pool;
+store_pool = POOL_PERM;
+exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), FALSE);
+exim_client_ctx->corked = NULL;
+store_pool = rc;
 
-if (tls_in.active >= 0)
+#ifdef SUPPORT_DANE
+tlsp->tlsa_usage = 0;
+#endif
+
+#ifndef DISABLE_OCSP
   {
-  tls_error(US"STARTTLS received after TLS started", NULL, US"");
-  smtp_printf("554 Already in TLS\r\n");
-  return FAIL;
-  }
+# ifdef SUPPORT_DANE
+  /*XXX this should be moved to caller, to be common across gnutls/openssl */
+  if (  conn_args->dane
+     && ob->hosts_request_ocsp[0] == '*'
+     && ob->hosts_request_ocsp[1] == '\0'
+     )
+    {
+    /* Unchanged from default.  Use a safer one under DANE */
+    request_ocsp = TRUE;
+    ob->hosts_request_ocsp = US"${if or { {= {0}{$tls_out_tlsa_usage}} "
+                                     "   {= {4}{$tls_out_tlsa_usage}} } "
+                                " {*}{}}";
+    }
+# endif
 
-/* Initialize the SSL library. If it fails, it will already have logged
-the error. */
+  if ((require_ocsp =
+       verify_check_given_host(CUSS &ob->hosts_require_ocsp, host) == OK))
+    request_ocsp = TRUE;
+  else
+# ifdef SUPPORT_DANE
+    if (!request_ocsp)
+# endif
+      request_ocsp =
+       verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK;
+  }
+#endif
 
-rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey,
-#ifdef EXPERIMENTAL_OCSP
-    tls_ocsp_file,
+rc = tls_init(host, ob,
+#ifndef DISABLE_OCSP
+    (void *)(long)request_ocsp,
 #endif
-    NULL, &server_static_cbinfo);
-if (rc != OK) return rc;
-cbinfo = server_static_cbinfo;
+    cookie, &client_static_state, tlsp, errstr);
+if (rc != OK) return FALSE;
 
-if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
-  return FAIL;
+exim_client_ctx->ctx = client_static_state->lib_state.lib_ctx;
 
-/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
-were historically separated by underscores. So that I can use either form in my
-tests, and also for general convenience, we turn underscores into hyphens here.
-*/
+tlsp->certificate_verified = FALSE;
+client_verify_callback_called = FALSE;
 
-if (expciphers != NULL)
+expciphers = NULL;
+#ifdef SUPPORT_DANE
+if (conn_args->dane)
   {
-  uschar *s = expciphers;
-  while (*s != 0) { if (*s == '_') *s = '-'; s++; }
-  DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
-  if (!SSL_CTX_set_cipher_list(server_ctx, CS expciphers))
-    return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL);
-  cbinfo->server_cipher_list = expciphers;
+  /* We fall back to tls_require_ciphers if unset, empty or forced failure, but
+  other failures should be treated as problems. */
+  if (ob->dane_require_tls_ciphers &&
+      !expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers",
+        &expciphers, errstr))
+    return FALSE;
+  if (expciphers && *expciphers == '\0')
+    expciphers = NULL;
   }
+#endif
+if (!expciphers &&
+    !expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
+      &expciphers, errstr))
+  return FALSE;
 
-/* If this is a host for which certificate verification is mandatory or
-optional, set up appropriately. */
-
-tls_in.certificate_verified = FALSE;
-server_verify_callback_called = FALSE;
+/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
+are separated by underscores. So that I can use either form in my tests, and
+also for general convenience, we turn underscores into hyphens here. */
 
-if (verify_check_host(&tls_verify_hosts) == OK)
+if (expciphers)
   {
-  rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
-                       FALSE, verify_callback_server);
-  if (rc != OK) return rc;
-  server_verify_optional = FALSE;
+  uschar *s = expciphers;
+  while (*s) { if (*s == '_') *s = '-'; s++; }
+  DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
+  if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers))
+    {
+    tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr);
+    return FALSE;
+    }
   }
-else if (verify_check_host(&tls_try_verify_hosts) == OK)
+
+#ifdef SUPPORT_DANE
+if (conn_args->dane)
   {
-  rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
-                       TRUE, verify_callback_server);
-  if (rc != OK) return rc;
-  server_verify_optional = TRUE;
+  SSL_CTX_set_verify(exim_client_ctx->ctx,
+    SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+    verify_callback_client_dane);
+
+  if (!DANESSL_library_init())
+    {
+    tls_error(US"library init", host, NULL, errstr);
+    return FALSE;
+    }
+  if (DANESSL_CTX_init(exim_client_ctx->ctx) <= 0)
+    {
+    tls_error(US"context init", host, NULL, errstr);
+    return FALSE;
+    }
   }
+else
 
-/* Prepare for new connection */
+#endif
 
-if ((server_ssl = SSL_new(server_ctx)) == NULL) return tls_error(US"SSL_new", NULL, NULL);
+if (tls_client_basic_ctx_init(exim_client_ctx->ctx, host, ob,
+      client_static_state, errstr) != OK)
+  return FALSE;
 
-/* Warning: we used to SSL_clear(ssl) here, it was removed.
- *
- * With the SSL_clear(), we get strange interoperability bugs with
- * OpenSSL 1.0.1b and TLS1.1/1.2.  It looks as though this may be a bug in
- * OpenSSL itself, as a clear should not lead to inability to follow protocols.
- *
- * The SSL_clear() call is to let an existing SSL* be reused, typically after
- * session shutdown.  In this case, we have a brand new object and there's no
- * obvious reason to immediately clear it.  I'm guessing that this was
- * originally added because of incomplete initialisation which the clear fixed,
- * in some historic release.
- */
+#ifndef DISABLE_TLS_RESUME
+tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
+#endif
 
-/* Set context and tell client to go ahead, except in the case of TLS startup
-on connection, where outputting anything now upsets the clients and tends to
-make them disconnect. We need to have an explicit fflush() here, to force out
-the response. Other smtp_printf() calls do not need it, because in non-TLS
-mode, the fflush() happens when smtp_getc() is called. */
 
-SSL_set_session_id_context(server_ssl, sid_ctx, Ustrlen(sid_ctx));
-if (!tls_in.on_connect)
+if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
   {
-  smtp_printf("220 TLS go ahead\r\n");
-  fflush(smtp_out);
+  tls_error(US"SSL_new", host, NULL, errstr);
+  return FALSE;
   }
+SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
 
-/* Now negotiate the TLS session. We put our own timer on it, since it seems
-that the OpenSSL library doesn't. */
-
-SSL_set_wfd(server_ssl, fileno(smtp_out));
-SSL_set_rfd(server_ssl, fileno(smtp_in));
-SSL_set_accept_state(server_ssl);
+SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
+SSL_set_connect_state(exim_client_ctx->ssl);
 
-DEBUG(D_tls) debug_printf("Calling SSL_accept\n");
-
-sigalrm_seen = FALSE;
-if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-rc = SSL_accept(server_ssl);
-alarm(0);
-
-if (rc <= 0)
+if (ob->tls_sni)
   {
-  tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL);
-  if (ERR_get_error() == 0)
-    log_write(0, LOG_MAIN,
-        "TLS client disconnected cleanly (rejected our certificate?)");
-  return FAIL;
+  if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr))
+    return FALSE;
+  if (!tlsp->sni)
+    {
+    DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n");
+    }
+  else if (!Ustrlen(tlsp->sni))
+    tlsp->sni = NULL;
+  else
+    {
+#ifdef EXIM_HAVE_OPENSSL_TLSEXT
+    DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tlsp->sni);
+    SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni);
+#else
+    log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; ignoring \"%s\"\n",
+          tlsp->sni);
+#endif
+    }
   }
 
-DEBUG(D_tls) debug_printf("SSL_accept was successful\n");
+if (ob->tls_alpn)
+#ifdef EXIM_HAVE_ALPN
+  {
+  const uschar * plist;
+  unsigned plen;
 
-/* TLS has been set up. Adjust the input functions to read via TLS,
-and initialize things. */
+  if (!tls_alpn_plist(ob->tls_alpn, &plist, &plen, errstr))
+    return FALSE;
+  if (plist)
+    if (SSL_set_alpn_protos(exim_client_ctx->ssl, plist, plen) != 0)
+      {
+      tls_error(US"alpn init", host, NULL, errstr);
+      return FALSE;
+      }
+    else
+      DEBUG(D_tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn);
+  }
+#else
+  log_write(0, LOG_MAIN, "ALPN unusable with this OpenSSL library version; ignoring \"%s\"\n",
+          ob->tls_alpn);
+#endif
 
-construct_cipher_name(server_ssl, cipherbuf, sizeof(cipherbuf), &tls_in.bits);
-tls_in.cipher = cipherbuf;
+#ifdef SUPPORT_DANE
+if (conn_args->dane)
+  if (dane_tlsa_load(exim_client_ctx->ssl, host, &conn_args->tlsa_dnsa, errstr) != OK)
+    return FALSE;
+#endif
 
-DEBUG(D_tls)
+#ifndef DISABLE_OCSP
+/* Request certificate status at connection-time.  If the server
+does OCSP stapling we will get the callback (set in tls_init()) */
+# ifdef SUPPORT_DANE
+if (request_ocsp)
   {
-  uschar buf[2048];
-  if (SSL_get_shared_ciphers(server_ssl, CS buf, sizeof(buf)) != NULL)
-    debug_printf("Shared ciphers: %s\n", buf);
+  const uschar * s;
+  if (  ((s = ob->hosts_require_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage"))
+     || ((s = ob->hosts_request_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage"))
+     )
+    {  /* Re-eval now $tls_out_tlsa_usage is populated.  If
+       this means we avoid the OCSP request, we wasted the setup
+       cost in tls_init(). */
+    require_ocsp = verify_check_given_host(CUSS &ob->hosts_require_ocsp, host) == OK;
+    request_ocsp = require_ocsp
+      || verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK;
+    }
   }
+# endif
 
-/* Record the certificate we presented */
+if (request_ocsp)
   {
-  X509 * crt = SSL_get_certificate(server_ssl);
-  tls_in.ourcert = crt ? X509_dup(crt) : NULL;
+  SSL_set_tlsext_status_type(exim_client_ctx->ssl, TLSEXT_STATUSTYPE_ocsp);
+  client_static_state->u_ocsp.client.verify_required = require_ocsp;
+  tlsp->ocsp = OCSP_NOT_RESP;
   }
+#endif
 
-/* Only used by the server-side tls (tls_in), including tls_getc.
-   Client-side (tls_out) reads (seem to?) go via
-   smtp_read_response()/ip_recv().
-   Hence no need to duplicate for _in and _out.
- */
-ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
-ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
-ssl_xfer_eof = ssl_xfer_error = 0;
-
-receive_getc = tls_getc;
-receive_ungetc = tls_ungetc;
-receive_feof = tls_feof;
-receive_ferror = tls_ferror;
-receive_smtp_buffered = tls_smtp_buffered;
-
-tls_in.active = fileno(smtp_out);
-return OK;
-}
-
-
-
-
-
-/*************************************************
-*    Start a TLS session in a client             *
-*************************************************/
-
-/* Called from the smtp transport after STARTTLS has been accepted.
-
-Argument:
-  fd               the fd of the connection
-  host             connected host (for messages)
-  addr             the first address
-  ob               smtp transport options
-
-Returns:           OK on success
-                   FAIL otherwise - note that tls_error() will not give DEFER
-                     because this is not a server
-*/
+#ifndef DISABLE_TLS_RESUME
+if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
+      errstr))
+  return FALSE;
+#endif
 
-int
-tls_client_start(int fd, host_item *host, address_item *addr,
-  void *v_ob)
-{
-smtp_transport_options_block * ob = v_ob;
-static uschar txt[256];
-uschar *expciphers;
-X509* server_cert;
-int rc;
-static uschar cipherbuf[256];
-#ifdef EXPERIMENTAL_OCSP
-BOOL require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp,
-  NULL, host->name, host->address, NULL) == OK;
-BOOL request_ocsp = require_ocsp ? TRUE
-  : verify_check_this_host(&ob->hosts_request_ocsp,
-      NULL, host->name, host->address, NULL) == OK;
-#endif
-
-rc = tls_init(&client_ctx, host, NULL,
-    ob->tls_certificate, ob->tls_privatekey,
-#ifdef EXPERIMENTAL_OCSP
-    (void *)(long)request_ocsp,
+#ifndef DISABLE_EVENT
+client_static_state->event_action = tb ? tb->event_action : NULL;
 #endif
-    addr, &client_static_cbinfo);
-if (rc != OK) return rc;
 
-tls_out.certificate_verified = FALSE;
-client_verify_callback_called = FALSE;
+/* There doesn't seem to be a built-in timeout on connection. */
 
-if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
-    &expciphers))
-  return FAIL;
+DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
+sigalrm_seen = FALSE;
+ALARM(ob->command_timeout);
+rc = SSL_connect(exim_client_ctx->ssl);
+ALARM_CLR(0);
 
-/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
-are separated by underscores. So that I can use either form in my tests, and
-also for general convenience, we turn underscores into hyphens here. */
+#ifdef SUPPORT_DANE
+if (conn_args->dane)
+  DANESSL_cleanup(exim_client_ctx->ssl);
+#endif
 
-if (expciphers != NULL)
+if (rc <= 0)
   {
-  uschar *s = expciphers;
-  while (*s != 0) { if (*s == '_') *s = '-'; s++; }
-  DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
-  if (!SSL_CTX_set_cipher_list(client_ctx, CS expciphers))
-    return tls_error(US"SSL_CTX_set_cipher_list", host, NULL);
+  tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL, errstr);
+  return FALSE;
   }
 
-/* stick to the old behaviour for compatibility if tls_verify_certificates is 
-   set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only
-   the specified host patterns if one of them is defined */
-if ((!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) ||
-    (verify_check_host(&ob->tls_verify_hosts) == OK))
+DEBUG(D_tls)
   {
-  if ((rc = setup_certs(client_ctx, ob->tls_verify_certificates,
-       ob->tls_crl, host, FALSE, verify_callback_client)) != OK)
-    return rc;
-  client_verify_optional = FALSE;
-  }
-else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
+  debug_printf("SSL_connect succeeded\n");
+#ifdef EXIM_HAVE_OPENSSL_KEYLOG
   {
-  if ((rc = setup_certs(client_ctx, ob->tls_verify_certificates,
-       ob->tls_crl, host, TRUE, verify_callback_client)) != OK)
-    return rc;
-  client_verify_optional = TRUE;
+  BIO * bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
+  SSL_SESSION_print_keylog(bp, SSL_get_session(exim_client_ctx->ssl));
+  BIO_free(bp);
+  }
+#endif
   }
 
-if ((client_ssl = SSL_new(client_ctx)) == NULL)
-  return tls_error(US"SSL_new", host, NULL);
-SSL_set_session_id_context(client_ssl, sid_ctx, Ustrlen(sid_ctx));
-SSL_set_fd(client_ssl, fd);
-SSL_set_connect_state(client_ssl);
+#ifndef DISABLE_TLS_RESUME
+tls_client_resume_posthandshake(exim_client_ctx, tlsp);
+#endif
 
-if (ob->tls_sni)
+#ifdef EXIM_HAVE_ALPN
+if (ob->tls_alpn)      /* We requested. See what was negotiated. */
   {
-  if (!expand_check(ob->tls_sni, US"tls_sni", &tls_out.sni))
-    return FAIL;
-  if (tls_out.sni == NULL)
+  const uschar * name;
+  unsigned len;
+
+  SSL_get0_alpn_selected(exim_client_ctx->ssl, &name, &len);
+  if (len > 0)
+    { DEBUG(D_tls) debug_printf("ALPN negotiated %u: '%.*s'\n", len, (int)*name, name+1); }
+  else if (verify_check_given_host(CUSS &ob->hosts_require_alpn, host) == OK)
     {
-    DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n");
+    /* Would like to send a relevant fatal Alert, but OpenSSL has no API */
+    tls_error(US"handshake", host, US"ALPN required but not negotiated", errstr);
+    return FALSE;
     }
-  else if (!Ustrlen(tls_out.sni))
-    tls_out.sni = NULL;
-  else
-    {
-#ifdef EXIM_HAVE_OPENSSL_TLSEXT
-    DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_out.sni);
-    SSL_set_tlsext_host_name(client_ssl, tls_out.sni);
-#else
-    DEBUG(D_tls)
-      debug_printf("OpenSSL at build-time lacked SNI support, ignoring \"%s\"\n",
-          tls_out.sni);
+  }
 #endif
-    }
+
+#ifdef SSL_get_extms_support
+tlsp->ext_master_secret = SSL_get_extms_support(exim_client_ctx->ssl) == 1;
+#endif
+peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
+
+tlsp->ver = tlsver_name(exim_client_ctx->ssl);
+tlsp->cipher = construct_cipher_name(exim_client_ctx->ssl, tlsp->ver, &tlsp->bits);
+tlsp->cipher_stdname = cipher_stdname_ssl(exim_client_ctx->ssl);
+
+/* Record the certificate we presented */
+  {
+  X509 * crt = SSL_get_certificate(exim_client_ctx->ssl);
+  tlsp->ourcert = crt ? X509_dup(crt) : NULL;
   }
 
-#ifdef EXPERIMENTAL_OCSP
-/* Request certificate status at connection-time.  If the server
-does OCSP stapling we will get the callback (set in tls_init()) */
-if (request_ocsp)
+/*XXX will this work with continued-TLS? */
+/* Channel-binding info for authenticators */
   {
-  SSL_set_tlsext_status_type(client_ssl, TLSEXT_STATUSTYPE_ocsp);
-  client_static_cbinfo->u_ocsp.client.verify_required = require_ocsp;
-  tls_out.ocsp = OCSP_NOT_RESP;
+  uschar c, * s;
+  size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0);
+  int old_pool = store_pool;
+
+  SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, TRUE), len);
+  store_pool = POOL_PERM;
+    tlsp->channelbinding = b64encode_taint(CUS s, (int)len, TRUE);
+  store_pool = old_pool;
+  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp);
   }
-#endif
 
-/* There doesn't seem to be a built-in timeout on connection. */
+tlsp->active.sock = cctx->sock;
+tlsp->active.tls_ctx = exim_client_ctx;
+cctx->tls_ctx = exim_client_ctx;
+return TRUE;
+}
 
-DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
-sigalrm_seen = FALSE;
-alarm(ob->command_timeout);
-rc = SSL_connect(client_ssl);
-alarm(0);
 
-if (rc <= 0)
-  return tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL);
 
-DEBUG(D_tls) debug_printf("SSL_connect succeeded\n");
 
-/* Beware anonymous ciphers which lead to server_cert being NULL */
-/*XXX server_cert is never freed... use X509_free() */
-server_cert = SSL_get_peer_certificate (client_ssl);
-if (server_cert)
-  {
-  tls_out.peerdn = US X509_NAME_oneline(X509_get_subject_name(server_cert),
-    CS txt, sizeof(txt));
-  tls_out.peerdn = txt;                /*XXX a static buffer... */
-  }
-else
-  tls_out.peerdn = NULL;
 
-construct_cipher_name(client_ssl, cipherbuf, sizeof(cipherbuf), &tls_out.bits);
-tls_out.cipher = cipherbuf;
+static BOOL
+tls_refill(unsigned lim)
+{
+SSL * ssl = state_server.lib_state.lib_ssl;
+int error;
+int inbytes;
+
+DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
+  ssl_xfer_buffer, ssl_xfer_buffer_size);
 
-/* Record the certificate we presented */
+ERR_clear_error();
+if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
+inbytes = SSL_read(ssl, CS ssl_xfer_buffer,
+                 MIN(ssl_xfer_buffer_size, lim));
+error = SSL_get_error(ssl, inbytes);
+if (smtp_receive_timeout > 0) ALARM_CLR(0);
+
+if (had_command_timeout)               /* set by signal handler */
+  smtp_command_timeout_exit();         /* does not return */
+if (had_command_sigterm)
+  smtp_command_sigterm_exit();
+if (had_data_timeout)
+  smtp_data_timeout_exit();
+if (had_data_sigint)
+  smtp_data_sigint_exit();
+
+/* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been
+closed down, not that the socket itself has been closed down. Revert to
+non-SSL handling. */
+
+switch(error)
   {
-  X509 * crt = SSL_get_certificate(client_ssl);
-  tls_out.ourcert = crt ? X509_dup(crt) : NULL;
-  }
+  case SSL_ERROR_NONE:
+    break;
 
-tls_out.active = fd;
-return OK;
-}
+  case SSL_ERROR_ZERO_RETURN:
+    DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
+
+    if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN)
+         SSL_shutdown(ssl);
+
+    tls_close(NULL, TLS_NO_SHUTDOWN);
+    return FALSE;
 
+  /* Handle genuine errors */
+  case SSL_ERROR_SSL:
+    ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+    log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
+    ssl_xfer_error = TRUE;
+    return FALSE;
 
+  default:
+    DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
+    DEBUG(D_tls) if (error == SSL_ERROR_SYSCALL)
+      debug_printf(" - syscall %s\n", strerror(errno));
+    ssl_xfer_error = TRUE;
+    return FALSE;
+  }
 
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
+#endif
+ssl_xfer_buffer_hwm = inbytes;
+ssl_xfer_buffer_lwm = 0;
+return TRUE;
+}
 
 
 /*************************************************
@@ -1655,109 +4108,97 @@ return OK;
 /* This gets the next byte from the TLS input buffer. If the buffer is empty,
 it refills the buffer via the SSL reading function.
 
-Arguments:  none
+Arguments:  lim                Maximum amount to read/buffer
 Returns:    the next character or EOF
 
 Only used by the server-side TLS.
 */
 
 int
-tls_getc(void)
+tls_getc(unsigned lim)
 {
 if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
-  {
-  int error;
-  int inbytes;
+  if (!tls_refill(lim))
+    return ssl_xfer_error ? EOF : smtp_getc(lim);
 
-  DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
-    ssl_xfer_buffer, ssl_xfer_buffer_size);
+/* Something in the buffer; return next uschar */
 
-  if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-  inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer, ssl_xfer_buffer_size);
-  error = SSL_get_error(server_ssl, inbytes);
-  alarm(0);
+return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+}
 
-  /* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been
-  closed down, not that the socket itself has been closed down. Revert to
-  non-SSL handling. */
+uschar *
+tls_getbuf(unsigned * len)
+{
+unsigned size;
+uschar * buf;
 
-  if (error == SSL_ERROR_ZERO_RETURN)
+if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
+  if (!tls_refill(*len))
     {
-    DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
-
-    receive_getc = smtp_getc;
-    receive_ungetc = smtp_ungetc;
-    receive_feof = smtp_feof;
-    receive_ferror = smtp_ferror;
-    receive_smtp_buffered = smtp_buffered;
-
-    SSL_free(server_ssl);
-    server_ssl = NULL;
-    tls_in.active = -1;
-    tls_in.bits = 0;
-    tls_in.cipher = NULL;
-    tls_in.peerdn = NULL;
-    tls_in.sni = NULL;
-
-    return smtp_getc();
+    if (!ssl_xfer_error) return smtp_getbuf(len);
+    *len = 0;
+    return NULL;
     }
 
-  /* Handle genuine errors */
-
-  else if (error == SSL_ERROR_SSL)
-    {
-    ERR_error_string(ERR_get_error(), ssl_errstring);
-    log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
-    ssl_xfer_error = 1;
-    return EOF;
-    }
+if ((size = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm) > *len)
+  size = *len;
+buf = &ssl_xfer_buffer[ssl_xfer_buffer_lwm];
+ssl_xfer_buffer_lwm += size;
+*len = size;
+return buf;
+}
 
-  else if (error != SSL_ERROR_NONE)
-    {
-    DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
-    ssl_xfer_error = 1;
-    return EOF;
-    }
 
+void
+tls_get_cache(unsigned lim)
+{
 #ifndef DISABLE_DKIM
-  dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
+int n = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm;
+debug_printf("tls_get_cache\n");
+if (n > lim)
+  n = lim;
+if (n > 0)
+  dkim_exim_verify_feed(ssl_xfer_buffer+ssl_xfer_buffer_lwm, n);
 #endif
-  ssl_xfer_buffer_hwm = inbytes;
-  ssl_xfer_buffer_lwm = 0;
-  }
+}
 
-/* Something in the buffer; return next uschar */
 
-return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+BOOL
+tls_could_read(void)
+{
+return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm
+    || SSL_pending(state_server.lib_state.lib_ssl) > 0;
 }
 
 
-
 /*************************************************
 *          Read bytes from TLS channel           *
 *************************************************/
 
 /*
 Arguments:
+  ct_ctx    client context pointer, or NULL for the one global server context
   buff      buffer of data
   len       size of buffer
 
 Returns:    the number of bytes read
-            -1 after a failed read
+            -1 after a failed read, including EOF
 
 Only used by the client-side TLS.
 */
 
 int
-tls_read(BOOL is_server, uschar *buff, size_t len)
+tls_read(void * ct_ctx, uschar *buff, size_t len)
 {
-SSL *ssl = is_server ? server_ssl : client_ssl;
+SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl
+                 : state_server.lib_state.lib_ssl;
 int inbytes;
 int error;
 
 DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
   buff, (unsigned int)len);
 
+ERR_clear_error();
 inbytes = SSL_read(ssl, CS buff, len);
 error = SSL_get_error(ssl, inbytes);
 
@@ -1767,9 +4208,7 @@ if (error == SSL_ERROR_ZERO_RETURN)
   return -1;
   }
 else if (error != SSL_ERROR_NONE)
-  {
   return -1;
-  }
 
 return inbytes;
 }
@@ -1784,62 +4223,137 @@ return inbytes;
 
 /*
 Arguments:
-  is_server channel specifier
+  ct_ctx    client context pointer, or NULL for the one global server context
   buff      buffer of data
   len       number of bytes
+  more     further data expected soon
 
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
 
-Used by both server-side and client-side TLS.
+Used by both server-side and client-side TLS.  Calling with len zero and more unset
+will flush buffered writes; buff can be null for this case.
 */
 
 int
-tls_write(BOOL is_server, const uschar *buff, size_t len)
+tls_write(void * ct_ctx, const uschar * buff, size_t len, BOOL more)
 {
-int outbytes;
-int error;
-int left = len;
-SSL *ssl = is_server ? server_ssl : client_ssl;
+size_t olen = len;
+int outbytes, error;
+SSL * ssl = ct_ctx
+  ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl
+  : state_server.lib_state.lib_ssl;
+static gstring * server_corked = NULL;
+gstring ** corkedp = ct_ctx
+  ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked;
+gstring * corked = *corkedp;
+
+DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
+  buff, (unsigned long)len, more ? ", more" : "");
+
+/* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when
+"more" is notified.  This hack is only ok if small amounts are involved AND only
+one stream does it, in one context (i.e. no store reset).  Currently it is used
+for the responses to the received SMTP MAIL , RCPT, DATA sequence, only.
+We support callouts done by the server process by using a separate client
+context for the stashed information. */
+/* + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
+a store reset there, so use POOL_PERM. */
+/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
+
+if (more || corked)
+  {
+  if (!len) buff = US &error;  /* dummy just so that string_catn is ok */
+
+  int save_pool = store_pool;
+  store_pool = POOL_PERM;
+
+  corked = string_catn(corked, buff, len);
+
+  store_pool = save_pool;
+
+  if (more)
+    {
+    *corkedp = corked;
+    return len;
+    }
+  buff = CUS corked->s;
+  len = corked->ptr;
+  *corkedp = NULL;
+  }
 
-DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left);
-while (left > 0)
+for (int left = len; left > 0;)
   {
-  DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left);
+  DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left);
+  ERR_clear_error();
   outbytes = SSL_write(ssl, CS buff, left);
   error = SSL_get_error(ssl, outbytes);
   DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error);
   switch (error)
     {
-    case SSL_ERROR_SSL:
-    ERR_error_string(ERR_get_error(), ssl_errstring);
-    log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring);
-    return -1;
+    case SSL_ERROR_NONE:       /* the usual case */
+      left -= outbytes;
+      buff += outbytes;
+      break;
 
-    case SSL_ERROR_NONE:
-    left -= outbytes;
-    buff += outbytes;
-    break;
+    case SSL_ERROR_SSL:
+      ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+      log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring);
+      return -1;
 
     case SSL_ERROR_ZERO_RETURN:
-    log_write(0, LOG_MAIN, "SSL channel closed on write");
-    return -1;
+      log_write(0, LOG_MAIN, "SSL channel closed on write");
+      return -1;
 
     case SSL_ERROR_SYSCALL:
-    log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
-      sender_fullhost ? sender_fullhost : US"<unknown>",
-      strerror(errno));
+      if (ct_ctx || errno != ECONNRESET || !f.smtp_in_quit)
+       log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
+         sender_fullhost ? sender_fullhost : US"<unknown>",
+         strerror(errno));
+      else if (LOGGING(protocol_detail))
+       log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before"
+         " SMTP response and TLS close\n", sender_host_address);
+      else
+       DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT,"
+         " client reset TCP before TLS close\n", sender_host_address);
+      return -1;
 
     default:
-    log_write(0, LOG_MAIN, "SSL_write error %d", error);
-    return -1;
+      log_write(0, LOG_MAIN, "SSL_write error %d", error);
+      return -1;
     }
   }
-return len;
+return olen;
 }
 
 
 
+/*
+Arguments:
+  ct_ctx       client TLS context pointer, or NULL for the one global server context
+*/
+
+void
+tls_shutdown_wr(void * ct_ctx)
+{
+exim_openssl_client_tls_ctx * o_ctx = ct_ctx;
+SSL ** sslp = o_ctx ? &o_ctx->ssl : (SSL **) &state_server.lib_state.lib_ssl;
+int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
+int rc;
+
+if (*fdp < 0) return;  /* TLS was not active */
+
+tls_write(ct_ctx, NULL, 0, FALSE);     /* flush write buffer */
+
+HDEBUG(D_transport|D_tls|D_acl|D_v) debug_printf_indent("  SMTP(TLS shutdown)>>\n");
+rc = SSL_shutdown(*sslp);
+if (rc < 0) DEBUG(D_tls)
+  {
+  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+  debug_printf("SSL_shutdown: %s\n", ssl_errstring);
+  }
+}
+
 /*************************************************
 *         Close down a TLS session               *
 *************************************************/
@@ -1848,29 +4362,70 @@ return len;
 daemon, to shut down the TLS library, without actually doing a shutdown (which
 would tamper with the SSL session in the parent process).
 
-Arguments:   TRUE if SSL_shutdown is to be called
+Arguments:
+  ct_ctx       client TLS context pointer, or NULL for the one global server context
+  do_shutdown  0 no data-flush or TLS close-alert
+               1 if TLS close-alert is to be sent,
+               2 if also response to be waited for
+
 Returns:     nothing
 
 Used by both server-side and client-side TLS.
 */
 
 void
-tls_close(BOOL is_server, BOOL shutdown)
+tls_close(void * ct_ctx, int do_shutdown)
 {
-SSL **sslp = is_server ? &server_ssl : &client_ssl;
-int *fdp = is_server ? &tls_in.active : &tls_out.active;
+exim_openssl_client_tls_ctx * o_ctx = ct_ctx;
+SSL ** sslp = o_ctx ? &o_ctx->ssl : (SSL **) &state_server.lib_state.lib_ssl;
+int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
 
 if (*fdp < 0) return;  /* TLS was not active */
 
-if (shutdown)
+if (do_shutdown)
+  {
+  int rc;
+  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+    do_shutdown > 1 ? " (with response-wait)" : "");
+
+  tls_write(ct_ctx, NULL, 0, FALSE);   /* flush write buffer */
+
+  if (  (rc = SSL_shutdown(*sslp)) == 0        /* send "close notify" alert */
+     && do_shutdown > 1)
+    {
+    ALARM(2);
+    rc = SSL_shutdown(*sslp);          /* wait for response */
+    ALARM_CLR(0);
+    }
+
+  if (rc < 0) DEBUG(D_tls)
+    {
+    ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+    debug_printf("SSL_shutdown: %s\n", ssl_errstring);
+    }
+  }
+
+if (!o_ctx)            /* server side */
   {
-  DEBUG(D_tls) debug_printf("tls_close(): shutting down SSL\n");
-  SSL_shutdown(*sslp);
+#ifndef DISABLE_OCSP
+  sk_X509_pop_free(state_server.verify_stack, X509_free);
+  state_server.verify_stack = NULL;
+#endif
+
+  receive_getc =       smtp_getc;
+  receive_getbuf =     smtp_getbuf;
+  receive_get_cache =  smtp_get_cache;
+  receive_ungetc =     smtp_ungetc;
+  receive_feof =       smtp_feof;
+  receive_ferror =     smtp_ferror;
+  receive_smtp_buffered = smtp_buffered;
+  tls_in.active.tls_ctx = NULL;
+  tls_in.sni = NULL;
+  /* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
   }
 
 SSL_free(*sslp);
 *sslp = NULL;
-
 *fdp = -1;
 }
 
@@ -1893,21 +4448,13 @@ tls_validate_require_cipher(void)
 SSL_CTX *ctx;
 uschar *s, *expciphers, *err;
 
-/* this duplicates from tls_init(), we need a better "init just global
-state, for no specific purpose" singleton function of our own */
-
-SSL_load_error_strings();
-OpenSSL_add_ssl_algorithms();
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-/* SHA256 is becoming ever more popular. This makes sure it gets added to the
-list of available digests. */
-EVP_add_digest(EVP_sha256());
-#endif
+tls_openssl_init();
 
 if (!(tls_require_ciphers && *tls_require_ciphers))
   return NULL;
 
-if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers))
+if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers,
+                 &err))
   return US"failed to expand tls_require_ciphers";
 
 if (!(expciphers && *expciphers))
@@ -1919,24 +4466,20 @@ while (*s != 0) { if (*s == '_') *s = '-'; s++; }
 
 err = NULL;
 
-ctx = SSL_CTX_new(SSLv23_server_method());
-if (!ctx)
+if (lib_ctx_new(&ctx, NULL, &err) == OK)
   {
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  return string_sprintf("SSL_CTX_new() failed: %s", ssl_errstring);
-  }
+  DEBUG(D_tls)
+    debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers);
 
-DEBUG(D_tls)
-  debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers);
+  if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
+    {
+    ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
+    err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed: %s",
+                       expciphers, ssl_errstring);
+    }
 
-if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
-  {
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed", expciphers);
+  SSL_CTX_free(ctx);
   }
-
-SSL_CTX_free(ctx);
-
 return err;
 }
 
@@ -2000,7 +4543,6 @@ unsigned int r;
 int i, needed_len;
 static pid_t pidlast = 0;
 pid_t pidnow;
-uschar *p;
 uschar smallbuf[sizeof(r)];
 
 if (max <= 1)
@@ -2025,7 +4567,7 @@ if (!RAND_status())
   gettimeofday(&r.tv, NULL);
   r.p = getpid();
 
-  RAND_seed((uschar *)(&r), sizeof(r));
+  RAND_seed(US (&r), sizeof(r));
   }
 /* We're after pseudo-random, not random; if we still don't have enough data
 in the internal PRNG then our options are limited.  We could sleep and hope
@@ -2043,8 +4585,13 @@ i = (i + 7) / 8;
 if (i < needed_len)
   needed_len = i;
 
+#ifdef EXIM_HAVE_RAND_PSEUDO
 /* We do not care if crypto-strong */
 i = RAND_pseudo_bytes(smallbuf, needed_len);
+#else
+i = RAND_bytes(smallbuf, needed_len);
+#endif
+
 if (i < 0)
   {
   DEBUG(D_all)
@@ -2053,11 +4600,8 @@ if (i < 0)
   }
 
 r = 0;
-for (p = smallbuf; needed_len; --needed_len, ++p)
-  {
-  r *= 256;
-  r += *p;
-  }
+for (uschar * p = smallbuf; needed_len; --needed_len, ++p)
+  r = 256 * r + *p;
 
 /* We don't particularly care about weighted results; if someone wants
 smooth distribution and cares enough then they should submit a patch then. */
@@ -2079,110 +4623,6 @@ Arguments:
 Returns   success or failure in parsing
 */
 
-struct exim_openssl_option {
-  uschar *name;
-  long    value;
-};
-/* We could use a macro to expand, but we need the ifdef and not all the
-options document which version they were introduced in.  Policylet: include
-all options unless explicitly for DTLS, let the administrator choose which
-to apply.
-
-This list is current as of:
-  ==>  1.0.1b  <==
-Plus SSL_OP_SAFARI_ECDHE_ECDSA_BUG from 2013-June patch/discussion on openssl-dev
-*/
-static struct exim_openssl_option exim_openssl_options[] = {
-/* KEEP SORTED ALPHABETICALLY! */
-#ifdef SSL_OP_ALL
-  { US"all", SSL_OP_ALL },
-#endif
-#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
-  { US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
-#endif
-#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
-  { US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
-#endif
-#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
-  { US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
-#endif
-#ifdef SSL_OP_EPHEMERAL_RSA
-  { US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
-#endif
-#ifdef SSL_OP_LEGACY_SERVER_CONNECT
-  { US"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT },
-#endif
-#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
-  { US"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
-#endif
-#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
-  { US"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG },
-#endif
-#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
-  { US"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING },
-#endif
-#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
-  { US"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG },
-#endif
-#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
-  { US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
-#endif
-#ifdef SSL_OP_NO_COMPRESSION
-  { US"no_compression", SSL_OP_NO_COMPRESSION },
-#endif
-#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
-  { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
-#endif
-#ifdef SSL_OP_NO_SSLv2
-  { US"no_sslv2", SSL_OP_NO_SSLv2 },
-#endif
-#ifdef SSL_OP_NO_SSLv3
-  { US"no_sslv3", SSL_OP_NO_SSLv3 },
-#endif
-#ifdef SSL_OP_NO_TICKET
-  { US"no_ticket", SSL_OP_NO_TICKET },
-#endif
-#ifdef SSL_OP_NO_TLSv1
-  { US"no_tlsv1", SSL_OP_NO_TLSv1 },
-#endif
-#ifdef SSL_OP_NO_TLSv1_1
-#if SSL_OP_NO_TLSv1_1 == 0x00000400L
-  /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */
-#warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring
-#else
-  { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 },
-#endif
-#endif
-#ifdef SSL_OP_NO_TLSv1_2
-  { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 },
-#endif
-#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
-  { US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
-#endif
-#ifdef SSL_OP_SINGLE_DH_USE
-  { US"single_dh_use", SSL_OP_SINGLE_DH_USE },
-#endif
-#ifdef SSL_OP_SINGLE_ECDH_USE
-  { US"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE },
-#endif
-#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
-  { US"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
-#endif
-#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
-  { US"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
-#endif
-#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
-  { US"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG },
-#endif
-#ifdef SSL_OP_TLS_D5_BUG
-  { US"tls_d5_bug", SSL_OP_TLS_D5_BUG },
-#endif
-#ifdef SSL_OP_TLS_ROLLBACK_BUG
-  { US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
-#endif
-};
-static int exim_openssl_options_size =
-  sizeof(exim_openssl_options)/sizeof(struct exim_openssl_option);
 
 
 static BOOL
@@ -2228,24 +4668,37 @@ BOOL
 tls_openssl_options_parse(uschar *option_spec, long *results)
 {
 long result, item;
-uschar *s, *end;
-uschar keep_c;
+uschar * exp, * end;
 BOOL adding, item_parsed;
 
-result = 0L;
+/* Server: send no (<= TLS1.2) session tickets */
+result = SSL_OP_NO_TICKET;
+
 /* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
- * from default because it increases BEAST susceptibility. */
+from default because it increases BEAST susceptibility. */
 #ifdef SSL_OP_NO_SSLv2
 result |= SSL_OP_NO_SSLv2;
 #endif
+#ifdef SSL_OP_NO_SSLv3
+result |= SSL_OP_NO_SSLv3;
+#endif
+#ifdef SSL_OP_SINGLE_DH_USE
+result |= SSL_OP_SINGLE_DH_USE;
+#endif
+#ifdef SSL_OP_NO_RENEGOTIATION
+result |= SSL_OP_NO_RENEGOTIATION;
+#endif
 
-if (option_spec == NULL)
+if (!option_spec)
   {
   *results = result;
   return TRUE;
   }
 
-for (s=option_spec; *s != '\0'; /**/)
+if (!expand_check(option_spec, US"openssl_options", &exp, &end))
+  return FALSE;
+
+for (uschar * s = exp; *s; /**/)
   {
   while (isspace(*s)) ++s;
   if (*s == '\0')
@@ -2257,22 +4710,19 @@ for (s=option_spec; *s != '\0'; /**/)
     return FALSE;
     }
   adding = *s++ == '+';
-  for (end = s; (*end != '\0') && !isspace(*end); ++end) /**/ ;
-  keep_c = *end;
-  *end = '\0';
-  item_parsed = tls_openssl_one_option_parse(s, &item);
+  for (end = s; *end && !isspace(*end); ) end++;
+  item_parsed = tls_openssl_one_option_parse(string_copyn(s, end-s), &item);
   if (!item_parsed)
     {
     DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"\n", s);
     return FALSE;
     }
-  DEBUG(D_tls) debug_printf("openssl option, %s from %lx: %lx (%s)\n",
-      adding ? "adding" : "removing", result, item, s);
+  DEBUG(D_tls) debug_printf("openssl option, %s %08lx: %08lx (%s)\n",
+      adding ? "adding to    " : "removing from", result, item, s);
   if (adding)
     result |= item;
   else
     result &= ~item;
-  *end = keep_c;
   s = end;
   }
 
@@ -2280,6 +4730,7 @@ for (s=option_spec; *s != '\0'; /**/)
 return TRUE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
 /* End of tls-openssl.c */