.row &%tls_crl%& "certificate revocation list"
.row &%tls_dh_max_bits%& "clamp D-H bit count suggestion"
.row &%tls_dhparam%& "DH parameters for server"
+.row &%tls_ocsp_file%& "location of server certificate status proof"
.row &%tls_on_connect_ports%& "specify SSMTP (SMTPS) ports"
.row &%tls_privatekey%& "location of server private key"
.row &%tls_remember_esmtp%& "don't reset after starting TLS"
acceptable bound from 1024 to 2048.
+.option tls_ocsp_file main string&!! unset
+This option
+must if set expand to the absolute path to a file which contains a current
+status proof for the server's certificate, as obtained from the
+Certificate Authority.
+
+
.option tls_on_connect_ports main "string list" unset
This option specifies a list of incoming SSMTP (aka SMTPS) ports that should
operate the obsolete SSMTP (SMTPS) protocol, where a TLS session is immediately
&<<CHAPSMTPAUTH>>& for details of authentication.
+.option hosts_request_ocsp smtp "host list&!!" *
+.cindex "TLS" "requiring for certain servers"
+Exim will request a Certificate Status on a
+TLS session for any host that matches this list.
+&%tls_verify_certificates%& should also be set for the transport.
+
+.option hosts_require_ocsp smtp "host list&!!" unset
+.cindex "TLS" "requiring for certain servers"
+Exim will request, and check for a valid Certificate Status being given, on a
+TLS session for any host that matches this list.
+&%tls_verify_certificates%& should also be set for the transport.
+
.option hosts_require_tls smtp "host list&!!" unset
.cindex "TLS" "requiring for certain servers"
Exim will insist on using a TLS session when delivering to any host that
.cindex "TLS" "revoked certificates"
.cindex "revocation list"
.cindex "certificate" "revocation list"
+.cindex "OCSP" "stapling"
Certificate issuing authorities issue Certificate Revocation Lists (CRLs) when
certificates are revoked. If you have such a list, you can pass it to an Exim
server using the global option called &%tls_crl%& and to an Exim client using
an identically named option for the &(smtp)& transport. In each case, the value
of the option is expanded and must then be the name of a file that contains a
CRL in PEM format.
+The downside is that clients have to periodically re-download a potentially huge
+file from every certificate authority the know of.
+
+The way with most moving parts at query time is Online Certificate
+Status Protocol (OCSP), where the client verifies the certificate
+against an OCSP server run by the CA. This lets the CA track all
+usage of the certs. It requires running software with access to the
+private key of the CA, to sign the responses to the OCSP queries. OCSP
+is based on HTTP and can be proxied accordingly.
+
+The only widespread OCSP server implementation (known to this writer)
+comes as part of OpenSSL and aborts on an invalid request, such as
+connecting to the port and then disconnecting. This requires
+re-entering the passphrase each time some random client does this.
+
+The third way is OCSP Stapling; in this, the server using a certificate
+issued by the CA periodically requests an OCSP proof of validity from
+the OCSP server, then serves it up inline as part of the TLS
+negotiation. This approach adds no extra round trips, does not let the
+CA track users, scales well with number of certs issued by the CA and is
+resilient to temporary OCSP server failures, as long as the server
+starts retrying to fetch an OCSP proof some time before its current
+proof expires. The downside is that it requires server support.
+
+Unless Exim is built with the support disabled,
+or with GnuTLS earlier than version 3.1.3,
+support for OCSP stapling is included.
+
+There is a global option called &%tls_ocsp_file%&.
+The file specified therein is expected to be in DER format, and contain
+an OCSP proof. Exim will serve it as part of the TLS handshake. This
+option will be re-expanded for SNI, if the &%tls_certificate%& option
+contains &`tls_in_sni`&, as per other TLS options.
+
+Exim does not at this time implement any support for fetching a new OCSP
+proof. The burden is on the administrator to handle this, outside of
+Exim. The file specified should be replaced atomically, so that the
+contents are always valid. Exim will expand the &%tls_ocsp_file%& option
+on each connection, so a new file will be handled transparently on the
+next connection.
+
+When built with OpenSSL Exim will check for a valid next update timestamp
+in the OCSP proof; if not present, or if the proof has expired, it will be
+ignored.
+
+For the client to be able to verify the stapled OCSP the server must
+also supply, in its stapled information, any intermediate
+certificates for the chain leading to the OCSP proof from the signer
+of the server certificate. There may be zero or one such. These
+intermediate certificates should be added to the server OCSP stapling
+file named by &%tls_ocsp_file%&.
+
+Note that the proof only covers the terminal server certificate,
+not any of the chain from CA to it.
+
+.code
+ A helper script "ocsp_fetch.pl" for fetching a proof from a CA
+ OCSP server is supplied. The server URL may be included in the
+ server certificate, if the CA is helpful.
+
+ One failure mode seen was the OCSP Signer cert expiring before the end
+ of validity of the OCSP proof. The checking done by Exim/OpenSSL
+ noted this as invalid overall, but the re-fetch script did not.
+.endd
+
+
.section "Configuring an Exim client to use TLS" "SECID185"
certificate verification to the listed servers. Verification either must
or need not succeed respectively.
+The &(smtp)& transport has two OCSP-related options:
+&%hosts_require_ocsp%&; a host-list for which a Certificate Status
+is requested and required for the connection to proceed. The default
+value is empty.
+&%hosts_request_ocsp%&; a host-list for which (additionally)
+a Certificate Status is requested (but not necessarily verified). The default
+value is "*" meaning that requests are made unless configured
+otherwise.
+
+The host(s) should also be in &%hosts_require_tls%&, and
+&%tls_verify_certificates%& configured for the transport,
+for OCSP to be relevant.
+
If
&%tls_require_ciphers%& is set on the &(smtp)& transport, it must contain a
list of permitted cipher suites. If either of these checks fails, delivery to
.next
.vindex "&%tls_verify_certificates%&"
&%tls_verify_certificates%&
+.next
+.vindex "&%tls_ocsp_file%&"
+&%tls_verify_certificates%&
.endlist
Great care should be taken to deal with matters of case, various injection
TL/11 Bug 1119: fix memory allocation in string_printing2(). Patch from
Christian Aistleitner.
+JH/24 The OCSP stapling feature is moved from Experimental into the mainline.
+
Exim version 4.82
-----------------
7. New command-line option -C for exiqgrep to specify alternate exim.conf
file when searching the queue.
- 8. EXPERIMENTAL_OCSP now supports GnuTLS also, if you have version 3.1.3
- or later of that.
+ 8. OCSP now supports GnuTLS also, if you have version 3.1.3 or later of that.
9. Support for DNSSEC on outbound connections.
11. PRDR is now supported dy default.
+12. OCSP stapling is now supported by default.
+
+13. If built with the EXPERIMENTAL_DSN feature enabled, Exim will output
+ Delivery Status Notification messages in MIME format, and negociate
+ DSN features per RFC 3461.
+
Version 4.82
------------
liable to incompatible change.
-OCSP Stapling support
---------------------------------------------------------------
-
-X.509 PKI certificates expire and can be revoked; to handle this, the
-clients need some way to determine if a particular certificate, from a
-particular Certificate Authority (CA), is still valid. There are three
-main ways to do so.
-
-The simplest way is to serve up a Certificate Revocation List (CRL) with
-an ordinary web-server, regenerating the CRL before it expires. The
-downside is that clients have to periodically re-download a potentially
-huge file from every certificate authority it knows of.
-
-The way with most moving parts at query time is Online Certificate
-Status Protocol (OCSP), where the client verifies the certificate
-against an OCSP server run by the CA. This lets the CA track all
-usage of the certs. This requires running software with access to the
-private key of the CA, to sign the responses to the OCSP queries. OCSP
-is based on HTTP and can be proxied accordingly.
-
-The only widespread OCSP server implementation (known to this writer)
-comes as part of OpenSSL and aborts on an invalid request, such as
-connecting to the port and then disconnecting. This requires
-re-entering the passphrase each time some random client does this.
-
-The third way is OCSP Stapling; in this, the server using a certificate
-issued by the CA periodically requests an OCSP proof of validity from
-the OCSP server, then serves it up inline as part of the TLS
-negotiation. This approach adds no extra round trips, does not let the
-CA track users, scales well with number of certs issued by the CA and is
-resilient to temporary OCSP server failures, as long as the server
-starts retrying to fetch an OCSP proof some time before its current
-proof expires. The downside is that it requires server support.
-
-If Exim is built with EXPERIMENTAL_OCSP and it was built with OpenSSL,
-or with GnuTLS 3.1.3 or later, then it gains a new global option:
-"tls_ocsp_file".
-
-The file specified therein is expected to be in DER format, and contain
-an OCSP proof. Exim will serve it as part of the TLS handshake. This
-option will be re-expanded for SNI, if the tls_certificate option
-contains $tls_sni, as per other TLS options.
-
-Exim does not at this time implement any support for fetching a new OCSP
-proof. The burden is on the administrator to handle this, outside of
-Exim. The file specified should be replaced atomically, so that the
-contents are always valid. Exim will expand the "tls_ocsp_file" option
-on each connection, so a new file will be handled transparently on the
-next connection.
-
-Under OpenSSL Exim will check for a valid next update timestamp in the
-OCSP proof; if not present, or if the proof has expired, it will be
-ignored.
-
-Also, given EXPERIMENTAL_OCSP, the smtp transport gains two options:
-- "hosts_require_ocsp"; a host-list for which an OCSP Stapling
-is requested and required for the connection to proceed. The default
-value is empty.
-- "hosts_request_ocsp"; a host-list for which (additionally) an OCSP
-Stapling is requested (but not necessarily verified). The default
-value is "*" meaning that requests are made unless configured
-otherwise.
-
-The host(s) should also be in "hosts_require_tls", and
-"tls_verify_certificates" configured for the transport.
-
-For the client to be able to verify the stapled OCSP the server must
-also supply, in its stapled information, any intermediate
-certificates for the chain leading to the OCSP proof from the signer
-of the server certificate. There may be zero or one such. These
-intermediate certificates should be added to the server OCSP stapling
-file (named by tls_ocsp_file).
-
-Note that the proof only covers the terminal server certificate,
-not any of the chain from CA to it.
-
-At this point in time, we're gathering feedback on use, to determine if
-it's worth adding complexity to the Exim daemon to periodically re-fetch
-OCSP files and somehow handling multiple files.
-
- A helper script "ocsp_fetch.pl" for fetching a proof from a CA
- OCSP server is supplied. The server URL may be included in the
- server certificate, if the CA is helpful.
-
- One failure mode seen was the OCSP Signer cert expiring before the end
- of validity of the OCSP proof. The checking done by Exim/OpenSSL
- noted this as invalid overall, but the re-fetch script did not.
-
-
-
-
Brightmail AntiSpam (BMI) suppport
--------------------------------------------------------------
# DISABLE_PRDR=yes
+#------------------------------------------------------------------------------
+# Uncomment the following line to remove OCSP stapling support in TLS,
+# from Exim. Note it can only be supported when built with
+# GnuTLS 3.1.3 or later, or OpenSSL
+
+# DISABLE_OCSP=yes
+
#------------------------------------------------------------------------------
# By default, Exim has support for checking the AD bit in a DNS response, to
# determine if DNSSEC validation was successful. If your system libraries
# 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, or with GnuTLS 3.1.3 or later.
-
-# EXPERIMENTAL_OCSP=yes
-
# Uncomment the following line to add DMARC checking capability, implemented
# using libopendmarc libraries.
# EXPERIMENTAL_DMARC=yes
#define DELIVER_IN_BUFFER_SIZE 8192
#define DELIVER_OUT_BUFFER_SIZE 8192
#define DISABLE_DKIM
+#define DISABLE_PRDR
+#define DISABLE_OCSP
#define DISABLE_DNSSEC
#define DISABLE_D_OPTION
#define EXPERIMENTAL_DCC
#define EXPERIMENTAL_DMARC
#define EXPERIMENTAL_DSN
-#define EXPERIMENTAL_OCSP
#define EXPERIMENTAL_PROXY
#define EXPERIMENTAL_REDIS
#define EXPERIMENTAL_SPF
(void) tls_import_cert(ptr, &addr->ourcert);
break;
- #ifdef EXPERIMENTAL_OCSP
+ #ifndef DISABLE_OCSP
case '4':
addr->ocsp = OCSP_NOT_REQ;
if (*ptr)
*ptr++ = 0;
rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
}
- # ifdef EXPERIMENTAL_OCSP
+ #ifndef DISABLE_OCSP
if (addr->ocsp > OCSP_NOT_REQ)
{
ptr = big_buffer;
#ifndef DISABLE_PRDR
fprintf(f, " PRDR");
#endif
+#ifndef DISABLE_OCSP
+ fprintf(f, " OCSP");
+#endif
#ifdef EXPERIMENTAL_SPF
fprintf(f, " Experimental_SPF");
#endif
#ifdef EXPERIMENTAL_DMARC
fprintf(f, " Experimental_DMARC");
#endif
-#ifdef EXPERIMENTAL_OCSP
- fprintf(f, " Experimental_OCSP");
-#endif
#ifdef EXPERIMENTAL_PROXY
fprintf(f, " Experimental_Proxy");
#endif
bit-count as "NORMAL" (2432) and Thunderbird dropping connection. */
int tls_dh_max_bits = 2236;
uschar *tls_dhparam = NULL;
-#if defined(EXPERIMENTAL_OCSP)
+#ifndef DISABLE_OCSP
uschar *tls_ocsp_file = NULL;
#endif
BOOL tls_offered = FALSE;
extern uschar *tls_crl; /* CRL File */
extern int tls_dh_max_bits; /* don't accept higher lib suggestions */
extern uschar *tls_dhparam; /* DH param file */
-#if defined(EXPERIMENTAL_OCSP)
+#ifndef DISABLE_OCSP
extern uschar *tls_ocsp_file; /* OCSP stapling proof file */
#endif
extern BOOL tls_offered; /* Server offered TLS */
{ "tls_crl", opt_stringptr, &tls_crl },
{ "tls_dh_max_bits", opt_int, &tls_dh_max_bits },
{ "tls_dhparam", opt_stringptr, &tls_dhparam },
-# if defined(EXPERIMENTAL_OCSP)
+# ifndef DISABLE_OCSP
{ "tls_ocsp_file", opt_stringptr, &tls_ocsp_file },
# endif
{ "tls_on_connect_ports", opt_stringptr, &tls_in.on_connect_ports },
#if GNUTLS_VERSION_NUMBER >= 0x020c00
# include <gnutls/pkcs11.h>
#endif
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
# include <gnutls/ocsp.h>
#endif
static int exim_sni_handling_cb(gnutls_session_t session);
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
static int server_ocsp_stapling_cb(gnutls_session_t session, void * ptr,
gnutls_datum_t * ocsp_response);
#endif
/* Set the OCSP stapling server info */
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
if ( !host /* server */
&& tls_ocsp_file
)
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
static int
server_ocsp_stapling_cb(gnutls_session_t session, void * ptr,
int rc;
const char *error;
exim_gnutls_state_st *state = NULL;
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
BOOL require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp,
NULL, host->name, host->address, NULL) == OK;
BOOL request_ocsp = require_ocsp ? TRUE
gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
}
-#ifdef EXPERIMENTAL_OCSP /* since GnuTLS 3.1.3 */
+#ifndef DISABLE_OCSP
+ /* supported since GnuTLS 3.1.3 */
if (request_ocsp)
{
DEBUG(D_tls) debug_printf("TLS: will request OCSP stapling\n");
!verify_certificate(state, &error))
return tls_error(US"certificate verification failed", error, state->host);
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
if (require_ocsp)
{
DEBUG(D_tls)
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
# include <openssl/ocsp.h>
#endif
-#ifdef EXPERIMENTAL_OCSP
-#define EXIM_OCSP_SKEW_SECONDS (300L)
-#define EXIM_OCSP_MAX_AGE (-1L)
+#ifndef DISABLE_OCSP
+# define EXIM_OCSP_SKEW_SECONDS (300L)
+# define EXIM_OCSP_MAX_AGE (-1L)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
typedef struct tls_ext_ctx_cb {
uschar *certificate;
uschar *privatekey;
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
BOOL is_server;
union {
struct {
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
static int tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg);
#endif
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
static int tls_server_stapling_cb(SSL *s, void *arg);
#endif
/* Extreme debug
-#if defined(EXPERIMENTAL_OCSP)
+#ifndef DISABLE_OCSP
void
x509_store_dump_cert_s_names(X509_STORE * store)
{
{
DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n",
X509_STORE_CTX_get_error_depth(x509ctx), txt);
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
if (tlsp == &tls_out && client_static_cbinfo->u_ocsp.client.verify_store)
{ /* client, wanting stapling */
/* Add the server cert's signing chain as the one
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
/*************************************************
* Load OCSP information into state *
*************************************************/
}
return;
}
-#endif /*EXPERIMENTAL_OCSP*/
+#endif /*!DISABLE_OCSP*/
"SSL_CTX_use_PrivateKey_file file=%s", expanded), cbinfo->host, NULL);
}
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
if (cbinfo->is_server && cbinfo->u_ocsp.server.file != NULL)
{
if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded))
SSL_CTX_set_tlsext_servername_arg(server_sni, cbinfo);
if (cbinfo->server_cipher_list)
SSL_CTX_set_cipher_list(server_sni, CS cbinfo->server_cipher_list);
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
if (cbinfo->u_ocsp.server.file)
{
SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
/*************************************************
* Callback to handle OCSP Stapling *
OCSP_RESPONSE_free(rsp);
return i;
}
-#endif /*EXPERIMENTAL_OCSP*/
+#endif /*!DISABLE_OCSP*/
static int
tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
uschar *privatekey,
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
uschar *ocsp_file,
#endif
address_item *addr, tls_ext_ctx_cb ** cbp)
cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
cbinfo->certificate = certificate;
cbinfo->privatekey = privatekey;
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
if ((cbinfo->is_server = host==NULL))
{
cbinfo->u_ocsp.server.file = ocsp_file;
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
if (host == NULL) /* server */
{
-# ifdef EXPERIMENTAL_OCSP
+# ifndef DISABLE_OCSP
/* We check u_ocsp.server.file, not server.response, because we care about if
the option exists, not what the current expansion might be, as SNI might
change the certificate and OCSP file in use between now and the time the
SSL_CTX_set_tlsext_servername_callback(*ctxp, tls_servername_cb);
SSL_CTX_set_tlsext_servername_arg(*ctxp, cbinfo);
}
-# ifdef EXPERIMENTAL_OCSP
+# ifndef DISABLE_OCSP
else /* client */
if(ocsp_file) /* wanting stapling */
{
the error. */
rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey,
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
tls_ocsp_file,
#endif
NULL, &server_static_cbinfo);
X509* server_cert;
int rc;
static uschar cipherbuf[256];
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
BOOL require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp,
NULL, host->name, host->address, NULL) == OK;
BOOL request_ocsp = require_ocsp ? TRUE
rc = tls_init(&client_ctx, host, NULL,
ob->tls_certificate, ob->tls_privatekey,
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
(void *)(long)request_ocsp,
#endif
addr, &client_static_cbinfo);
}
}
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
/* Request certificate status at connection-time. If the server
does OCSP stapling we will get the callback (set in tls_init()) */
if (request_ocsp)
(void *)offsetof(smtp_transport_options_block, hosts_override) },
{ "hosts_randomize", opt_bool,
(void *)offsetof(smtp_transport_options_block, hosts_randomize) },
-#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_OCSP)
+#if defined(SUPPORT_TLS) && !defined(DISABLE_OCSP)
{ "hosts_request_ocsp", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, hosts_request_ocsp) },
#endif
{ "hosts_require_auth", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, hosts_require_auth) },
#ifdef SUPPORT_TLS
-# if defined EXPERIMENTAL_OCSP
+# ifndef DISABLE_OCSP
{ "hosts_require_ocsp", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, hosts_require_ocsp) },
# endif
#ifndef DISABLE_PRDR
NULL, /* hosts_try_prdr */
#endif
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
US"*", /* hosts_request_ocsp */
NULL, /* hosts_require_ocsp */
#endif
#ifndef DISABLE_PRDR
uschar *hosts_try_prdr;
#endif
-#ifdef EXPERIMENTAL_OCSP
+#ifndef DISABLE_OCSP
uschar *hosts_request_ocsp;
uschar *hosts_require_ocsp;
#endif
support OpenSSL
-support Experimental_OCSP
+support OCSP
running IPv4
support OpenSSL
-support Experimental_OCSP
+support OCSP
support Experimental_TPDA
running IPv4
support GnuTLS
-support Experimental_OCSP
+support OCSP
running IPv4
support GnuTLS
-support Experimental_OCSP
+support OCSP
support Experimental_TPDA
running IPv4