Merge branch 'experimental_ocsp'
authorPhil Pennock <pdp@exim.org>
Wed, 16 May 2012 16:35:40 +0000 (12:35 -0400)
committerPhil Pennock <pdp@exim.org>
Wed, 16 May 2012 16:35:40 +0000 (12:35 -0400)
1  2 
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/EDITME
src/src/config.h.defaults
src/src/globals.c
src/src/globals.h
src/src/readconf.c
src/src/tls-openssl.c

diff --combined doc/doc-txt/ChangeLog
index fdb0074ab66ea980843c978b54d909022ee04ad6,7c6ce246f2a62b31fcc57f289aa0d7b451d57f2c..991f59f081c58b47ca91eb2d07b97dc1b297dfed
@@@ -91,22 -91,8 +91,24 @@@ PP/20 Revert part of NM/04, it broke lo
  
  PP/21 Defaulting "accept_8bitmime" to true, not false.
  
 -PP/22 Added EXPERIMENTAL_OCSP for OpenSSL.
 +PP/22 Added -bw for inetd wait mode support.
 +
 +PP/23 Added PCRE_CONFIG=yes support to Makefile for using pcre-config to
 +      locate the relevant includes and libraries.  Made this the default.
 +
 +PP/24 Fixed headers_only on smtp transports (was not sending trailing dot).
 +      Bugzilla 1246, report and most of solution from Tomasz Kusy.
 +
 +JH/02 ${eval } now uses 64-bit and supports a "g" suffix (like to "k" and "m").
 +      This may cause build issues on older platforms.
 +
 +PP/25 Revamped GnuTLS support, passing tls_require_ciphers to
 +      gnutls_priority_init, ignoring Exim options gnutls_require_kx,
 +      gnutls_require_mac & gnutls_require_protocols (no longer supported).
 +      Added SNI support via GnuTLS too.
 +
++PP/26 Added EXPERIMENTAL_OCSP for OpenSSL.
  
  Exim version 4.77
  -----------------
diff --combined doc/doc-txt/NewStuff
index 57102958a2a1f1ad11db808f81234985150df58f,96839cde6fdf0c48fcd20753d7a35371aa6b70dc..d41d79c837fb523b7a4d22231597fc030965e094
@@@ -26,9 -26,6 +26,9 @@@ Version 4.7
      "LOOKUP_LIBS" directly.  Similarly for handling the TLS library support
      without adjusting "TLS_INCLUDE" and "TLS_LIBS".
  
 +    In addition, setting PCRE_CONFIG=yes will query the pcre-config tool to
 +    find the headers and libraries for PCRE.
 +
   4. New expansion variable $tls_bits.
  
   5. New lookup type, "dbmjz".  Key is an Exim list, the elements of which will
      A new log_selector, +tls_sni, has been added, to log received SNI values
      for Exim as a server.
  
 -    Currently OpenSSL only.
 -
   8. The existing "accept_8bitmime" option now defaults to true.  This means
      that Exim is deliberately not strictly RFC compliant.  We're following
      Dan Bernstein's advice in http://cr.yp.to/smtp/8bitmime.html by default.
      Those who disagree, or know that they are talking to mail servers that,
      even today, are not 8-bit clean, need to turn off this option.
  
 - 9. With OpenSSL, if built with EXPERIMENTAL_OCSP, a new option tls_ocsp_file
 + 9. Exim can now be started with -bw (with an optional timeout, given as
 +    -bw<timespec>).  With this, stdin at startup is a socket that is
 +    already listening for connections.  This has a more modern name of
 +    "socket activation", but forcing the activated socket to fd 0.  We're
 +    interested in adding more support for modern variants.
 +
 +10. ${eval } now uses 64-bit values on supporting platforms.  A new "G" suffux
 +    for numbers indicates multiplication by 1024^3.
 +
 +11. The GnuTLS support has been revamped; the three options gnutls_require_kx,
 +    gnutls_require_mac & gnutls_require_protocols are no longer supported.
 +    tls_require_ciphers is now parsed by gnutls_priority_init(3) as a priority
 +    string, documentation for which is at:
 +    http://www.gnu.org/software/gnutls/manual/html_node/Priority-Strings.html
 +
 +    SNI support has been added to Exim's GnuTLS integration too.
 +
++12. With OpenSSL, if built with EXPERIMENTAL_OCSP, a new option tls_ocsp_file
+     is now available.  If the contents of the file are valid, then Exim will
+     send that back in response to a TLS status request; this is OCSP Stapling.
+     Exim will not maintain the contents of the file in any way: administrators
+     are responsible for ensuring that it is up-to-date.
+     See "experimental-spec.txt" for more details.
  
  Version 4.77
  ------------
diff --combined src/src/EDITME
index d972e9c150b666eed33c4b000a5e8e59bb6a4093,f4e788ae54e89342e13cd40810f89a1696c0cd87..1f717a988235cc65619afe69ff9a1010ca8202d0
@@@ -342,13 -342,10 +342,13 @@@ LOOKUP_DNSDB=ye
  # In either case you must specify the library link info here.  If the
  # PCRE header files are not in the standard search path you must also
  # modify the INCLUDE path (above)
 -# The default setting of PCRE_LIBS should work on the vast majority of
 -# systems
 +#
 +# Use PCRE_CONFIG to query the pcre-config command (first found in $PATH)
 +# to find the include files and libraries, else use PCRE_LIBS and set INCLUDE
 +# too if needed.
  
 -PCRE_LIBS=-lpcre
 +# PCRE_CONFIG=yes
 +# PCRE_LIBS=-lpcre
  
  
  #------------------------------------------------------------------------------
@@@ -442,6 -439,11 +442,11 @@@ EXIM_MONITOR=eximon.bi
  # CFLAGS  += -I/opt/brightmail/bsdk-6.0/include
  # LDFLAGS += -lxml2_single -lbmiclient_single -L/opt/brightmail/bsdk-6.0/lib
  
+ # Uncomment the following line to add OCSP stapling support in TLS, if Exim
+ # was built using OpenSSL.
+ # EXPERIMENTAL_OCSP=yes
  
  
  ###############################################################################
index 61b2f38e0aab16896cc1cae366e182d4ed54c7c8,a5e12d2abc834b3725488f2c3ef48958537af667..14dbd0a00c2ee39d58a60cdbf018b94d7093ac1d
@@@ -158,10 -158,11 +158,11 @@@ it's a default value. *
  #define WITH_OLD_CLAMAV_STREAM
  
  /* EXPERIMENTAL features */
- #define EXPERIMENTAL_SPF
- #define EXPERIMENTAL_SRS
  #define EXPERIMENTAL_BRIGHTMAIL
  #define EXPERIMENTAL_DCC
+ #define EXPERIMENTAL_OCSP
+ #define EXPERIMENTAL_SPF
+ #define EXPERIMENTAL_SRS
  
  /* Things that are not routinely changed but are nevertheless configurable
  just in case. */
  #define ROOT_UID                      0
  #define ROOT_GID                      0
  
 +/* Sizes for integer arithmetic.  Go for 64bit; can be overridden in OS/os.h-FOO */
 +#ifndef int_eximarith_t
 + #define int_eximarith_t int64_t
 +#endif
 +#ifndef PR_EXIM_ARITH
 + #define PR_EXIM_ARITH "%" PRId64             /* C99 standard, printf %lld */
 +#endif
 +#ifndef SC_EXIM_ARITH
 + #define SC_EXIM_ARITH "%" SCNi64             /* scanf incl. 0x prefix */
 +#endif
 +#ifndef SC_EXIM_DEC
 + #define SC_EXIM_DEC   "%" SCNd64             /* scanf decimal */
 +#endif
 +
  /* End of config.h.defaults */
diff --combined src/src/globals.c
index d341ceb4ab709f70f0f0edf69e96fb298ff3d5d4,5ea4329125b9b0fd2d5b74de5cead93026aeeb7f..666f5e78a07875b3722d3e78005158fe1612197a
@@@ -112,11 -112,16 +112,14 @@@ uschar *tls_advertise_hosts    = NULL
  uschar *tls_certificate        = NULL;
  uschar *tls_crl                = NULL;
  uschar *tls_dhparam            = NULL;
+ #if defined(EXPERIMENTAL_OCSP) && !defined(USE_GNUTLS)
+ uschar *tls_ocsp_file          = NULL;
+ #endif
  BOOL    tls_offered            = FALSE;
  uschar *tls_privatekey         = NULL;
  BOOL    tls_remember_esmtp     = FALSE;
  uschar *tls_require_ciphers    = NULL;
 -#ifndef USE_GNUTLS
  uschar *tls_sni                = NULL;
 -#endif
  uschar *tls_try_verify_hosts   = NULL;
  uschar *tls_verify_certificates= NULL;
  uschar *tls_verify_hosts       = NULL;
@@@ -657,8 -662,6 +660,8 @@@ uschar *hosts_connection_nolog = NULL
  int     ignore_bounce_errors_after = 10*7*24*60*60;  /* 10 weeks */
  BOOL    ignore_fromline_local  = FALSE;
  uschar *ignore_fromline_hosts  = NULL;
 +BOOL    inetd_wait_mode        = FALSE;
 +int     inetd_wait_timeout     = -1;
  uschar *interface_address      = NULL;
  int     interface_port         = -1;
  BOOL    is_inetd               = FALSE;
diff --combined src/src/globals.h
index 37b0f6cf041834ce6265ede9ba009e9a4498f00e,ec19d0a23341768ab2d0e89510c951dde9bfffe1..f0bc09f35d52e88838577bb415f4b08c99bbcd40
@@@ -94,11 -94,16 +94,14 @@@ extern uschar *tls_certificate;        
  extern uschar *tls_channelbinding_b64; /* string of base64 channel binding */
  extern uschar *tls_crl;                /* CRL File */
  extern uschar *tls_dhparam;            /* DH param file */
+ #if defined(EXPERIMENTAL_OCSP) && !defined(USE_GNUTLS)
+ extern uschar *tls_ocsp_file;          /* OCSP stapling proof file */
+ #endif
  extern BOOL    tls_offered;            /* Server offered TLS */
  extern uschar *tls_privatekey;         /* Private key file */
  extern BOOL    tls_remember_esmtp;     /* For YAEB */
  extern uschar *tls_require_ciphers;    /* So some can be avoided */
 -#ifndef USE_GNUTLS
  extern uschar *tls_sni;                /* Server Name Indication */
 -#endif
  extern uschar *tls_try_verify_hosts;   /* Optional client verification */
  extern uschar *tls_verify_certificates;/* Path for certificates to check */
  extern uschar *tls_verify_hosts;       /* Mandatory client verification */
@@@ -422,8 -427,6 +425,8 @@@ extern uschar *hosts_treat_as_local;   
  extern int     ignore_bounce_errors_after; /* Keep them for this time. */
  extern BOOL    ignore_fromline_local;  /* Local SMTP ignore fromline */
  extern uschar *ignore_fromline_hosts;  /* Hosts permitted to send "From " */
 +extern BOOL    inetd_wait_mode;        /* Whether running in inetd wait mode */
 +extern int     inetd_wait_timeout;     /* Timeout for inetd wait mode */
  extern BOOL    is_inetd;               /* True for inetd calls */
  extern uschar *iterate_item;           /* Item from iterate list */
  
diff --combined src/src/readconf.c
index cdd32be5843b5f581c7f074e0839a352656100f5,badb6a27609f1983bae803973ad8d23d1a086664..95e155ff317a86dc43d4e8981531b5aad752e2a6
@@@ -235,7 -235,6 +235,7 @@@ static optionlist optionlist_config[] 
    { "gecos_pattern",            opt_stringptr,   &gecos_pattern },
  #ifdef SUPPORT_TLS
    { "gnutls_compat_mode",       opt_bool,        &gnutls_compat_mode },
 +  /* These three gnutls_require_* options stopped working in Exim 4.78 */
    { "gnutls_require_kx",        opt_stringptr,   &gnutls_require_kx },
    { "gnutls_require_mac",       opt_stringptr,   &gnutls_require_mac },
    { "gnutls_require_protocols", opt_stringptr,   &gnutls_require_proto },
    { "tls_certificate",          opt_stringptr,   &tls_certificate },
    { "tls_crl",                  opt_stringptr,   &tls_crl },
    { "tls_dhparam",              opt_stringptr,   &tls_dhparam },
+ #if defined(EXPERIMENTAL_OCSP) && !defined(USE_GNUTLS)
+   { "tls_ocsp_file",            opt_stringptr,   &tls_ocsp_file },
+ #endif
    { "tls_on_connect_ports",     opt_stringptr,   &tls_on_connect_ports },
    { "tls_privatekey",           opt_stringptr,   &tls_privatekey },
    { "tls_remember_esmtp",       opt_bool,        &tls_remember_esmtp },
diff --combined src/src/tls-openssl.c
index 316fd5a908eae3fa9516f1cea26a9939e3ce0730,9ead7945d6d55e7898a09016a2debc802f5361eb..e485aa67d74e4fad0834ac405bd1498181863f95
@@@ -20,6 -20,14 +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. */
  
@@@ -48,6 -56,11 +56,11 @@@ static BOOL    reexpand_tls_files_for_s
  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;
@@@ -63,6 -76,12 +76,12 @@@ 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
  
  /*************************************************
  *               Handle TLS error                 *
@@@ -298,6 -317,131 +317,131 @@@ 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          *
  *************************************************/
@@@ -314,7 -458,7 +458,7 @@@ Returns:          OK/DEFER/FAI
  */
  
  static int
- tls_expand_session_files(SSL_CTX *sctx, const tls_ext_ctx_cb *cbinfo)
+ tls_expand_session_files(SSL_CTX *sctx, tls_ext_ctx_cb *cbinfo)
  {
  uschar *expanded;
  
@@@ -352,6 -496,27 +496,27 @@@ if (expanded != NULL && *expanded != 0
        "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;
  }
  
@@@ -375,15 -540,11 +540,11 @@@ Arguments
  Returns:          SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK}
  */
  
- static int
- tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg);
- /* pre-declared for SSL_CTX_set_tlsext_servername_callback call within func */
  static int
  tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
  {
  const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
+ tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
  int rc;
  int old_pool = store_pool;
  
@@@ -424,11 -585,20 +585,20 @@@ SSL_CTX_set_tlsext_servername_callback(
  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 = tls_expand_session_files(ctx_sni, cbinfo);
+ rc = setup_certs(ctx_sni, tls_verify_certificates, tls_crl, NULL, FALSE);
  if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
  
- rc = setup_certs(ctx_sni, tls_verify_certificates, tls_crl, NULL, FALSE);
+ /* 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");
@@@ -440,6 -610,45 +610,45 @@@ 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                  *
  *************************************************/
@@@ -459,7 -668,11 +668,11 @@@ Returns:          OK/DEFER/FAI
  
  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;
@@@ -469,6 -682,9 +682,9 @@@ 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;
  
@@@ -546,7 -762,7 +762,7 @@@ els
  
  if (!init_dh(dhparam, host)) return DEFER;
  
- /* Set up certificate and key */
+ /* Set up certificate and key (and perhaps OCSP info) */
  
  rc = tls_expand_session_files(ctx, cbinfo);
  if (rc != OK) return rc;
  #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)
+     {
+     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);
@@@ -779,6 -1006,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
  */
  
  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;
@@@ -805,7 -1038,11 +1032,11 @@@ 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;
  
@@@ -813,9 -1050,8 +1044,9 @@@ if (!expand_check(require_ciphers, US"t
    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)
    {
@@@ -949,6 -1185,11 +1180,6 @@@ Argument
    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
  tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
    uschar *certificate, uschar *privatekey, uschar *sni,
    uschar *verify_certs, uschar *crl,
 -  uschar *require_ciphers, uschar *require_mac, uschar *require_kx,
 -  uschar *require_proto, int timeout)
 +  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;
@@@ -1281,7 -1527,7 +1516,7 @@@ fprintf(f, "Library version: OpenSSL: C
  
  
  /*************************************************
 -*        Pseudo-random number generation         *
 +*            Random number generation            *
  *************************************************/
  
  /* Pseudo-random number generation.  The result is not expected to be
@@@ -1296,7 -1542,7 +1531,7 @@@ Returns     a random number in range [0
  */
  
  int
 -pseudo_random_number(int max)
 +vaguely_random_number(int max)
  {
  unsigned int r;
  int i, needed_len;
@@@ -1332,14 -1578,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)
    {