Compiler quietening
[exim.git] / src / src / tls-openssl.c
index 85ba2e5bd9f1482ca2c7c9906083ef97fd2a45ca..969a99d997a4658328e25e29948ba5dc29de4a55 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* 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,20 +69,21 @@ 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
 # endif
 # if OPENSSL_VERSION_NUMBER >= 0x010000000L \
     && (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
 #  define EXIM_HAVE_OPENSSL_CHECKHOST
 # endif
+#endif
 
+#if !defined(LIBRESSL_VERSION_NUMBER) \
+    || 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
-#   if OPENSSL_VERSION_NUMBER < 0x10100000L
-#    define EXIM_HAVE_OPENSSL_ECDH_AUTO
-#   endif
 #   define EXIM_HAVE_OPENSSL_EC_NIST2NID
 #  endif
 # endif
@@ -93,6 +94,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 {
@@ -146,8 +151,9 @@ 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 {
       uschar        *file;
@@ -179,7 +185,7 @@ tls_ext_ctx_cb *server_static_cbinfo = NULL;
 
 static int
 setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
-    int (*cert_vfy_cb)(int, X509_STORE_CTX *) );
+    int (*cert_vfy_cb)(int, X509_STORE_CTX *), uschar ** errstr );
 
 /* Callbacks */
 #ifdef EXIM_HAVE_OPENSSL_TLSEXT
@@ -206,47 +212,33 @@ 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, const host_item * host, uschar *  msg)
+tls_error(uschar * prefix, const host_item * host, uschar * msg, uschar ** errstr)
 {
 if (!msg)
   {
   ERR_error_string(ERR_get_error(), ssl_errstring);
-  msg = (uschar *)ssl_errstring;
+  msg = US ssl_errstring;
   }
 
-if (host)
-  {
-  log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection (%s): %s",
-    host->name, host->address, prefix, msg);
-  return FAIL;
-  }
-else
-  {
-  uschar *conn_info = smtp_get_connection_info();
-  if (Ustrncmp(conn_info, US"SMTP ", 5) == 0)
-    conn_info += 5;
-  /* I'd like to get separated H= here, but too hard for now */
-  log_write(0, LOG_MAIN, "TLS error on %s (%s): %s",
-    conn_info, prefix, msg);
-  return DEFER;
-  }
+if (errstr) *errstr = string_sprintf("(%s): %s", prefix, msg);
+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
 
@@ -270,8 +262,7 @@ if (  !BN_set_word(bn, (unsigned long)RSA_F4)
    || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL)
    )
 #else
-rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
-if (rsa_key == NULL)
+if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL)))
 #endif
 
   {
@@ -282,7 +273,6 @@ if (rsa_key == NULL)
   }
 return rsa_key;
 }
-#endif
 
 
 
@@ -396,11 +386,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)
     {
@@ -424,6 +416,7 @@ else if (depth != 0)
     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
 #ifndef DISABLE_EVENT
@@ -460,7 +453,7 @@ else
        if (rc < 0)
          {
          log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
-               tlsp == &tls_out ? deliver_host_address : sender_host_address);
+           tlsp == &tls_out ? deliver_host_address : sender_host_address);
          name = NULL;
          }
        break;
@@ -470,10 +463,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: \"%s\"",
-               tlsp == &tls_out ? deliver_host_address : sender_host_address,
-               dn);
+       "[%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)
        {
@@ -515,7 +512,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.
@@ -525,8 +522,8 @@ verify_callback_client_dane(int preverify_ok, X509_STORE_CTX * x509ctx)
 {
 X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
 uschar dn[256];
-#ifndef DISABLE_EVENT
 int depth = X509_STORE_CTX_get_error_depth(x509ctx);
+#ifndef DISABLE_EVENT
 BOOL dummy_called, optional = FALSE;
 #endif
 
@@ -543,8 +540,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);
@@ -556,7 +566,7 @@ else
 return preverify_ok;
 }
 
-#endif /*EXPERIMENTAL_DANE*/
+#endif /*SUPPORT_DANE*/
 
 
 /*************************************************
@@ -595,19 +605,21 @@ Arguments:
   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:    TRUE if OK (nothing to set up, or setup worked)
 */
 
 static BOOL
-init_dh(SSL_CTX *sctx, uschar *dhparam, const host_item *host)
+init_dh(SSL_CTX *sctx, uschar *dhparam, const host_item *host, uschar ** errstr)
 {
 BIO *bio;
 DH *dh;
 uschar *dhexpanded;
 const char *pem;
+int dh_bitsize;
 
-if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded))
+if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
   return FALSE;
 
 if (!dhexpanded || !*dhexpanded)
@@ -617,7 +629,7 @@ else if (dhexpanded[0] == '/')
   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;
     }
   }
@@ -632,7 +644,7 @@ else
   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);
@@ -642,25 +654,38 @@ 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);
@@ -695,12 +720,13 @@ Patches welcome.
 Arguments:
   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 BOOL
-init_ecdh(SSL_CTX * sctx, host_item * host)
+init_ecdh(SSL_CTX * sctx, host_item * host, uschar ** errstr)
 {
 #ifdef OPENSSL_NO_ECDH
 return TRUE;
@@ -720,21 +746,37 @@ DEBUG(D_tls)
 return TRUE;
 # else
 
-if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve))
+if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
   return FALSE;
 if (!exp_curve || !*exp_curve)
   return TRUE;
 
-#  ifdef EXIM_HAVE_OPENSSL_ECDH_AUTO
-/* check if new enough library to support auto ECDH temp key parameter selection */
+/* "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)
   {
+#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 temp key parameter settings: OpenSSL 1.2+ autoselection\n");
+    "ECDH OpenSSL 1.0.2+ temp key parameter settings: autoselection\n");
   SSL_CTX_set_ecdh_auto(sctx, 1);
   return TRUE;
+# else
+  DEBUG(D_tls) debug_printf(
+    "ECDH OpenSSL 1.1.0+ temp key parameter settings: default selection\n");
+  return TRUE;
+# endif
+#endif
   }
-#  endif
 
 DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
 if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
@@ -743,15 +785,14 @@ if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
 #   endif
    )
   {
-  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'",
-      exp_curve),
-    host, NULL);
+  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
+    host, NULL, errstr);
   return FALSE;
   }
 
 if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
   {
-  tls_error(US"Unable to create ec curve", host, NULL);
+  tls_error(US"Unable to create ec curve", host, NULL, errstr);
   return FALSE;
   }
 
@@ -759,7 +800,7 @@ if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
 not to the stability of the interface. */
 
 if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
-  tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), host, NULL);
+  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);
 
@@ -777,7 +818,6 @@ return !rv;
 /*************************************************
 *       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.
@@ -794,12 +834,12 @@ Arguments:
 static void
 ocsp_load_response(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo, const uschar *expanded)
 {
-BIO *bio;
-OCSP_RESPONSE *resp;
-OCSP_BASICRESP *basic_response;
-OCSP_SINGLERESP *single_response;
-ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
-X509_STORE *store;
+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;
 
@@ -810,8 +850,7 @@ if (cbinfo->u_ocsp.server.response)
   cbinfo->u_ocsp.server.response = NULL;
   }
 
-bio = BIO_new_file(CS cbinfo->u_ocsp.server.file_expanded, "rb");
-if (!bio)
+if (!(bio = BIO_new_file(CS cbinfo->u_ocsp.server.file_expanded, "rb")))
   {
   DEBUG(D_tls) debug_printf("Failed to open OCSP response file \"%s\"\n",
       cbinfo->u_ocsp.server.file_expanded);
@@ -826,33 +865,54 @@ if (!resp)
   return;
   }
 
-status = OCSP_response_status(resp);
-if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+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;
   }
 
-basic_response = OCSP_response_get1_basic(resp);
-if (!basic_response)
+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;
   }
 
-store = SSL_CTX_get_cert_store(sctx);
+sk = cbinfo->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 */
 
-i = OCSP_basic_verify(basic_response, NULL, store, verify_flags);
-if (i <= 0)
+/* 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) {
+  DEBUG(D_tls)
+    {
     ERR_error_string(ERR_get_error(), ssl_errstring);
     debug_printf("OCSP response verify failure: %s\n", US ssl_errstring);
     }
@@ -866,8 +926,8 @@ proves false, we need to extract a cert id from our issued cert
 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 (!(single_response = OCSP_resp_get0(basic_response, 0)))
   {
   DEBUG(D_tls)
     debug_printf("Unable to get first response from OCSP basic response.\n");
@@ -890,7 +950,7 @@ 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:
@@ -898,7 +958,7 @@ bad:
     {
     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");
@@ -912,6 +972,96 @@ return;
 
 
 
+/* Create and install a selfsigned certificate, for use in server mode */
+
+static int
+tls_install_selfsign(SSL_CTX * sctx, uschar ** errstr)
+{
+X509 * x509 = NULL;
+EVP_PKEY * pkey;
+RSA * rsa;
+X509_NAME * name;
+uschar * where;
+
+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, 1024)))
+  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), 0);
+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);
+
+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;
+}
+
+
+
+
+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          *
 *************************************************/
@@ -923,56 +1073,82 @@ the certificate string.
 Arguments:
   sctx            the SSL_CTX* to update
   cbinfo          various parts of session state
+  errstr         error string pointer
 
 Returns:          OK/DEFER/FAIL
 */
 
 static int
-tls_expand_session_files(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo)
+tls_expand_session_files(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo,
+  uschar ** errstr)
 {
 uschar *expanded;
 
-if (cbinfo->certificate == NULL)
-  return OK;
+if (!cbinfo->certificate)
+  {
+  if (!cbinfo->is_server)              /* client */
+    return OK;
+                                       /* 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")
-   )
-  reexpand_tls_files_for_sni = TRUE;
+  if (Ustrstr(cbinfo->certificate, US"tls_sni") ||
+      Ustrstr(cbinfo->certificate, US"tls_in_sni") ||
+      Ustrstr(cbinfo->certificate, US"tls_out_sni")
+     )
+    reexpand_tls_files_for_sni = TRUE;
 
-if (!expand_check(cbinfo->certificate, US"tls_certificate", &expanded))
-  return DEFER;
+  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);
-  }
+  if (expanded)
+    if (cbinfo->is_server)
+      {
+      const uschar * file_list = expanded;
+      int sep = 0;
+      uschar * file;
 
-if (cbinfo->privatekey != NULL &&
-    !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded))
-  return DEFER;
+      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 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 (cbinfo->privatekey != NULL &&
+      !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
+    return DEFER;
 
-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);
+  /* 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 (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)
   {
-  if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded))
+  /*XXX stack*/
+  if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded, errstr))
     return DEFER;
 
   if (expanded && *expanded)
@@ -984,9 +1160,7 @@ if (cbinfo->is_server && cbinfo->u_ocsp.server.file)
       DEBUG(D_tls) debug_printf(" - value unchanged, using existing values\n");
       }
     else
-      {
       ocsp_load_response(sctx, cbinfo, expanded);
-      }
     }
   }
 #endif
@@ -1022,6 +1196,7 @@ 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;
+uschar * dummy_errstr;
 
 if (!servername)
   return SSL_TLSEXT_ERR_OK;
@@ -1058,8 +1233,8 @@ 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 (  !init_dh(server_sni, cbinfo->dhparam, NULL)
-   || !init_ecdh(server_sni, NULL)
+if (  !init_dh(server_sni, cbinfo->dhparam, NULL, &dummy_errstr)
+   || !init_ecdh(server_sni, NULL, &dummy_errstr)
    )
   return SSL_TLSEXT_ERR_NOACK;
 
@@ -1073,12 +1248,13 @@ if (cbinfo->u_ocsp.server.file)
   }
 #endif
 
-rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE, verify_callback_server);
-if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+if ((rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE,
+                     verify_callback_server, &dummy_errstr)) != OK)
+  return SSL_TLSEXT_ERR_NOACK;
 
 /* do this after setup_certs, because this can require the certs for verifying
 OCSP information. */
-if ((rc = tls_expand_session_files(server_sni, cbinfo)) != OK)
+if ((rc = tls_expand_session_files(server_sni, cbinfo, &dummy_errstr)) != OK)
   return SSL_TLSEXT_ERR_NOACK;
 
 DEBUG(D_tls) debug_printf("Switching SSL context.\n");
@@ -1109,9 +1285,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");
@@ -1121,7 +1303,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;
@@ -1195,21 +1377,23 @@ 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 */
 
     /* 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, NULL,
+    if ((i = OCSP_basic_verify(bs, cbinfo->verify_stack,
              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;
       }
 
@@ -1304,6 +1488,7 @@ Arguments:
   ocsp_file       file of stapling info (server); flag for require ocsp (client)
   addr            address if client; NULL if server (for some randomness)
   cbp             place to put allocated callback context
+  errstr         error string pointer
 
 Returns:          OK/DEFER/FAIL
 */
@@ -1312,20 +1497,22 @@ 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)
+  address_item *addr, tls_ext_ctx_cb ** cbp, uschar ** errstr)
 {
+SSL_CTX * ctx;
 long init_options;
 int rc;
-BOOL okay;
 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
-if ((cbinfo->is_server = host==NULL))
+cbinfo->verify_stack = NULL;
+if (!host)
   {
   cbinfo->u_ocsp.server.file = ocsp_file;
   cbinfo->u_ocsp.server.file_expanded = NULL;
@@ -1358,9 +1545,8 @@ 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 ? SSLv23_client_method() : SSLv23_server_method());
-
-if (!*ctxp) return tls_error(US"SSL_CTX_new", host, NULL);
+if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())))
+  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
 order to get the full complement of ciphers to work. It took me roughly a day
@@ -1376,22 +1562,22 @@ 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,
-      US"unable to seed random number generator");
+      US"unable to seed random number generator", errstr);
   }
 
 /* Set up the information callback, which outputs if debugging is at a suitable
 level. */
 
-DEBUG(D_tls) SSL_CTX_set_info_callback(*ctxp, (void (*)())info_callback);
+DEBUG(D_tls) SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
 
 /* Automatically re-try reads/writes after renegotiation. */
-(void) SSL_CTX_set_mode(*ctxp, SSL_MODE_AUTO_RETRY);
+(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
 
 /* Apply administrator-supplied work-arounds.
 Historically we applied just one requested option,
@@ -1402,35 +1588,47 @@ 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.  */
 
-okay = tls_openssl_options_parse(openssl_options, &init_options);
-if (!okay)
-  return tls_error(US"openssl_options parsing failed", host, NULL);
+if (!tls_openssl_options_parse(openssl_options, &init_options))
+  return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
 
 if (init_options)
   {
   DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
-  if (!(SSL_CTX_set_options(*ctxp, init_options)))
+  if (!(SSL_CTX_set_options(ctx, init_options)))
     return tls_error(string_sprintf(
-          "SSL_CTX_set_option(%#lx)", init_options), host, NULL);
+          "SSL_CTX_set_option(%#lx)", init_options), host, NULL, errstr);
   }
 else
   DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
 
+/* Disable session cache unconditionally */
+
+(void) SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+
 /* Initialize with DH parameters if supplied */
 /* Initialize ECDH temp key parameter selection */
 
-if (  !init_dh(*ctxp, dhparam, host)
-   || !init_ecdh(*ctxp, host)
+if (  !init_dh(ctx, dhparam, host, errstr)
+   || !init_ecdh(ctx, host, errstr)
    )
   return DEFER;
 
 /* Set up certificate and key (and perhaps OCSP info) */
 
-rc = tls_expand_session_files(*ctxp, cbinfo);
-if (rc != OK) return rc;
+if ((rc = tls_expand_session_files(ctx, cbinfo, errstr)) != OK)
+  return rc;
+
+/* If we need to handle SNI or OCSP, do so */
 
-/* If we need to handle SNI, do so */
 #ifdef EXIM_HAVE_OPENSSL_TLSEXT
+# ifndef DISABLE_OCSP
+  if (!(cbinfo->verify_stack = sk_X509_new_null()))
+    {
+    DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n");
+    return FAIL;
+    }
+# endif
+
 if (host == NULL)              /* server */
   {
 # ifndef DISABLE_OCSP
@@ -1440,14 +1638,14 @@ if (host == NULL)               /* server */
   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);
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
+    SSL_CTX_set_tlsext_status_arg(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);
+  SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
+  SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
   }
 # ifndef DISABLE_OCSP
 else                   /* client */
@@ -1458,8 +1656,8 @@ else                      /* client */
       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);
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
+    SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
     }
 # endif
 #endif
@@ -1468,15 +1666,16 @@ cbinfo->verify_cert_hostnames = NULL;
 
 #ifdef EXIM_HAVE_EPHEM_RSA_KEX
 /* Set up the RSA callback */
-SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
+SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
 #endif
 
 /* Finally, set the timeout, and we are done */
 
-SSL_CTX_set_timeout(*ctxp, ssl_session_timeout);
+SSL_CTX_set_timeout(ctx, ssl_session_timeout);
 DEBUG(D_tls) debug_printf("Initialized TLS\n");
 
 *cbp = cbinfo;
+*ctxp = ctx;
 
 return OK;
 }
@@ -1547,7 +1746,28 @@ else
 *        Set up for verifying certificates       *
 *************************************************/
 
-/* Called by both client and server startup
+/* Load certs from file, return TRUE on success */
+
+static BOOL
+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;
+}
+
+
+
+/* Called by both client and server startup; on the server possibly
+repeated after a Server Name Indication.
 
 Arguments:
   sctx          SSL_CTX* to initialise
@@ -1557,18 +1777,20 @@ Arguments:
   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
+  errstr       error string pointer
 
 Returns:        OK/DEFER/FAIL
 */
 
 static int
 setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
-    int (*cert_vfy_cb)(int, X509_STORE_CTX *) )
+    int (*cert_vfy_cb)(int, X509_STORE_CTX *), uschar ** errstr)
 {
 uschar *expcerts, *expcrl;
 
-if (!expand_check(certs, US"tls_verify_certificates", &expcerts))
+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)
   {
@@ -1576,7 +1798,7 @@ if (expcerts && *expcerts)
   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);
+    return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL, errstr);
 
   if (Ustrcmp(expcerts, "system") != 0)
     {
@@ -1594,23 +1816,40 @@ if (expcerts && *expcerts)
       if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
        { file = NULL; dir = expcerts; }
       else
-       { file = expcerts; dir = NULL; }
+       {
+       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. */
+
+       if (  !host
+          && statbuf.st_size > 0
+          && server_static_cbinfo->u_ocsp.server.file
+          && !chain_from_pem_file(file, server_static_cbinfo->verify_stack)
+          )
+         {
+         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 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. */
+      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);
+       return tls_error(US"SSL_CTX_load_verify_locations", host, NULL, errstr);
 
       /* 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 reqest for client certs.
+      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
@@ -1620,9 +1859,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);
        }
       }
     }
@@ -1641,7 +1880,7 @@ if (expcerts && *expcerts)
   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 (!expand_check(crl, US"tls_crl", &expcrl, errstr)) return DEFER;
   if (expcrl && *expcrl)
     {
     struct stat statbufcrl;
@@ -1669,7 +1908,7 @@ if (expcerts && *expcerts)
         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);
+        return tls_error(US"X509_STORE_load_locations", host, NULL, errstr);
 
       /* setting the flags to check against the complete crl chain */
 
@@ -1702,19 +1941,20 @@ a TLS session.
 
 Arguments:
   require_ciphers   allowed ciphers
+  errstr           pointer to error message
 
 Returns:            OK on success
                     DEFER for errors before the start of the negotiation
-                    FAIL for errors during the negotation; the server can't
+                    FAIL for errors during the negotiation; the server can't
                       continue running.
 */
 
 int
-tls_server_start(const uschar *require_ciphers)
+tls_server_start(const uschar * require_ciphers, uschar ** errstr)
 {
 int rc;
-uschar *expciphers;
-tls_ext_ctx_cb *cbinfo;
+uschar * expciphers;
+tls_ext_ctx_cb * cbinfo;
 static uschar peerdn[256];
 static uschar cipherbuf[256];
 
@@ -1722,8 +1962,8 @@ static uschar cipherbuf[256];
 
 if (tls_in.active >= 0)
   {
-  tls_error(US"STARTTLS received after TLS started", NULL, US"");
-  smtp_printf("554 Already in TLS\r\n");
+  tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr);
+  smtp_printf("554 Already in TLS\r\n", FALSE);
   return FAIL;
   }
 
@@ -1732,13 +1972,13 @@ 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);
+    NULL, &server_static_cbinfo, errstr);
 if (rc != OK) return rc;
 cbinfo = server_static_cbinfo;
 
-if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
+if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers, errstr))
   return FAIL;
 
 /* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
@@ -1746,13 +1986,13 @@ 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.
 */
 
-if (expciphers != NULL)
+if (expciphers)
   {
-  uschar *s = expciphers;
+  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);
+    return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
   cbinfo->server_cipher_list = expciphers;
   }
 
@@ -1760,7 +2000,7 @@ if (expciphers != NULL)
 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;
@@ -1768,21 +2008,22 @@ 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);
+                       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);
+                       TRUE, verify_callback_server, errstr);
   if (rc != OK) return rc;
   server_verify_optional = TRUE;
   }
 
 /* Prepare for new connection */
 
-if ((server_ssl = SSL_new(server_ctx)) == NULL) return tls_error(US"SSL_new", NULL, NULL);
+if (!(server_ssl = SSL_new(server_ctx)))
+  return tls_error(US"SSL_new", NULL, NULL, errstr);
 
 /* Warning: we used to SSL_clear(ssl) here, it was removed.
  *
@@ -1806,7 +2047,7 @@ 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)
   {
-  smtp_printf("220 TLS go ahead\r\n");
+  smtp_printf("220 TLS go ahead\r\n", FALSE);
   fflush(smtp_out);
   }
 
@@ -1826,10 +2067,7 @@ alarm(0);
 
 if (rc <= 0)
   {
-  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?)");
+  (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
   return FAIL;
   }
 
@@ -1861,11 +2099,13 @@ 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;
+receive_get_cache = tls_get_cache;
 receive_ungetc = tls_ungetc;
 receive_feof = tls_feof;
 receive_ferror = tls_ferror;
@@ -1880,8 +2120,8 @@ return OK;
 
 static int
 tls_client_basic_ctx_init(SSL_CTX * ctx,
-    host_item * host, smtp_transport_options_block * ob, tls_ext_ctx_cb * cbinfo
-                         )
+    host_item * host, smtp_transport_options_block * ob, tls_ext_ctx_cb * cbinfo,
+    uschar ** errstr)
 {
 int rc;
 /* stick to the old behaviour for compatibility if tls_verify_certificates is
@@ -1900,7 +2140,8 @@ else
   return OK;
 
 if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
-      ob->tls_crl, host, client_verify_optional, verify_callback_client)) != OK)
+      ob->tls_crl, host, client_verify_optional, verify_callback_client,
+      errstr)) != OK)
   return rc;
 
 if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK)
@@ -1918,9 +2159,9 @@ return OK;
 }
 
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 static int
-dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa)
+dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa, uschar ** errstr)
 {
 dns_record * rr;
 dns_scan dnss;
@@ -1928,14 +2169,14 @@ const char * hostnames[2] = { CS host->name, NULL };
 int found = 0;
 
 if (DANESSL_init(ssl, NULL, hostnames) != 1)
-  return tls_error(US"hostnames load", host, NULL);
+  return tls_error(US"hostnames load", host, NULL, errstr);
 
 for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
      rr;
      rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
     ) if (rr->type == T_TLSA)
   {
-  uschar * p = rr->data;
+  const uschar * p = rr->data;
   uint8_t usage, selector, mtype;
   const char * mdname;
 
@@ -1959,8 +2200,8 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
   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 */
-      return tls_error(US"tlsa load", host, NULL);
     case 1:    break;
     }
 
@@ -1973,7 +2214,7 @@ if (found)
 log_write(0, LOG_MAIN, "DANE error: No usable TLSA records");
 return DEFER;
 }
-#endif /*EXPERIMENTAL_DANE*/
+#endif /*SUPPORT_DANE*/
 
 
 
@@ -1989,6 +2230,7 @@ Argument:
   addr             the first address
   tb               transport (always smtp)
   tlsa_dnsa        tlsa lookup, if DANE, else null
+  errstr          error string pointer
 
 Returns:           OK on success
                    FAIL otherwise - note that tls_error() will not give DEFER
@@ -1997,11 +2239,11 @@ Returns:           OK on success
 
 int
 tls_client_start(int fd, host_item *host, address_item *addr,
-  transport_instance *tb
-#ifdef EXPERIMENTAL_DANE
-  , dns_answer * tlsa_dnsa
+  transport_instance * tb,
+#ifdef SUPPORT_DANE
+  dns_answer * tlsa_dnsa,
 #endif
-  )
+  uschar ** errstr)
 {
 smtp_transport_options_block * ob =
   (smtp_transport_options_block *)tb->options_block;
@@ -2015,13 +2257,13 @@ BOOL request_ocsp = FALSE;
 BOOL require_ocsp = FALSE;
 #endif
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 tls_out.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'
@@ -2039,7 +2281,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 =
@@ -2052,30 +2294,30 @@ rc = tls_init(&client_ctx, host, NULL,
 #ifndef DISABLE_OCSP
     (void *)(long)request_ocsp,
 #endif
-    addr, &client_static_cbinfo);
+    addr, &client_static_cbinfo, errstr);
 if (rc != OK) return rc;
 
 tls_out.certificate_verified = FALSE;
 client_verify_callback_called = FALSE;
 
 if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
-    &expciphers))
+    &expciphers, errstr))
   return FAIL;
 
 /* 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 (expciphers != NULL)
+if (expciphers)
   {
   uschar *s = expciphers;
-  while (*s != 0) { if (*s == '_') *s = '-'; s++; }
+  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);
+    return tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr);
   }
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
   {
   SSL_CTX_set_verify(client_ctx,
@@ -2083,29 +2325,29 @@ if (tlsa_dnsa)
     verify_callback_client_dane);
 
   if (!DANESSL_library_init())
-    return tls_error(US"library init", host, NULL);
+    return tls_error(US"library init", host, NULL, errstr);
   if (DANESSL_CTX_init(client_ctx) <= 0)
-    return tls_error(US"context init", host, NULL);
+    return tls_error(US"context init", host, NULL, errstr);
   }
 else
 
 #endif
 
-  if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob, client_static_cbinfo))
-      != OK)
+  if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob,
+      client_static_cbinfo, errstr)) != OK)
     return rc;
 
 if ((client_ssl = SSL_new(client_ctx)) == NULL)
-  return tls_error(US"SSL_new", host, 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 (ob->tls_sni)
   {
-  if (!expand_check(ob->tls_sni, US"tls_sni", &tls_out.sni))
+  if (!expand_check(ob->tls_sni, US"tls_sni", &tls_out.sni, errstr))
     return FAIL;
-  if (tls_out.sni == NULL)
+  if (!tls_out.sni)
     {
     DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n");
     }
@@ -2123,16 +2365,16 @@ if (ob->tls_sni)
     }
   }
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
-  if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa)) != OK)
+  if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa, errstr)) != OK)
     return rc;
 #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;
@@ -2169,13 +2411,14 @@ alarm(ob->command_timeout);
 rc = SSL_connect(client_ssl);
 alarm(0);
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
   DANESSL_cleanup(client_ssl);
 #endif
 
 if (rc <= 0)
-  return tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL);
+  return tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL,
+    errstr);
 
 DEBUG(D_tls) debug_printf("SSL_connect succeeded\n");
 
@@ -2198,6 +2441,81 @@ return OK;
 
 
 
+static BOOL
+tls_refill(unsigned lim)
+{
+int error;
+int inbytes;
+
+DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
+  ssl_xfer_buffer, ssl_xfer_buffer_size);
+
+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);
+
+/* 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)
+  {
+  DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
+
+  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;
+
+  if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
+       SSL_shutdown(server_ssl);
+
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  SSL_free(server_ssl);
+  SSL_CTX_free(server_ctx);
+  server_static_cbinfo->verify_stack = NULL;
+  server_ctx = NULL;
+  server_ssl = NULL;
+  tls_in.active = -1;
+  tls_in.bits = 0;
+  tls_in.cipher = NULL;
+  tls_in.peerdn = NULL;
+  tls_in.sni = NULL;
+
+  return FALSE;
+  }
+
+/* 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 = TRUE;
+  return FALSE;
+  }
+
+else if (error != SSL_ERROR_NONE)
+  {
+  DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
+  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;
+}
+
+
 /*************************************************
 *            TLS version of getc                 *
 *************************************************/
@@ -2205,84 +2523,65 @@ 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()
+{
 #ifndef DISABLE_DKIM
-  dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
+int n = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm;
+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(server_ssl) > 0;
 }
 
 
-
 /*************************************************
 *          Read bytes from TLS channel           *
 *************************************************/
@@ -2317,9 +2616,7 @@ if (error == SSL_ERROR_ZERO_RETURN)
   return -1;
   }
 else if (error != SSL_ERROR_NONE)
-  {
   return -1;
-  }
 
 return inbytes;
 }
@@ -2337,6 +2634,7 @@ Arguments:
   is_server channel specifier
   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
@@ -2345,15 +2643,31 @@ Used by both server-side and client-side TLS.
 */
 
 int
-tls_write(BOOL is_server, const uschar *buff, size_t len)
+tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more)
 {
-int outbytes;
-int error;
-int left = len;
+int outbytes, error, left;
 SSL *ssl = is_server ? server_ssl : client_ssl;
+static gstring * corked = NULL;
+
+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))
+  {
+  corked = string_catn(corked, buff, len);
+  if (more)
+    return len;
+  buff = CUS corked->s;
+  len = corked->ptr;
+  corked = NULL;
+  }
 
-DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left);
-while (left > 0)
+for (left = len; left > 0;)
   {
   DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left);
   outbytes = SSL_write(ssl, CS buff, left);
@@ -2399,15 +2713,19 @@ 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:
+  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(BOOL is_server, int shutdown)
 {
+SSL_CTX **ctxp = is_server ? &server_ctx : &client_ctx;
 SSL **sslp = is_server ? &server_ssl : &client_ssl;
 int *fdp = is_server ? &tls_in.active : &tls_out.active;
 
@@ -2415,13 +2733,35 @@ 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);
+    }
+  }
+
+if (is_server)
+  {
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  server_static_cbinfo->verify_stack = NULL;
   }
 
+SSL_CTX_free(*ctxp);
 SSL_free(*sslp);
+*ctxp = NULL;
 *sslp = NULL;
-
 *fdp = -1;
 }
 
@@ -2458,7 +2798,8 @@ EVP_add_digest(EVP_sha256());
 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))
@@ -2483,7 +2824,8 @@ DEBUG(D_tls)
 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);
+  err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed: %s",
+                     expciphers, ssl_errstring);
   }
 
 SSL_CTX_free(ctx);
@@ -2576,7 +2918,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
@@ -2788,7 +3130,7 @@ uschar *s, *end;
 uschar keep_c;
 BOOL adding, item_parsed;
 
-result = 0L;
+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. */
 #ifdef SSL_OP_NO_SSLv2
@@ -2798,7 +3140,7 @@ result |= SSL_OP_NO_SSLv2;
 result |= SSL_OP_SINGLE_DH_USE;
 #endif
 
-if (option_spec == NULL)
+if (!option_spec)
   {
   *results = result;
   return TRUE;