Docs: more indexing of affix-related bits
[exim.git] / src / src / tls-openssl.c
index c09d9bdf6211c545e57c4496727d5dff81398fe4..53a967a196eb55da4f35009bf2f0db9dc934a332 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2017 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Portions Copyright (c) The OpenSSL Project 1999 */
@@ -28,8 +28,8 @@ functions from the OpenSSL library. */
 #ifndef DISABLE_OCSP
 # include <openssl/ocsp.h>
 #endif
-#ifdef EXPERIMENTAL_DANE
-# include <danessl.h>
+#ifdef SUPPORT_DANE
+# include "danessl.h"
 #endif
 
 
@@ -51,7 +51,7 @@ functions from the OpenSSL library. */
 # define EXIM_HAVE_RAND_PSEUDO
 #endif
 #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-# define EXIM_HAVE_SHA256
+# define EXIM_HAVE_SHA256      /*MMMM*/
 #endif
 
 /*
@@ -69,6 +69,8 @@ functions from the OpenSSL library. */
 #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
 # endif
 # if OPENSSL_VERSION_NUMBER >= 0x010000000L \
     && (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
@@ -80,7 +82,7 @@ functions from the OpenSSL library. */
     || LIBRESSL_VERSION_NUMBER >= 0x20010000L
 # if !defined(OPENSSL_NO_ECDH)
 #  if OPENSSL_VERSION_NUMBER >= 0x0090800fL
-#   define EXIM_HAVE_ECDH
+#   define EXIM_HAVE_ECDH      /*MMMM*/
 #  endif
 #  if OPENSSL_VERSION_NUMBER >= 0x10002000L
 #   define EXIM_HAVE_OPENSSL_EC_NIST2NID
@@ -93,6 +95,10 @@ functions from the OpenSSL library. */
 # define DISABLE_OCSP
 #endif
 
+#ifdef EXIM_HAVE_OPENSSL_CHECKHOST
+# include <openssl/x509v3.h>
+#endif
+
 /* Structure for collecting random data for seeding. */
 
 typedef struct randstuff {
@@ -111,7 +117,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.
@@ -125,9 +133,12 @@ Server:
  configuration.
 */
 
-static SSL_CTX *client_ctx = NULL;
+typedef struct {
+  SSL_CTX *    ctx;
+  SSL *                ssl;
+} exim_openssl_client_tls_ctx;
+
 static SSL_CTX *server_ctx = NULL;
-static SSL     *client_ssl = NULL;
 static SSL     *server_ssl = NULL;
 
 #ifdef EXIM_HAVE_OPENSSL_TLSEXT
@@ -146,8 +157,8 @@ static BOOL reexpand_tls_files_for_sni = FALSE;
 typedef struct tls_ext_ctx_cb {
   uschar *certificate;
   uschar *privatekey;
-#ifndef DISABLE_OCSP
   BOOL is_server;
+#ifndef DISABLE_OCSP
   STACK_OF(X509) *verify_stack;                /* chain for verifying the proof */
   union {
     struct {
@@ -227,14 +238,13 @@ return host ? FAIL : DEFER;
 
 
 
-#ifdef EXIM_HAVE_EPHEM_RSA_KEX
 /*************************************************
 *        Callback to generate RSA key            *
 *************************************************/
 
 /*
 Arguments:
-  s          SSL connection
+  s          SSL connection (not used)
   export     not used
   keylength  keylength
 
@@ -269,7 +279,6 @@ if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL)))
   }
 return rsa_key;
 }
-#endif
 
 
 
@@ -383,11 +392,13 @@ dn[sizeof(dn)-1] = '\0';
 
 if (preverify_ok == 0)
   {
-  log_write(0, LOG_MAIN, "[%s] SSL verify error: depth=%d error=%s cert=%s",
-       tlsp == &tls_out ? deliver_host_address : sender_host_address,
-    depth,
-    X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)),
-    dn);
+  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)
     {
@@ -425,7 +436,7 @@ else
 
   if (  tlsp == &tls_out
      && ((verify_cert_hostnames = client_static_cbinfo->verify_cert_hostnames)))
-       /* client, wanting hostname check */
+       /* client, wanting hostname check */
     {
 
 #ifdef EXIM_HAVE_OPENSSL_CHECKHOST
@@ -448,7 +459,7 @@ else
        if (rc < 0)
          {
          log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
-               deliver_host_address);
+           tlsp == &tls_out ? deliver_host_address : sender_host_address);
          name = NULL;
          }
        break;
@@ -458,10 +469,14 @@ 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: certificate name mismatch: "
-               "DN=\"%s\" H=\"%s\"",
-               deliver_host_address, dn, verify_cert_hostnames);
+       "[%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)
        {
@@ -503,7 +518,7 @@ return verify_callback(preverify_ok, x509ctx, &tls_in,
 }
 
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 
 /* This gets called *by* the dane library verify callback, which interposes
 itself.
@@ -531,8 +546,21 @@ DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n",
 #endif
 
 if (preverify_ok == 1)
-  tls_out.dane_verified =
-  tls_out.certificate_verified = TRUE;
+  {
+  tls_out.dane_verified = tls_out.certificate_verified = TRUE;
+#ifndef DISABLE_OCSP
+  if (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,
+                             cert))
+      ERR_clear_error();
+    sk_X509_push(client_static_cbinfo->verify_stack, cert);
+    }
+#endif
+  }
 else
   {
   int err = X509_STORE_CTX_get_error(x509ctx);
@@ -544,7 +572,7 @@ else
 return preverify_ok;
 }
 
-#endif /*EXPERIMENTAL_DANE*/
+#endif /*SUPPORT_DANE*/
 
 
 /*************************************************
@@ -595,6 +623,7 @@ BIO *bio;
 DH *dh;
 uschar *dhexpanded;
 const char *pem;
+int dh_bitsize;
 
 if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
   return FALSE;
@@ -635,21 +664,34 @@ if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)))
   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\n",
-        8*DH_size(dh), tls_dh_max_bits);
+        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);
@@ -868,7 +910,7 @@ 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) - 
+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?  */
@@ -914,15 +956,15 @@ if (!OCSP_check_validity(thisupd, nextupd, EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX
   }
 
 supply_response:
-  cbinfo->u_ocsp.server.response = resp;
+  cbinfo->u_ocsp.server.response = resp;       /*XXX stack?*/
 return;
 
 bad:
-  if (running_in_test_harness)
+  if (f.running_in_test_harness)
     {
     extern char ** environ;
     uschar ** p;
-    if (environ) for (p = USS environ; *p != NULL; p++)
+    if (environ) for (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");
@@ -956,8 +998,7 @@ if (!(x509 = X509_new()))
   goto err;
 
 where = US"generating pkey";
-               /* deprecated, use RSA_generate_key_ex() */
-if (!(rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL)))
+if (!(rsa = rsa_callback(NULL, 0, 1024)))
   goto err;
 
 where = US"assigning pkey";
@@ -965,7 +1006,7 @@ 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), 0);
+ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
 X509_gmtime_adj(X509_get_notBefore(x509), 0);
 X509_gmtime_adj(X509_get_notAfter(x509), (long)60 * 60);       /* 1 hour */
 X509_set_pubkey(x509, pkey);
@@ -1003,6 +1044,30 @@ err:
 
 
 
+static int
+tls_add_certfile(SSL_CTX * sctx, tls_ext_ctx_cb * 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, tls_ext_ctx_cb * 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;
+}
+
+
 /*************************************************
 *        Expand key and cert file specs          *
 *************************************************/
@@ -1027,14 +1092,16 @@ uschar *expanded;
 
 if (!cbinfo->certificate)
   {
-  if (cbinfo->host)                    /* client */
+  if (!cbinfo->is_server)              /* client */
     return OK;
-                                       /* server */
+                                       /* server */
   if (tls_install_selfsign(sctx, errstr) != OK)
     return DEFER;
   }
 else
   {
+  int err;
+
   if (Ustrstr(cbinfo->certificate, US"tls_sni") ||
       Ustrstr(cbinfo->certificate, US"tls_in_sni") ||
       Ustrstr(cbinfo->certificate, US"tls_out_sni")
@@ -1044,14 +1111,20 @@ else
   if (!expand_check(cbinfo->certificate, US"tls_certificate", &expanded, errstr))
     return DEFER;
 
-  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, errstr);
-    }
+  if (expanded)
+    if (cbinfo->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_certfile(sctx, cbinfo, file, errstr)))
+         return err;
+      }
+    else       /* would there ever be a need for multiple client certs? */
+      if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr)))
+       return err;
 
   if (cbinfo->privatekey != NULL &&
       !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
@@ -1062,17 +1135,25 @@ else
   key is in the same file as the certificate. */
 
   if (expanded && *expanded)
-    {
-    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, errstr);
-    }
+    if (cbinfo->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, cbinfo, file, errstr)))
+         return err;
+      }
+    else       /* would there ever be a need for multiple client certs? */
+      if ((err = tls_add_pkeyfile(sctx, cbinfo, expanded, errstr)))
+       return err;
   }
 
 #ifndef DISABLE_OCSP
 if (cbinfo->is_server && cbinfo->u_ocsp.server.file)
   {
+  /*XXX stack*/
   if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded, errstr))
     return DEFER;
 
@@ -1141,7 +1222,11 @@ if (!reexpand_tls_files_for_sni)
 not confident that memcpy wouldn't break some internal reference counting.
 Especially since there's a references struct member, which would be off. */
 
+#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
+if (!(server_sni = SSL_CTX_new(TLS_server_method())))
+#else
 if (!(server_sni = SSL_CTX_new(SSLv23_server_method())))
+#endif
   {
   ERR_error_string(ERR_get_error(), ssl_errstring);
   DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring);
@@ -1210,9 +1295,15 @@ static int
 tls_server_stapling_cb(SSL *s, void *arg)
 {
 const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
-uschar *response_der;
+uschar *response_der;  /*XXX blob */
 int response_der_len;
 
+/*XXX stack: use SSL_get_certificate() to see which cert; from that work
+out which ocsp blob to send.  Unfortunately, SSL_get_certificate is known
+buggy in current OpenSSL; it returns the last cert loaded always rather than
+the one actually presented.  So we can't support a stack of OCSP proofs at
+this time. */
+
 DEBUG(D_tls)
   debug_printf("Received TLS status request (OCSP stapling); %s response\n",
     cbinfo->u_ocsp.server.response ? "have" : "lack");
@@ -1222,7 +1313,7 @@ if (!cbinfo->u_ocsp.server.response)
   return SSL_TLSEXT_ERR_NOACK;
 
 response_der = NULL;
-response_der_len = i2d_OCSP_RESPONSE(cbinfo->u_ocsp.server.response,
+response_der_len = i2d_OCSP_RESPONSE(cbinfo->u_ocsp.server.response,   /*XXX stack*/
                      &response_der);
 if (response_der_len <= 0)
   return SSL_TLSEXT_ERR_NOACK;
@@ -1296,7 +1387,7 @@ if(!(bs = OCSP_response_get1_basic(rsp)))
     int status, reason;
     ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
 
-    DEBUG(D_tls) bp = BIO_new_fp(stderr, BIO_NOCLOSE);
+    DEBUG(D_tls) bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
 
     /*OCSP_RESPONSE_print(bp, rsp, 0);   extreme debug: stapling content */
 
@@ -1307,10 +1398,12 @@ if(!(bs = OCSP_response_get1_basic(rsp)))
              cbinfo->u_ocsp.client.verify_store, 0)) <= 0)
       {
       tls_out.ocsp = OCSP_FAILED;
-      if (LOGGING(tls_cipher))
-       log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable");
+      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;
       }
 
@@ -1414,7 +1507,7 @@ static int
 tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
   uschar *privatekey,
 #ifndef DISABLE_OCSP
-  uschar *ocsp_file,
+  uschar *ocsp_file,   /*XXX stack, in server*/
 #endif
   address_item *addr, tls_ext_ctx_cb ** cbp, uschar ** errstr)
 {
@@ -1426,9 +1519,10 @@ tls_ext_ctx_cb * cbinfo;
 cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
 cbinfo->certificate = certificate;
 cbinfo->privatekey = privatekey;
+cbinfo->is_server = host==NULL;
 #ifndef DISABLE_OCSP
 cbinfo->verify_stack = NULL;
-if ((cbinfo->is_server = host==NULL))
+if (!host)
   {
   cbinfo->u_ocsp.server.file = ocsp_file;
   cbinfo->u_ocsp.server.file_expanded = NULL;
@@ -1461,7 +1555,11 @@ when OpenSSL is built without SSLv2 support.
 By disabling with openssl_options, we can let admins re-enable with the
 existing knob. */
 
+#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);
 
 /* It turns out that we need to seed the random number generator this early in
@@ -1478,9 +1576,9 @@ if (!RAND_status())
   gettimeofday(&r.tv, NULL);
   r.p = getpid();
 
-  RAND_seed((uschar *)(&r), sizeof(r));
-  RAND_seed((uschar *)big_buffer, big_buffer_size);
-  if (addr != NULL) RAND_seed((uschar *)addr, sizeof(addr));
+  RAND_seed(US (&r), sizeof(r));
+  RAND_seed(US big_buffer, big_buffer_size);
+  if (addr != NULL) RAND_seed(US addr, sizeof(addr));
 
   if (!RAND_status())
     return tls_error(US"RAND_status", host,
@@ -1517,9 +1615,15 @@ if (init_options)
 else
   DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
 
-/* Disable session cache unconditionally */
-
+/* 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 */
@@ -1545,7 +1649,7 @@ if ((rc = tls_expand_session_files(ctx, cbinfo, errstr)) != OK)
     }
 # endif
 
-if (host == NULL)              /* server */
+if (!host)             /* server */
   {
 # ifndef DISABLE_OCSP
   /* We check u_ocsp.server.file, not server.response, because we care about if
@@ -1614,15 +1718,13 @@ Returns:    nothing
 static void
 construct_cipher_name(SSL *ssl, uschar *cipherbuf, int bsize, int *bits)
 {
-/* With OpenSSL 1.0.0a, this needs to be const but the documentation doesn't
+/* 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 uschar *ver;
 
-ver = (const uschar *)SSL_get_version(ssl);
+const uschar * ver = CUS SSL_get_version(ssl);
+const SSL_CIPHER * c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
 
-c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
 SSL_CIPHER_get_bits(c, bits);
 
 string_format(cipherbuf, bsize, "%s:%s:%u", ver,
@@ -1662,6 +1764,7 @@ else
 *        Set up for verifying certificates       *
 *************************************************/
 
+#ifndef DISABLE_OCSP
 /* Load certs from file, return TRUE on success */
 
 static BOOL
@@ -1670,16 +1773,21 @@ chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack)
 BIO * bp;
 X509 * x;
 
+while (sk_X509_num(verify_stack) > 0)
+  X509_free(sk_X509_pop(verify_stack));
+
 if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
 while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)))
   sk_X509_push(verify_stack, x);
 BIO_free(bp);
 return TRUE;
 }
+#endif
 
 
 
-/* Called by both client and server startup
+/* Called by both client and server startup; on the server possibly
+repeated after a Server Name Indication.
 
 Arguments:
   sctx          SSL_CTX* to initialise
@@ -1741,7 +1849,7 @@ if (expcerts && *expcerts)
           )
          {
          log_write(0, LOG_MAIN|LOG_PANIC,
-           "failed to load cert hain from %s", file);
+           "failed to load cert chain from %s", file);
          return DEFER;
          }
 #endif
@@ -1771,9 +1879,9 @@ if (expcerts && *expcerts)
        {
        STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
 
+       SSL_CTX_set_client_CA_list(sctx, names);
        DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
                                    sk_X509_NAME_num(names));
-       SSL_CTX_set_client_CA_list(sctx, names);
        }
       }
     }
@@ -1872,7 +1980,7 @@ static uschar cipherbuf[256];
 
 /* Check for previous activation */
 
-if (tls_in.active >= 0)
+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);
@@ -1884,7 +1992,7 @@ the error. */
 
 rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey,
 #ifndef DISABLE_OCSP
-    tls_ocsp_file,
+    tls_ocsp_file,     /*XXX stack*/
 #endif
     NULL, &server_static_cbinfo, errstr);
 if (rc != OK) return rc;
@@ -1896,6 +2004,10 @@ if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers, errstr)
 /* 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 (expciphers)
@@ -1912,7 +2024,7 @@ if (expciphers)
 optional, set up appropriately. */
 
 tls_in.certificate_verified = FALSE;
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 tls_in.dane_verified = FALSE;
 #endif
 server_verify_callback_called = FALSE;
@@ -1920,14 +2032,14 @@ server_verify_callback_called = FALSE;
 if (verify_check_host(&tls_verify_hosts) == OK)
   {
   rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
-                       FALSE, verify_callback_server, errstr);
+                       FALSE, verify_callback_server, errstr);
   if (rc != OK) return rc;
   server_verify_optional = FALSE;
   }
 else if (verify_check_host(&tls_try_verify_hosts) == OK)
   {
   rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
-                       TRUE, verify_callback_server, errstr);
+                       TRUE, verify_callback_server, errstr);
   if (rc != OK) return rc;
   server_verify_optional = TRUE;
   }
@@ -2011,9 +2123,9 @@ DEBUG(D_tls)
    smtp_read_response()/ip_recv().
    Hence no need to duplicate for _in and _out.
  */
-ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
+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 = 0;
+ssl_xfer_eof = ssl_xfer_error = FALSE;
 
 receive_getc = tls_getc;
 receive_getbuf = tls_getbuf;
@@ -2023,7 +2135,8 @@ receive_feof = tls_feof;
 receive_ferror = tls_ferror;
 receive_smtp_buffered = tls_smtp_buffered;
 
-tls_in.active = fileno(smtp_out);
+tls_in.active.sock = fileno(smtp_out);
+tls_in.active.tls_ctx = NULL;  /* not using explicit ctx for server-side */
 return OK;
 }
 
@@ -2043,7 +2156,7 @@ int rc;
 if (  (  !ob->tls_verify_hosts
       && (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts)
       )
-   || (verify_check_given_host(&ob->tls_verify_hosts, host) == OK)
+   || verify_check_given_host(&ob->tls_verify_hosts, host) == OK
    )
   client_verify_optional = FALSE;
 else if (verify_check_given_host(&ob->tls_try_verify_hosts, host) == OK)
@@ -2071,7 +2184,7 @@ return OK;
 }
 
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 static int
 dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa, uschar ** errstr)
 {
@@ -2126,7 +2239,7 @@ if (found)
 log_write(0, LOG_MAIN, "DANE error: No usable TLSA records");
 return DEFER;
 }
-#endif /*EXPERIMENTAL_DANE*/
+#endif /*SUPPORT_DANE*/
 
 
 
@@ -2138,27 +2251,28 @@ return DEFER;
 
 Argument:
   fd               the fd of the connection
-  host             connected host (for messages)
-  addr             the first address
+  host             connected host (for messages and option-tests)
+  addr             the first address (for some randomness; can be NULL)
   tb               transport (always smtp)
   tlsa_dnsa        tlsa lookup, if DANE, else null
+  tlsp            record details of channel configuration here; must be non-NULL
   errstr          error string pointer
 
-Returns:           OK on success
-                   FAIL otherwise - note that tls_error() will not give DEFER
-                     because this is not a server
+Returns:           Pointer to TLS session context, or NULL on error
 */
 
-int
+void *
 tls_client_start(int fd, host_item *host, address_item *addr,
   transport_instance * tb,
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
   dns_answer * tlsa_dnsa,
 #endif
-  uschar ** errstr)
+  tls_support * tlsp, uschar ** errstr)
 {
-smtp_transport_options_block * ob =
-  (smtp_transport_options_block *)tb->options_block;
+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;
 static uschar peerdn[256];
 uschar * expciphers;
 int rc;
@@ -2169,13 +2283,18 @@ BOOL request_ocsp = FALSE;
 BOOL require_ocsp = FALSE;
 #endif
 
-#ifdef EXPERIMENTAL_DANE
-tls_out.tlsa_usage = 0;
+rc = store_pool;
+store_pool = POOL_PERM;
+exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx));
+store_pool = rc;
+
+#ifdef SUPPORT_DANE
+tlsp->tlsa_usage = 0;
 #endif
 
 #ifndef DISABLE_OCSP
   {
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
   if (  tlsa_dnsa
      && ob->hosts_request_ocsp[0] == '*'
      && ob->hosts_request_ocsp[1] == '\0'
@@ -2193,7 +2312,7 @@ tls_out.tlsa_usage = 0;
        verify_check_given_host(&ob->hosts_require_ocsp, host) == OK))
     request_ocsp = TRUE;
   else
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
     if (!request_ocsp)
 # endif
       request_ocsp =
@@ -2201,20 +2320,35 @@ tls_out.tlsa_usage = 0;
   }
 #endif
 
-rc = tls_init(&client_ctx, host, NULL,
+rc = tls_init(&exim_client_ctx->ctx, host, NULL,
     ob->tls_certificate, ob->tls_privatekey,
 #ifndef DISABLE_OCSP
     (void *)(long)request_ocsp,
 #endif
     addr, &client_static_cbinfo, errstr);
-if (rc != OK) return rc;
+if (rc != OK) return NULL;
 
-tls_out.certificate_verified = FALSE;
+tlsp->certificate_verified = FALSE;
 client_verify_callback_called = FALSE;
 
-if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
-    &expciphers, errstr))
-  return FAIL;
+expciphers = NULL;
+#ifdef SUPPORT_DANE
+if (tlsa_dnsa)
+  {
+  /* 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 NULL;
+  if (expciphers && *expciphers == '\0')
+    expciphers = NULL;
+  }
+#endif
+if (!expciphers &&
+    !expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
+      &expciphers, errstr))
+  return NULL;
 
 /* 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
@@ -2225,68 +2359,80 @@ if (expciphers)
   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(client_ctx, CS expciphers))
-    return tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr);
+  if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers))
+    {
+    tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr);
+    return NULL;
+    }
   }
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
   {
-  SSL_CTX_set_verify(client_ctx,
+  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())
-    return tls_error(US"library init", host, NULL, errstr);
-  if (DANESSL_CTX_init(client_ctx) <= 0)
-    return tls_error(US"context init", host, NULL, errstr);
+    {
+    tls_error(US"library init", host, NULL, errstr);
+    return NULL;
+    }
+  if (DANESSL_CTX_init(exim_client_ctx->ctx) <= 0)
+    {
+    tls_error(US"context init", host, NULL, errstr);
+    return NULL;
+    }
   }
 else
 
 #endif
 
-  if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob,
-      client_static_cbinfo, errstr)) != OK)
-    return rc;
+  if (tls_client_basic_ctx_init(exim_client_ctx->ctx, host, ob,
+       client_static_cbinfo, errstr) != OK)
+    return NULL;
 
-if ((client_ssl = SSL_new(client_ctx)) == NULL)
-  return tls_error(US"SSL_new", host, NULL, errstr);
-SSL_set_session_id_context(client_ssl, sid_ctx, Ustrlen(sid_ctx));
-SSL_set_fd(client_ssl, fd);
-SSL_set_connect_state(client_ssl);
+if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
+  {
+  tls_error(US"SSL_new", host, NULL, errstr);
+  return NULL;
+  }
+SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
+SSL_set_fd(exim_client_ctx->ssl, fd);
+SSL_set_connect_state(exim_client_ctx->ssl);
 
 if (ob->tls_sni)
   {
-  if (!expand_check(ob->tls_sni, US"tls_sni", &tls_out.sni, errstr))
-    return FAIL;
-  if (!tls_out.sni)
+  if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr))
+    return NULL;
+  if (!tlsp->sni)
     {
     DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n");
     }
-  else if (!Ustrlen(tls_out.sni))
-    tls_out.sni = NULL;
+  else if (!Ustrlen(tlsp->sni))
+    tlsp->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);
+    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",
-          tls_out.sni);
+          tlsp->sni);
 #endif
     }
   }
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
-  if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa, errstr)) != OK)
-    return rc;
+  if (dane_tlsa_load(exim_client_ctx->ssl, host, tlsa_dnsa, errstr) != OK)
+    return NULL;
 #endif
 
 #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 EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
 if (request_ocsp)
   {
   const uschar * s;
@@ -2305,14 +2451,14 @@ if (request_ocsp)
 
 if (request_ocsp)
   {
-  SSL_set_tlsext_status_type(client_ssl, TLSEXT_STATUSTYPE_ocsp);
+  SSL_set_tlsext_status_type(exim_client_ctx->ssl, TLSEXT_STATUSTYPE_ocsp);
   client_static_cbinfo->u_ocsp.client.verify_required = require_ocsp;
-  tls_out.ocsp = OCSP_NOT_RESP;
+  tlsp->ocsp = OCSP_NOT_RESP;
   }
 #endif
 
 #ifndef DISABLE_EVENT
-client_static_cbinfo->event_action = tb->event_action;
+client_static_cbinfo->event_action = tb ? tb->event_action : NULL;
 #endif
 
 /* There doesn't seem to be a built-in timeout on connection. */
@@ -2320,33 +2466,36 @@ client_static_cbinfo->event_action = tb->event_action;
 DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
 sigalrm_seen = FALSE;
 alarm(ob->command_timeout);
-rc = SSL_connect(client_ssl);
+rc = SSL_connect(exim_client_ctx->ssl);
 alarm(0);
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
-  DANESSL_cleanup(client_ssl);
+  DANESSL_cleanup(exim_client_ctx->ssl);
 #endif
 
 if (rc <= 0)
-  return tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL,
-    errstr);
+  {
+  tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL, errstr);
+  return NULL;
+  }
 
 DEBUG(D_tls) debug_printf("SSL_connect succeeded\n");
 
-peer_cert(client_ssl, &tls_out, peerdn, sizeof(peerdn));
+peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
 
-construct_cipher_name(client_ssl, cipherbuf, sizeof(cipherbuf), &tls_out.bits);
-tls_out.cipher = cipherbuf;
+construct_cipher_name(exim_client_ctx->ssl, cipherbuf, sizeof(cipherbuf), &tlsp->bits);
+tlsp->cipher = cipherbuf;
 
 /* Record the certificate we presented */
   {
-  X509 * crt = SSL_get_certificate(client_ssl);
-  tls_out.ourcert = crt ? X509_dup(crt) : NULL;
+  X509 * crt = SSL_get_certificate(exim_client_ctx->ssl);
+  tlsp->ourcert = crt ? X509_dup(crt) : NULL;
   }
 
-tls_out.active = fd;
-return OK;
+tlsp->active.sock = fd;
+tlsp->active.tls_ctx = exim_client_ctx;
+return exim_client_ctx;
 }
 
 
@@ -2366,50 +2515,70 @@ if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
 inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
                  MIN(ssl_xfer_buffer_size, lim));
 error = SSL_get_error(server_ssl, inbytes);
-alarm(0);
+if (smtp_receive_timeout > 0) alarm(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. */
 
-if (error == SSL_ERROR_ZERO_RETURN)
+switch(error)
   {
-  DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
+  case SSL_ERROR_NONE:
+    break;
 
-  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;
-
-  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;
+  case SSL_ERROR_ZERO_RETURN:
+    DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
 
-  return FALSE;
-  }
+    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;
 
-/* Handle genuine errors */
+    if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
+         SSL_shutdown(server_ssl);
 
-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 FALSE;
-  }
+#ifndef DISABLE_OCSP
+    sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+    server_static_cbinfo->verify_stack = NULL;
+#endif
+    SSL_free(server_ssl);
+    SSL_CTX_free(server_ctx);
+    server_ctx = NULL;
+    server_ssl = NULL;
+    tls_in.active.sock = -1;
+    tls_in.active.tls_ctx = NULL;
+    tls_in.bits = 0;
+    tls_in.cipher = NULL;
+    tls_in.peerdn = NULL;
+    tls_in.sni = NULL;
 
-else if (error != SSL_ERROR_NONE)
-  {
-  DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
-  ssl_xfer_error = 1;
-  return FALSE;
+    return FALSE;
+
+  /* Handle genuine errors */
+  case 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 = 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
@@ -2493,19 +2662,20 @@ return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm || SSL_pending(server_ssl) > 0;
 
 /*
 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 : server_ssl;
 int inbytes;
 int error;
 
@@ -2536,7 +2706,7 @@ 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
@@ -2548,34 +2718,33 @@ Used by both server-side and client-side TLS.
 */
 
 int
-tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more)
+tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
 {
 int outbytes, error, left;
-SSL *ssl = is_server ? server_ssl : client_ssl;
-static uschar * corked = NULL;
-static int c_size = 0, c_len = 0;
+SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
+static gstring * corked = NULL;
 
-DEBUG(D_tls) debug_printf("%s(%p, %d%s)\n", __FUNCTION__,
-  buff, left, more ? ", more" : "");
+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. */
 
-if (is_server && (more || corked))
+if (!ct_ctx && (more || corked))
   {
-  corked = string_catn(corked, &c_size, &c_len, buff, len);
+  corked = string_catn(corked, buff, len);
   if (more)
     return len;
-  buff = CUS corked;
-  len = c_len;
-  corked = NULL; c_size = c_len = 0;
+  buff = CUS corked->s;
+  len = corked->ptr;
+  corked = NULL;
   }
 
 for (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);
   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);
@@ -2619,29 +2788,59 @@ 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
+  shutdown     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 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_CTX **ctxp = o_ctx ? &o_ctx->ctx : &server_ctx;
+SSL **sslp =     o_ctx ? &o_ctx->ssl : &server_ssl;
+int *fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
 
 if (*fdp < 0) return;  /* TLS was not active */
 
 if (shutdown)
   {
-  DEBUG(D_tls) debug_printf("tls_close(): shutting down SSL\n");
-  SSL_shutdown(*sslp);
+  int rc;
+  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+    shutdown > 1 ? " (with response-wait)" : "");
+
+  if (  (rc = SSL_shutdown(*sslp)) == 0        /* send "close notify" alert */
+     && shutdown > 1)
+    {
+    alarm(2);
+    rc = SSL_shutdown(*sslp);          /* wait for response */
+    alarm(0);
+    }
+
+  if (rc < 0) DEBUG(D_tls)
+    {
+    ERR_error_string(ERR_get_error(), ssl_errstring);
+    debug_printf("SSL_shutdown: %s\n", ssl_errstring);
+    }
+  }
+
+#ifndef DISABLE_OCSP
+if (!o_ctx)            /* server side */
+  {
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  server_static_cbinfo->verify_stack = NULL;
   }
+#endif
 
+SSL_CTX_free(*ctxp);
 SSL_free(*sslp);
+*ctxp = NULL;
 *sslp = NULL;
-
 *fdp = -1;
 }
 
@@ -2691,8 +2890,11 @@ while (*s != 0) { if (*s == '_') *s = '-'; s++; }
 
 err = NULL;
 
-ctx = SSL_CTX_new(SSLv23_server_method());
-if (!ctx)
+#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
+if (!(ctx = SSL_CTX_new(TLS_server_method())))
+#else
+if (!(ctx = SSL_CTX_new(SSLv23_server_method())))
+#endif
   {
   ERR_error_string(ERR_get_error(), ssl_errstring);
   return string_sprintf("SSL_CTX_new() failed: %s", ssl_errstring);
@@ -2798,7 +3000,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