GnuTLS control constants exposed to Makefile.
[exim.git] / src / src / tls-openssl.c
index 2104711bb96230013a2c27948abd6ded697c6533..1938d2fb7a72ad1bc4f8f299621f5b04e9952294 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2012 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* This module provides the TLS (aka SSL) support for Exim using the OpenSSL
@@ -20,6 +20,14 @@ functions from the OpenSSL library. */
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
+#ifdef EXPERIMENTAL_OCSP
+#include <openssl/ocsp.h>
+#endif
+
+#ifdef EXPERIMENTAL_OCSP
+#define EXIM_OCSP_SKEW_SECONDS (300L)
+#define EXIM_OCSP_MAX_AGE (-1L)
+#endif
 
 /* Structure for collecting random data for seeding. */
 
@@ -34,6 +42,7 @@ static BOOL verify_callback_called = FALSE;
 static const uschar *sid_ctx = US"exim";
 
 static SSL_CTX *ctx = NULL;
+static SSL_CTX *ctx_sni = NULL;
 static SSL *ssl = NULL;
 
 static char ssl_errstring[256];
@@ -41,8 +50,37 @@ static char ssl_errstring[256];
 static int  ssl_session_timeout = 200;
 static BOOL verify_optional = FALSE;
 
+static BOOL    reexpand_tls_files_for_sni = FALSE;
 
 
+typedef struct tls_ext_ctx_cb {
+  uschar *certificate;
+  uschar *privatekey;
+#ifdef EXPERIMENTAL_OCSP
+  uschar *ocsp_file;
+  uschar *ocsp_file_expanded;
+  OCSP_RESPONSE *ocsp_response;
+#endif
+  uschar *dhparam;
+  /* these are cached from first expand */
+  uschar *server_cipher_list;
+  /* only passed down to tls_error: */
+  host_item *host;
+} tls_ext_ctx_cb;
+
+/* should figure out a cleanup of API to handle state preserved per
+implementation, for various reasons, which can be void * in the APIs.
+For now, we hack around it. */
+tls_ext_ctx_cb *static_cbinfo = NULL;
+
+static int
+setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional);
+
+/* Callbacks */
+static int tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg);
+#ifdef EXPERIMENTAL_OCSP
+static int tls_stapling_cb(SSL *s, void *arg);
+#endif
 
 
 /*************************************************
@@ -201,8 +239,8 @@ return 1;   /* accept */
 *************************************************/
 
 /* The SSL library functions call this from time to time to indicate what they
-are doing. We copy the string to the debugging output when the level is high
-enough.
+are doing. We copy the string to the debugging output when TLS debugging has
+been requested.
 
 Arguments:
   s         the SSL connection
@@ -279,6 +317,338 @@ return yield;
 
 
 
+#ifdef EXPERIMENTAL_OCSP
+/*************************************************
+*       Load OCSP information into state         *
+*************************************************/
+
+/* Called to load the OCSP response from the given file into memory, once
+caller has determined this is needed.  Checks validity.  Debugs a message
+if invalid.
+
+ASSUMES: single response, for single cert.
+
+Arguments:
+  sctx            the SSL_CTX* to update
+  cbinfo          various parts of session state
+  expanded        the filename putatively holding an OCSP response
+
+*/
+
+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;
+unsigned long verify_flags;
+int status, reason, i;
+
+cbinfo->ocsp_file_expanded = string_copy(expanded);
+if (cbinfo->ocsp_response)
+  {
+  OCSP_RESPONSE_free(cbinfo->ocsp_response);
+  cbinfo->ocsp_response = NULL;
+  }
+
+bio = BIO_new_file(CS cbinfo->ocsp_file_expanded, "rb");
+if (!bio)
+  {
+  DEBUG(D_tls) debug_printf("Failed to open OCSP response file \"%s\"\n",
+      cbinfo->ocsp_file_expanded);
+  return;
+  }
+
+resp = d2i_OCSP_RESPONSE_bio(bio, NULL);
+BIO_free(bio);
+if (!resp)
+  {
+  DEBUG(D_tls) debug_printf("Error reading OCSP response.\n");
+  return;
+  }
+
+status = OCSP_response_status(resp);
+if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+  {
+  DEBUG(D_tls) debug_printf("OCSP response not valid: %s (%d)\n",
+      OCSP_response_status_str(status), status);
+  return;
+  }
+
+basic_response = OCSP_response_get1_basic(resp);
+if (!basic_response)
+  {
+  DEBUG(D_tls)
+    debug_printf("OCSP response parse error: unable to extract basic response.\n");
+  return;
+  }
+
+store = SSL_CTX_get_cert_store(sctx);
+verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */
+
+/* May need to expose ability to adjust those flags?
+OCSP_NOSIGS OCSP_NOVERIFY OCSP_NOCHAIN OCSP_NOCHECKS OCSP_NOEXPLICIT
+OCSP_TRUSTOTHER OCSP_NOINTERN */
+
+i = OCSP_basic_verify(basic_response, NULL, store, verify_flags);
+if (i <= 0)
+  {
+  DEBUG(D_tls) {
+    ERR_error_string(ERR_get_error(), ssl_errstring);
+    debug_printf("OCSP response verify failure: %s\n", US ssl_errstring);
+  }
+  return;
+  }
+
+/* Here's the simplifying assumption: there's only one response, for the
+one certificate we use, and nothing for anything else in a chain.  If this
+proves false, we need to extract a cert id from our issued cert
+(tls_certificate) and use that for OCSP_resp_find_status() (which finds the
+right cert in the stack and then calls OCSP_single_get0_status()).
+
+I'm hoping to avoid reworking a bunch more of how we handle state here. */
+single_response = OCSP_resp_get0(basic_response, 0);
+if (!single_response)
+  {
+  DEBUG(D_tls)
+    debug_printf("Unable to get first response from OCSP basic response.\n");
+  return;
+  }
+
+status = OCSP_single_get0_status(single_response, &reason, &rev, &thisupd, &nextupd);
+/* how does this status differ from the one above? */
+if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+  {
+  DEBUG(D_tls) debug_printf("OCSP response not valid (take 2): %s (%d)\n",
+      OCSP_response_status_str(status), status);
+  return;
+  }
+
+if (!OCSP_check_validity(thisupd, nextupd, EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
+  {
+  DEBUG(D_tls) debug_printf("OCSP status invalid times.\n");
+  return;
+  }
+
+cbinfo->ocsp_response = resp;
+}
+#endif
+
+
+
+
+/*************************************************
+*        Expand key and cert file specs          *
+*************************************************/
+
+/* Called once during tls_init and possibly againt during TLS setup, for a
+new context, if Server Name Indication was used and tls_sni was seen in
+the certificate string.
+
+Arguments:
+  sctx            the SSL_CTX* to update
+  cbinfo          various parts of session state
+
+Returns:          OK/DEFER/FAIL
+*/
+
+static int
+tls_expand_session_files(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo)
+{
+uschar *expanded;
+
+if (cbinfo->certificate == NULL)
+  return OK;
+
+if (Ustrstr(cbinfo->certificate, US"tls_sni"))
+  reexpand_tls_files_for_sni = TRUE;
+
+if (!expand_check(cbinfo->certificate, US"tls_certificate", &expanded))
+  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 (cbinfo->privatekey != NULL &&
+    !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded))
+  return DEFER;
+
+/* If expansion was forced to fail, key_expanded will be NULL. If the result
+of the expansion is an empty string, ignore it also, and assume the private
+key is in the same file as the certificate. */
+
+if (expanded != NULL && *expanded != 0)
+  {
+  DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", expanded);
+  if (!SSL_CTX_use_PrivateKey_file(sctx, CS expanded, SSL_FILETYPE_PEM))
+    return tls_error(string_sprintf(
+      "SSL_CTX_use_PrivateKey_file file=%s", expanded), cbinfo->host, NULL);
+  }
+
+#ifdef EXPERIMENTAL_OCSP
+if (cbinfo->ocsp_file != NULL)
+  {
+  if (!expand_check(cbinfo->ocsp_file, US"tls_ocsp_file", &expanded))
+    return DEFER;
+
+  if (expanded != NULL && *expanded != 0)
+    {
+    DEBUG(D_tls) debug_printf("tls_ocsp_file %s\n", expanded);
+    if (cbinfo->ocsp_file_expanded &&
+        (Ustrcmp(expanded, cbinfo->ocsp_file_expanded) == 0))
+      {
+      DEBUG(D_tls)
+        debug_printf("tls_ocsp_file value unchanged, using existing values.\n");
+      } else {
+        ocsp_load_response(sctx, cbinfo, expanded);
+      }
+    }
+  }
+#endif
+
+return OK;
+}
+
+
+
+
+/*************************************************
+*            Callback to handle SNI              *
+*************************************************/
+
+/* Called when acting as server during the TLS session setup if a Server Name
+Indication extension was sent by the client.
+
+API documentation is OpenSSL s_server.c implementation.
+
+Arguments:
+  s               SSL* of the current session
+  ad              unknown (part of OpenSSL API) (unused)
+  arg             Callback of "our" registered data
+
+Returns:          SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK}
+*/
+
+static int
+tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
+{
+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;
+
+if (!servername)
+  return SSL_TLSEXT_ERR_OK;
+
+DEBUG(D_tls) debug_printf("Received TLS SNI \"%s\"%s\n", servername,
+    reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)");
+
+/* Make the extension value available for expansion */
+store_pool = POOL_PERM;
+tls_sni = string_copy(US servername);
+store_pool = old_pool;
+
+if (!reexpand_tls_files_for_sni)
+  return SSL_TLSEXT_ERR_OK;
+
+/* Can't find an SSL_CTX_clone() or equivalent, so we do it manually;
+not confident that memcpy wouldn't break some internal reference counting.
+Especially since there's a references struct member, which would be off. */
+
+ctx_sni = SSL_CTX_new(SSLv23_server_method());
+if (!ctx_sni)
+  {
+  ERR_error_string(ERR_get_error(), ssl_errstring);
+  DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring);
+  return SSL_TLSEXT_ERR_NOACK;
+  }
+
+/* Not sure how many of these are actually needed, since SSL object
+already exists.  Might even need this selfsame callback, for reneg? */
+
+SSL_CTX_set_info_callback(ctx_sni, SSL_CTX_get_info_callback(ctx));
+SSL_CTX_set_mode(ctx_sni, SSL_CTX_get_mode(ctx));
+SSL_CTX_set_options(ctx_sni, SSL_CTX_get_options(ctx));
+SSL_CTX_set_timeout(ctx_sni, SSL_CTX_get_timeout(ctx));
+SSL_CTX_set_tlsext_servername_callback(ctx_sni, tls_servername_cb);
+SSL_CTX_set_tlsext_servername_arg(ctx_sni, cbinfo);
+if (cbinfo->server_cipher_list)
+  SSL_CTX_set_cipher_list(ctx_sni, CS cbinfo->server_cipher_list);
+#ifdef EXPERIMENTAL_OCSP
+if (cbinfo->ocsp_file)
+  {
+  SSL_CTX_set_tlsext_status_cb(ctx_sni, tls_stapling_cb);
+  SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
+  }
+#endif
+
+rc = setup_certs(ctx_sni, tls_verify_certificates, tls_crl, NULL, FALSE);
+if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+
+/* do this after setup_certs, because this can require the certs for verifying
+OCSP information. */
+rc = tls_expand_session_files(ctx_sni, cbinfo);
+if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+
+DEBUG(D_tls) debug_printf("Switching SSL context.\n");
+SSL_set_SSL_CTX(s, ctx_sni);
+
+return SSL_TLSEXT_ERR_OK;
+}
+
+
+
+
+#ifdef EXPERIMENTAL_OCSP
+/*************************************************
+*        Callback to handle OCSP Stapling        *
+*************************************************/
+
+/* Called when acting as server during the TLS session setup if the client
+requests OCSP information with a Certificate Status Request.
+
+Documentation via openssl s_server.c and the Apache patch from the OpenSSL
+project.
+
+*/
+
+static int
+tls_stapling_cb(SSL *s, void *arg)
+{
+const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
+uschar *response_der;
+int response_der_len;
+
+DEBUG(D_tls) debug_printf("Received TLS status request (OCSP stapling); %s response.\n",
+    cbinfo->ocsp_response ? "have" : "lack");
+if (!cbinfo->ocsp_response)
+  return SSL_TLSEXT_ERR_NOACK;
+
+response_der = NULL;
+response_der_len = i2d_OCSP_RESPONSE(cbinfo->ocsp_response, &response_der);
+if (response_der_len <= 0)
+  return SSL_TLSEXT_ERR_NOACK;
+
+SSL_set_tlsext_status_ocsp_resp(ssl, response_der, response_der_len);
+return SSL_TLSEXT_ERR_OK;
+}
+
+#endif /* EXPERIMENTAL_OCSP */
+
+
+
+
 /*************************************************
 *            Initialize for TLS                  *
 *************************************************/
@@ -298,10 +668,25 @@ Returns:          OK/DEFER/FAIL
 
 static int
 tls_init(host_item *host, uschar *dhparam, uschar *certificate,
-  uschar *privatekey, address_item *addr)
+  uschar *privatekey,
+#ifdef EXPERIMENTAL_OCSP
+  uschar *ocsp_file,
+#endif
+  address_item *addr)
 {
 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;
+#ifdef EXPERIMENTAL_OCSP
+cbinfo->ocsp_file = ocsp_file;
+#endif
+cbinfo->dhparam = dhparam;
+cbinfo->host = host;
 
 SSL_load_error_strings();          /* basic set up */
 OpenSSL_add_ssl_algorithms();
@@ -347,6 +732,9 @@ level. */
 
 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
 
+/* Automatically re-try reads/writes after renegotiation. */
+(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+
 /* Apply administrator-supplied work-arounds.
 Historically we applied just one requested option,
 SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS, but when bug 994 requested a second, we
@@ -374,38 +762,32 @@ else
 
 if (!init_dh(dhparam, host)) return DEFER;
 
-/* Set up certificate and key */
-
-if (certificate != NULL)
-  {
-  uschar *expanded;
-  if (!expand_check(certificate, US"tls_certificate", &expanded))
-    return DEFER;
-
-  if (expanded != NULL)
-    {
-    DEBUG(D_tls) debug_printf("tls_certificate file %s\n", expanded);
-    if (!SSL_CTX_use_certificate_chain_file(ctx, CS expanded))
-      return tls_error(string_sprintf(
-        "SSL_CTX_use_certificate_chain_file file=%s", expanded), host, NULL);
-    }
-
-  if (privatekey != NULL &&
-      !expand_check(privatekey, US"tls_privatekey", &expanded))
-    return DEFER;
+/* Set up certificate and key (and perhaps OCSP info) */
 
-  /* 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. */
+rc = tls_expand_session_files(ctx, cbinfo);
+if (rc != OK) return rc;
 
-  if (expanded != NULL && *expanded != 0)
+/* If we need to handle SNI, do so */
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+if (host == NULL)
+  {
+#ifdef EXPERIMENTAL_OCSP
+  /* We check ocsp_file, not ocsp_response, because we care about if
+  the option exists, not what the current expansion might be, as SNI might
+  change the certificate and OCSP file in use between now and the time the
+  callback is invoked. */
+  if (cbinfo->ocsp_file)
     {
-    DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", expanded);
-    if (!SSL_CTX_use_PrivateKey_file(ctx, CS expanded, SSL_FILETYPE_PEM))
-      return tls_error(string_sprintf(
-        "SSL_CTX_use_PrivateKey_file file=%s", expanded), host, NULL);
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_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(ctx, tls_servername_cb);
+  SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
   }
+#endif
 
 /* Set up the RSA callback */
 
@@ -415,6 +797,9 @@ SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
 
 SSL_CTX_set_timeout(ctx, ssl_session_timeout);
 DEBUG(D_tls) debug_printf("Initialized TLS\n");
+
+static_cbinfo = cbinfo;
+
 return OK;
 }
 
@@ -456,6 +841,18 @@ switch (ssl->session->ssl_version)
   ver = US"TLSv1";
   break;
 
+#ifdef TLS1_1_VERSION
+  case TLS1_1_VERSION:
+  ver = US"TLSv1.1";
+  break;
+#endif
+
+#ifdef TLS1_2_VERSION
+  case TLS1_2_VERSION:
+  ver = US"TLSv1.2";
+  break;
+#endif
+
   default:
   ver = US"UNKNOWN";
   }
@@ -481,6 +878,7 @@ DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf);
 /* Called by both client and server startup
 
 Arguments:
+  sctx          SSL_CTX* to initialise
   certs         certs file or NULL
   crl           CRL file or NULL
   host          NULL in a server; the remote host in a client
@@ -491,7 +889,7 @@ Returns:        OK/DEFER/FAIL
 */
 
 static int
-setup_certs(uschar *certs, uschar *crl, host_item *host, BOOL optional)
+setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional)
 {
 uschar *expcerts, *expcrl;
 
@@ -501,7 +899,7 @@ if (!expand_check(certs, US"tls_verify_certificates", &expcerts))
 if (expcerts != NULL)
   {
   struct stat statbuf;
-  if (!SSL_CTX_set_default_verify_paths(ctx))
+  if (!SSL_CTX_set_default_verify_paths(sctx))
     return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
 
   if (Ustat(expcerts, &statbuf) < 0)
@@ -524,12 +922,12 @@ if (expcerts != NULL)
     says no certificate was supplied.) But this is better. */
 
     if ((file == NULL || statbuf.st_size > 0) &&
-          !SSL_CTX_load_verify_locations(ctx, CS file, CS dir))
+          !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
       return tls_error(US"SSL_CTX_load_verify_locations", host, NULL);
 
     if (file != NULL)
       {
-      SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CS file));
+      SSL_CTX_set_client_CA_list(sctx, SSL_load_client_CA_file(CS file));
       }
     }
 
@@ -561,7 +959,7 @@ if (expcerts != NULL)
       {
       /* is it a file or directory? */
       uschar *file, *dir;
-      X509_STORE *cvstore = SSL_CTX_get_cert_store(ctx);
+      X509_STORE *cvstore = SSL_CTX_get_cert_store(sctx);
       if ((statbufcrl.st_mode & S_IFMT) == S_IFDIR)
         {
         file = NULL;
@@ -588,7 +986,7 @@ if (expcerts != NULL)
 
   /* If verification is optional, don't fail if no certificate */
 
-  SSL_CTX_set_verify(ctx,
+  SSL_CTX_set_verify(sctx,
     SSL_VERIFY_PEER | (optional? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
     verify_callback);
   }
@@ -608,11 +1006,6 @@ a TLS session.
 
 Arguments:
   require_ciphers   allowed ciphers
-  ------------------------------------------------------
-  require_mac      list of allowed MACs                 ) Not used
-  require_kx       list of allowed key_exchange methods )   for
-  require_proto    list of allowed protocols            ) OpenSSL
-  ------------------------------------------------------
 
 Returns:            OK on success
                     DEFER for errors before the start of the negotiation
@@ -621,11 +1014,11 @@ Returns:            OK on success
 */
 
 int
-tls_server_start(uschar *require_ciphers, uschar *require_mac,
-  uschar *require_kx, uschar *require_proto)
+tls_server_start(const uschar *require_ciphers)
 {
 int rc;
 uschar *expciphers;
+tls_ext_ctx_cb *cbinfo;
 
 /* Check for previous activation */
 
@@ -639,15 +1032,21 @@ if (tls_active >= 0)
 /* Initialize the SSL library. If it fails, it will already have logged
 the error. */
 
-rc = tls_init(NULL, tls_dhparam, tls_certificate, tls_privatekey, NULL);
+rc = tls_init(NULL, tls_dhparam, tls_certificate, tls_privatekey,
+#ifdef EXPERIMENTAL_OCSP
+    tls_ocsp_file,
+#endif
+    NULL);
 if (rc != OK) return rc;
+cbinfo = static_cbinfo;
 
 if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
   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. */
+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)
   {
@@ -656,6 +1055,7 @@ if (expciphers != NULL)
   DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
   if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
     return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL);
+  cbinfo->server_cipher_list = expciphers;
   }
 
 /* If this is a host for which certificate verification is mandatory or
@@ -666,13 +1066,13 @@ verify_callback_called = FALSE;
 
 if (verify_check_host(&tls_verify_hosts) == OK)
   {
-  rc = setup_certs(tls_verify_certificates, tls_crl, NULL, FALSE);
+  rc = setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, FALSE);
   if (rc != OK) return rc;
   verify_optional = FALSE;
   }
 else if (verify_check_host(&tls_try_verify_hosts) == OK)
   {
-  rc = setup_certs(tls_verify_certificates, tls_crl, NULL, TRUE);
+  rc = setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, TRUE);
   if (rc != OK) return rc;
   verify_optional = TRUE;
   }
@@ -680,7 +1080,19 @@ else if (verify_check_host(&tls_try_verify_hosts) == OK)
 /* Prepare for new connection */
 
 if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", NULL, NULL);
-SSL_clear(ssl);
+
+/* Warning: we used to SSL_clear(ssl) here, it was removed.
+ *
+ * With the SSL_clear(), we get strange interoperability bugs with
+ * OpenSSL 1.0.1b and TLS1.1/1.2.  It looks as though this may be a bug in
+ * OpenSSL itself, as a clear should not lead to inability to follow protocols.
+ *
+ * The SSL_clear() call is to let an existing SSL* be reused, typically after
+ * session shutdown.  In this case, we have a brand new object and there's no
+ * obvious reason to immediately clear it.  I'm guessing that this was
+ * originally added because of incomplete initialisation which the clear fixed,
+ * in some historic release.
+ */
 
 /* Set context and tell client to go ahead, except in the case of TLS startup
 on connection, where outputting anything now upsets the clients and tends to
@@ -764,14 +1176,10 @@ Argument:
   dhparam          DH parameter file
   certificate      certificate file
   privatekey       private key file
+  sni              TLS SNI to send to remote host
   verify_certs     file for certificate verify
   crl              file containing CRL
   require_ciphers  list of allowed ciphers
-  ------------------------------------------------------
-  require_mac      list of allowed MACs                 ) Not used
-  require_kx       list of allowed key_exchange methods )   for
-  require_proto    list of allowed protocols            ) OpenSSL
-  ------------------------------------------------------
   timeout          startup timeout
 
 Returns:           OK on success
@@ -781,16 +1189,20 @@ Returns:           OK on success
 
 int
 tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
-  uschar *certificate, uschar *privatekey, uschar *verify_certs, uschar *crl,
-  uschar *require_ciphers, uschar *require_mac, uschar *require_kx,
-  uschar *require_proto, int timeout)
+  uschar *certificate, uschar *privatekey, uschar *sni,
+  uschar *verify_certs, uschar *crl,
+  uschar *require_ciphers, int timeout)
 {
 static uschar txt[256];
 uschar *expciphers;
 X509* server_cert;
 int rc;
 
-rc = tls_init(host, dhparam, certificate, privatekey, addr);
+rc = tls_init(host, dhparam, certificate, privatekey,
+#ifdef EXPERIMENTAL_OCSP
+    NULL,
+#endif
+    addr);
 if (rc != OK) return rc;
 
 tls_certificate_verified = FALSE;
@@ -812,7 +1224,7 @@ if (expciphers != NULL)
     return tls_error(US"SSL_CTX_set_cipher_list", host, NULL);
   }
 
-rc = setup_certs(verify_certs, crl, host, FALSE);
+rc = setup_certs(ctx, verify_certs, crl, host, FALSE);
 if (rc != OK) return rc;
 
 if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", host, NULL);
@@ -820,6 +1232,19 @@ SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx));
 SSL_set_fd(ssl, fd);
 SSL_set_connect_state(ssl);
 
+if (sni)
+  {
+  if (!expand_check(sni, US"tls_sni", &tls_sni))
+    return FAIL;
+  if (!Ustrlen(tls_sni))
+    tls_sni = NULL;
+  else
+    {
+    DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_sni);
+    SSL_set_tlsext_host_name(ssl, tls_sni);
+    }
+  }
+
 /* There doesn't seem to be a built-in timeout on connection. */
 
 DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
@@ -873,8 +1298,8 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
   int error;
   int inbytes;
 
-  DEBUG(D_tls) debug_printf("Calling SSL_read(%lx, %lx, %u)\n", (long)ssl,
-    (long)ssl_xfer_buffer, ssl_xfer_buffer_size);
+  DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
+    ssl_xfer_buffer, ssl_xfer_buffer_size);
 
   if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
   inbytes = SSL_read(ssl, CS ssl_xfer_buffer, ssl_xfer_buffer_size);
@@ -898,8 +1323,10 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
     SSL_free(ssl);
     ssl = NULL;
     tls_active = -1;
+    tls_bits = 0;
     tls_cipher = NULL;
     tls_peerdn = NULL;
+    tls_sni = NULL;
 
     return smtp_getc();
     }
@@ -920,6 +1347,7 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
     ssl_xfer_error = 1;
     return EOF;
     }
+
 #ifndef DISABLE_DKIM
   dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
 #endif
@@ -953,8 +1381,8 @@ tls_read(uschar *buff, size_t len)
 int inbytes;
 int error;
 
-DEBUG(D_tls) debug_printf("Calling SSL_read(%lx, %lx, %u)\n", (long)ssl,
-  (long)buff, (unsigned int)len);
+DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
+  buff, (unsigned int)len);
 
 inbytes = SSL_read(ssl, CS buff, len);
 error = SSL_get_error(ssl, inbytes);
@@ -996,10 +1424,10 @@ int outbytes;
 int error;
 int left = len;
 
-DEBUG(D_tls) debug_printf("tls_do_write(%lx, %d)\n", (long)buff, left);
+DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left);
 while (left > 0)
   {
-  DEBUG(D_tls) debug_printf("SSL_write(SSL, %lx, %d)\n", (long)buff, left);
+  DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", 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);
@@ -1088,7 +1516,7 @@ fprintf(f, "Library version: OpenSSL: Compile: %s\n"
 
 
 /*************************************************
-*        Pseudo-random number generation         *
+*            Random number generation            *
 *************************************************/
 
 /* Pseudo-random number generation.  The result is not expected to be
@@ -1103,7 +1531,7 @@ Returns     a random number in range [0, max-1]
 */
 
 int
-pseudo_random_number(int max)
+vaguely_random_number(int max)
 {
 unsigned int r;
 int i, needed_len;
@@ -1139,7 +1567,14 @@ if (i < needed_len)
   needed_len = i;
 
 /* We do not care if crypto-strong */
-(void) RAND_pseudo_bytes(smallbuf, needed_len);
+i = RAND_pseudo_bytes(smallbuf, needed_len);
+if (i < 0)
+  {
+  DEBUG(D_all)
+    debug_printf("OpenSSL RAND_pseudo_bytes() not supported by RAND method, using fallback.\n");
+  return vaguely_random_number_fallback(max);
+  }
+
 r = 0;
 for (p = smallbuf; needed_len; --needed_len, ++p)
   {
@@ -1177,7 +1612,7 @@ all options unless explicitly for DTLS, let the administrator choose which
 to apply.
 
 This list is current as of:
-  ==>  1.0.0c  <==  */
+  ==>  1.0.1b  <==  */
 static struct exim_openssl_option exim_openssl_options[] = {
 /* KEEP SORTED ALPHABETICALLY! */
 #ifdef SSL_OP_ALL
@@ -1213,6 +1648,9 @@ static struct exim_openssl_option exim_openssl_options[] = {
 #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
   { US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
 #endif
+#ifdef SSL_OP_NO_COMPRESSION
+  { US"no_compression", SSL_OP_NO_COMPRESSION },
+#endif
 #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
   { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
 #endif
@@ -1228,6 +1666,17 @@ static struct exim_openssl_option exim_openssl_options[] = {
 #ifdef SSL_OP_NO_TLSv1
   { US"no_tlsv1", SSL_OP_NO_TLSv1 },
 #endif
+#ifdef SSL_OP_NO_TLSv1_1
+#if SSL_OP_NO_TLSv1_1 == 0x00000400L
+  /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */
+#warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring
+#else
+  { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 },
+#endif
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+  { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 },
+#endif
 #ifdef SSL_OP_SINGLE_DH_USE
   { US"single_dh_use", SSL_OP_SINGLE_DH_USE },
 #endif
@@ -1253,6 +1702,7 @@ static struct exim_openssl_option exim_openssl_options[] = {
 static int exim_openssl_options_size =
   sizeof(exim_openssl_options)/sizeof(struct exim_openssl_option);
 
+
 static BOOL
 tls_openssl_one_option_parse(uschar *name, long *value)
 {
@@ -1301,10 +1751,8 @@ uschar keep_c;
 BOOL adding, item_parsed;
 
 result = 0L;
-/* We grandfather in as default the one option which we used to set always. */
-#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
-result |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
-#endif
+/* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
+ * from default because it increases BEAST susceptibility. */
 
 if (option_spec == NULL)
   {