"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/tls-openssl.c" between
exim-4.91.tar.xz and exim-4.92.tar.xz

About: Exim is a message transfer agent (MTA).

tls-openssl.c  (exim-4.91.tar.xz):tls-openssl.c  (exim-4.92.tar.xz)
skipping to change at line 52 skipping to change at line 52
#if OPENSSL_VERSION_NUMBER >= 0x00908000L #if OPENSSL_VERSION_NUMBER >= 0x00908000L
# define EXIM_HAVE_RSA_GENKEY_EX # define EXIM_HAVE_RSA_GENKEY_EX
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000L #if OPENSSL_VERSION_NUMBER >= 0x10100000L
# define EXIM_HAVE_OCSP_RESP_COUNT # define EXIM_HAVE_OCSP_RESP_COUNT
#else #else
# define EXIM_HAVE_EPHEM_RSA_KEX # define EXIM_HAVE_EPHEM_RSA_KEX
# define EXIM_HAVE_RAND_PSEUDO # define EXIM_HAVE_RAND_PSEUDO
#endif #endif
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
# define EXIM_HAVE_SHA256 /*MMMM*/ # define EXIM_HAVE_SHA256
#endif #endif
/* /*
* X509_check_host provides sane certificate hostname checking, but was added * X509_check_host provides sane certificate hostname checking, but was added
* to OpenSSL late, after other projects forked off the code-base. So in * to OpenSSL late, after other projects forked off the code-base. So in
* addition to guarding against the base version number, beware that LibreSSL * addition to guarding against the base version number, beware that LibreSSL
* does not (at this time) support this function. * does not (at this time) support this function.
* *
* If LibreSSL gains a different API, perhaps via libtls, then we'll probably * If LibreSSL gains a different API, perhaps via libtls, then we'll probably
* opt to disentangle and ask a LibreSSL user to provide glue for a third * opt to disentangle and ask a LibreSSL user to provide glue for a third
* crypto provider for libtls instead of continuing to tie the OpenSSL glue * crypto provider for libtls instead of continuing to tie the OpenSSL glue
* into even twistier knots. If LibreSSL gains the same API, we can just * into even twistier knots. If LibreSSL gains the same API, we can just
* change this guard and punt the issue for a while longer. * change this guard and punt the issue for a while longer.
*/ */
#ifndef LIBRESSL_VERSION_NUMBER #ifndef LIBRESSL_VERSION_NUMBER
# if OPENSSL_VERSION_NUMBER >= 0x010100000L # if OPENSSL_VERSION_NUMBER >= 0x010100000L
# define EXIM_HAVE_OPENSSL_CHECKHOST # define EXIM_HAVE_OPENSSL_CHECKHOST
# define EXIM_HAVE_OPENSSL_DH_BITS # define EXIM_HAVE_OPENSSL_DH_BITS
# define EXIM_HAVE_OPENSSL_TLS_METHOD
# else
# define EXIM_NEED_OPENSSL_INIT
# endif # endif
# if OPENSSL_VERSION_NUMBER >= 0x010000000L \ # if OPENSSL_VERSION_NUMBER >= 0x010000000L \
&& (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L && (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
# define EXIM_HAVE_OPENSSL_CHECKHOST # define EXIM_HAVE_OPENSSL_CHECKHOST
# endif # endif
#endif #endif
#if !defined(LIBRESSL_VERSION_NUMBER) \ #if !defined(LIBRESSL_VERSION_NUMBER) \
|| LIBRESSL_VERSION_NUMBER >= 0x20010000L || LIBRESSL_VERSION_NUMBER >= 0x20010000L
# if !defined(OPENSSL_NO_ECDH) # if !defined(OPENSSL_NO_ECDH)
# if OPENSSL_VERSION_NUMBER >= 0x0090800fL # if OPENSSL_VERSION_NUMBER >= 0x0090800fL
# define EXIM_HAVE_ECDH /*MMMM*/ # define EXIM_HAVE_ECDH
# endif # endif
# if OPENSSL_VERSION_NUMBER >= 0x10002000L # if OPENSSL_VERSION_NUMBER >= 0x10002000L
# define EXIM_HAVE_OPENSSL_EC_NIST2NID # define EXIM_HAVE_OPENSSL_EC_NIST2NID
# endif # endif
# endif # endif
#endif #endif
#if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP) #if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP)
# warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile" # warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
# define DISABLE_OCSP # define DISABLE_OCSP
#endif #endif
#ifdef EXIM_HAVE_OPENSSL_CHECKHOST #ifdef EXIM_HAVE_OPENSSL_CHECKHOST
# include <openssl/x509v3.h> # include <openssl/x509v3.h>
#endif #endif
/*************************************************
* OpenSSL option parse *
*************************************************/
typedef struct exim_openssl_option {
uschar *name;
long value;
} exim_openssl_option;
/* We could use a macro to expand, but we need the ifdef and not all the
options document which version they were introduced in. Policylet: include
all options unless explicitly for DTLS, let the administrator choose which
to apply.
This list is current as of:
==> 1.0.1b <==
Plus SSL_OP_SAFARI_ECDHE_ECDSA_BUG from 2013-June patch/discussion on openssl-de
v
Plus SSL_OP_NO_TLSv1_3 for 1.1.2-dev
*/
static exim_openssl_option exim_openssl_options[] = {
/* KEEP SORTED ALPHABETICALLY! */
#ifdef SSL_OP_ALL
{ US"all", SSL_OP_ALL },
#endif
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
{ US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIAT
ION },
#endif
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
{ US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
#endif
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
{ US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
#endif
#ifdef SSL_OP_EPHEMERAL_RSA
{ US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
#endif
#ifdef SSL_OP_LEGACY_SERVER_CONNECT
{ US"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT },
#endif
#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
{ US"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
#endif
#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
{ US"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG },
#endif
#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
{ US"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING },
#endif
#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
{ US"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG },
#endif
#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
{ US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BU
G },
#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
#ifdef SSL_OP_NO_SSLv2
{ US"no_sslv2", SSL_OP_NO_SSLv2 },
#endif
#ifdef SSL_OP_NO_SSLv3
{ US"no_sslv3", SSL_OP_NO_SSLv3 },
#endif
#ifdef SSL_OP_NO_TICKET
{ US"no_ticket", SSL_OP_NO_TICKET },
#endif
#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_NO_TLSv1_3
{ US"no_tlsv1_3", SSL_OP_NO_TLSv1_3 },
#endif
#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
{ US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
#endif
#ifdef SSL_OP_SINGLE_DH_USE
{ US"single_dh_use", SSL_OP_SINGLE_DH_USE },
#endif
#ifdef SSL_OP_SINGLE_ECDH_USE
{ US"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE },
#endif
#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
{ US"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
#endif
#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
{ US"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
#endif
#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
{ US"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG },
#endif
#ifdef SSL_OP_TLS_D5_BUG
{ US"tls_d5_bug", SSL_OP_TLS_D5_BUG },
#endif
#ifdef SSL_OP_TLS_ROLLBACK_BUG
{ US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
#endif
};
#ifndef MACRO_PREDEF
static int exim_openssl_options_size = nelem(exim_openssl_options);
#endif
#ifdef MACRO_PREDEF
void
options_tls(void)
{
struct exim_openssl_option * o;
uschar buf[64];
for (o = exim_openssl_options;
o < exim_openssl_options + nelem(exim_openssl_options); o++)
{
/* Trailing X is workaround for problem with _OPT_OPENSSL_NO_TLSV1
being a ".ifdef _OPT_OPENSSL_NO_TLSV1_3" match */
spf(buf, sizeof(buf), US"_OPT_OPENSSL_%T_X", o->name);
builtin_macro_create(buf);
}
}
#else
/******************************************************************************/
/* Structure for collecting random data for seeding. */ /* Structure for collecting random data for seeding. */
typedef struct randstuff { typedef struct randstuff {
struct timeval tv; struct timeval tv;
pid_t p; pid_t p;
} randstuff; } randstuff;
/* Local static variables */ /* Local static variables */
static BOOL client_verify_callback_called = FALSE; static BOOL client_verify_callback_called = FALSE;
static BOOL server_verify_callback_called = FALSE; static BOOL server_verify_callback_called = FALSE;
static const uschar *sid_ctx = US"exim"; static const uschar *sid_ctx = US"exim";
/* We have three different contexts to care about. /* We have three different contexts to care about.
Simple case: client, `client_ctx` Simple case: client, `client_ctx`
As a client, we can be doing a callout or cut-through delivery while receiving As a client, we can be doing a callout or cut-through delivery while receiving
a message. So we have a client context, which should have options initialised a message. So we have a client context, which should have options initialised
from the SMTP Transport. from the SMTP Transport. We may also concurrently want to make TLS connections
to utility daemons, so client-contexts are allocated and passed around in call
args rather than using a gobal.
Server: Server:
There are two cases: with and without ServerNameIndication from the client. There are two cases: with and without ServerNameIndication from the client.
Given TLS SNI, we can be using different keys, certs and various other Given TLS SNI, we can be using different keys, certs and various other
configuration settings, because they're re-expanded with $tls_sni set. This configuration settings, because they're re-expanded with $tls_sni set. This
allows vhosting with TLS. This SNI is sent in the handshake. allows vhosting with TLS. This SNI is sent in the handshake.
A client might not send SNI, so we need a fallback, and an initial setup too. A client might not send SNI, so we need a fallback, and an initial setup too.
So as a server, we start out using `server_ctx`. So as a server, we start out using `server_ctx`.
If SNI is sent by the client, then we as server, mid-negotiation, try to clone If SNI is sent by the client, then we as server, mid-negotiation, try to clone
`server_sni` from `server_ctx` and then initialise settings by re-expanding `server_sni` from `server_ctx` and then initialise settings by re-expanding
configuration. configuration.
*/ */
static SSL_CTX *client_ctx = NULL; typedef struct {
SSL_CTX * ctx;
SSL * ssl;
} exim_openssl_client_tls_ctx;
static SSL_CTX *server_ctx = NULL; static SSL_CTX *server_ctx = NULL;
static SSL *client_ssl = NULL;
static SSL *server_ssl = NULL; static SSL *server_ssl = NULL;
#ifdef EXIM_HAVE_OPENSSL_TLSEXT #ifdef EXIM_HAVE_OPENSSL_TLSEXT
static SSL_CTX *server_sni = NULL; static SSL_CTX *server_sni = NULL;
#endif #endif
static char ssl_errstring[256]; static char ssl_errstring[256];
static int ssl_session_timeout = 200; static int ssl_session_timeout = 200;
static BOOL client_verify_optional = FALSE; static BOOL client_verify_optional = FALSE;
skipping to change at line 221 skipping to change at line 365
errstr pointer to output error message errstr pointer to output error message
Returns: OK/DEFER/FAIL Returns: OK/DEFER/FAIL
*/ */
static int static int
tls_error(uschar * prefix, const host_item * host, uschar * msg, uschar ** errst r) tls_error(uschar * prefix, const host_item * host, uschar * msg, uschar ** errst r)
{ {
if (!msg) if (!msg)
{ {
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
msg = US ssl_errstring; msg = US ssl_errstring;
} }
if (errstr) *errstr = string_sprintf("(%s): %s", prefix, msg); msg = string_sprintf("(%s): %s", prefix, msg);
DEBUG(D_tls) debug_printf("TLS error '%s'\n", msg);
if (errstr) *errstr = msg;
return host ? FAIL : DEFER; return host ? FAIL : DEFER;
} }
/************************************************* /*************************************************
* Callback to generate RSA key * * Callback to generate RSA key *
*************************************************/ *************************************************/
/* /*
Arguments: Arguments:
s SSL connection (not used) s SSL connection (not used)
skipping to change at line 263 skipping to change at line 409
#ifdef EXIM_HAVE_RSA_GENKEY_EX #ifdef EXIM_HAVE_RSA_GENKEY_EX
if ( !BN_set_word(bn, (unsigned long)RSA_F4) if ( !BN_set_word(bn, (unsigned long)RSA_F4)
|| !(rsa_key = RSA_new()) || !(rsa_key = RSA_new())
|| !RSA_generate_key_ex(rsa_key, keylength, bn, NULL) || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL)
) )
#else #else
if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL))) if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL)))
#endif #endif
{ {
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s", log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s",
ssl_errstring); ssl_errstring);
return NULL; return NULL;
} }
return rsa_key; return rsa_key;
} }
/* Extreme debug /* Extreme debug
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
void void
skipping to change at line 285 skipping to change at line 431
{ {
STACK_OF(X509_OBJECT) * roots= store->objs; STACK_OF(X509_OBJECT) * roots= store->objs;
int i; int i;
static uschar name[256]; static uschar name[256];
for(i= 0; i<sk_X509_OBJECT_num(roots); i++) for(i= 0; i<sk_X509_OBJECT_num(roots); i++)
{ {
X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i); X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i);
if(tmp_obj->type == X509_LU_X509) if(tmp_obj->type == X509_LU_X509)
{ {
X509 * current_cert= tmp_obj->data.x509; X509_NAME * sn = X509_get_subject_name(tmp_obj->data.x509);
X509_NAME_oneline(X509_get_subject_name(current_cert), CS name, sizeof(name) if (X509_NAME_oneline(sn, CS name, sizeof(name)))
); {
name[sizeof(name)-1] = '\0'; name[sizeof(name)-1] = '\0';
debug_printf(" %s\n", name); debug_printf(" %s\n", name);
}
} }
} }
} }
#endif #endif
*/ */
#ifndef DISABLE_EVENT #ifndef DISABLE_EVENT
static int static int
verify_event(tls_support * tlsp, X509 * cert, int depth, const uschar * dn, verify_event(tls_support * tlsp, X509 * cert, int depth, const uschar * dn,
BOOL *calledp, const BOOL *optionalp, const uschar * what) BOOL *calledp, const BOOL *optionalp, const uschar * what)
skipping to change at line 368 skipping to change at line 516
preverify_ok current yes/no state as 1/0 preverify_ok current yes/no state as 1/0
x509ctx certificate information. x509ctx certificate information.
tlsp per-direction (client vs. server) support data tlsp per-direction (client vs. server) support data
calledp has-been-called flag calledp has-been-called flag
optionalp verification-is-optional flag optionalp verification-is-optional flag
Returns: 0 if verification should fail, otherwise 1 Returns: 0 if verification should fail, otherwise 1
*/ */
static int static int
verify_callback(int preverify_ok, X509_STORE_CTX *x509ctx, verify_callback(int preverify_ok, X509_STORE_CTX * x509ctx,
tls_support *tlsp, BOOL *calledp, BOOL *optionalp) tls_support * tlsp, BOOL * calledp, BOOL * optionalp)
{ {
X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
int depth = X509_STORE_CTX_get_error_depth(x509ctx); int depth = X509_STORE_CTX_get_error_depth(x509ctx);
uschar dn[256]; uschar dn[256];
X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)); if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)))
{
DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n");
log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
tlsp == &tls_out ? deliver_host_address : sender_host_address);
return 0;
}
dn[sizeof(dn)-1] = '\0'; dn[sizeof(dn)-1] = '\0';
if (preverify_ok == 0) if (preverify_ok == 0)
{ {
uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])", uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])",
*verify_mode, sender_host_address) *verify_mode, sender_host_address)
: US""; : US"";
log_write(0, LOG_MAIN, "[%s] SSL verify error%s: depth=%d error=%s cert=%s", 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, tlsp == &tls_out ? deliver_host_address : sender_host_address,
extra, depth, extra, depth,
skipping to change at line 424 skipping to change at line 578
if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL")) if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL"))
return 0; /* reject, with peercert set */ return 0; /* reject, with peercert set */
#endif #endif
} }
else else
{ {
const uschar * verify_cert_hostnames; const uschar * verify_cert_hostnames;
if ( tlsp == &tls_out if ( tlsp == &tls_out
&& ((verify_cert_hostnames = client_static_cbinfo->verify_cert_hostnames))) && ((verify_cert_hostnames = client_static_cbinfo->verify_cert_hostnames)))
/* client, wanting hostname check */ /* client, wanting hostname check */
{ {
#ifdef EXIM_HAVE_OPENSSL_CHECKHOST #ifdef EXIM_HAVE_OPENSSL_CHECKHOST
# ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS # ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
# define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0 # define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0
# endif # endif
# ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS # ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
# define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0 # define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0
# endif # endif
int sep = 0; int sep = 0;
skipping to change at line 520 skipping to change at line 674
static int static int
verify_callback_client_dane(int preverify_ok, X509_STORE_CTX * x509ctx) verify_callback_client_dane(int preverify_ok, X509_STORE_CTX * x509ctx)
{ {
X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
uschar dn[256]; uschar dn[256];
int depth = X509_STORE_CTX_get_error_depth(x509ctx); int depth = X509_STORE_CTX_get_error_depth(x509ctx);
#ifndef DISABLE_EVENT #ifndef DISABLE_EVENT
BOOL dummy_called, optional = FALSE; BOOL dummy_called, optional = FALSE;
#endif #endif
X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)); if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)))
{
DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n");
log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
deliver_host_address);
return 0;
}
dn[sizeof(dn)-1] = '\0'; dn[sizeof(dn)-1] = '\0';
DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n", DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n",
preverify_ok ? "ok":"BAD", depth, dn); preverify_ok ? "ok":"BAD", depth, dn);
#ifndef DISABLE_EVENT #ifndef DISABLE_EVENT
if (verify_event(&tls_out, cert, depth, dn, if (verify_event(&tls_out, cert, depth, dn,
&dummy_called, &optional, US"DANE")) &dummy_called, &optional, US"DANE"))
return 0; /* reject, with peercert set */ return 0; /* reject, with peercert set */
#endif #endif
skipping to change at line 580 skipping to change at line 740
s the SSL connection s the SSL connection
where where
ret ret
Returns: nothing Returns: nothing
*/ */
static void static void
info_callback(SSL *s, int where, int ret) info_callback(SSL *s, int where, int ret)
{ {
where = where; DEBUG(D_tls)
ret = ret; {
DEBUG(D_tls) debug_printf("SSL info: %s\n", SSL_state_string_long(s)); const uschar * str;
if (where & SSL_ST_CONNECT)
str = US"SSL_connect";
else if (where & SSL_ST_ACCEPT)
str = US"SSL_accept";
else
str = US"SSL info (undefined)";
if (where & SSL_CB_LOOP)
debug_printf("%s: %s\n", str, SSL_state_string_long(s));
else if (where & SSL_CB_ALERT)
debug_printf("SSL3 alert %s:%s:%s\n",
str = where & SSL_CB_READ ? US"read" : US"write",
SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
else if (where & SSL_CB_EXIT)
if (ret == 0)
debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s));
else if (ret < 0)
debug_printf("%s: error in %s\n", str, SSL_state_string_long(s));
else if (where & SSL_CB_HANDSHAKE_START)
debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s));
else if (where & SSL_CB_HANDSHAKE_DONE)
debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s));
}
} }
/************************************************* /*************************************************
* Initialize for DH * * Initialize for DH *
*************************************************/ *************************************************/
/* If dhparam is set, expand it, and load up the parameters for DH encryption. /* If dhparam is set, expand it, and load up the parameters for DH encryption.
Arguments: Arguments:
sctx The current SSL CTX (inbound or outbound) sctx The current SSL CTX (inbound or outbound)
skipping to change at line 897 skipping to change at line 1081
Separately we might try to replace using OCSP_basic_verify() - which seems to no t Separately we might try to replace using OCSP_basic_verify() - which seems to no t
be a public interface into the OpenSSL library (there's no manual entry) - be a public interface into the OpenSSL library (there's no manual entry) -
But what with? We also use OCSP_basic_verify in the client stapling callback. 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 And there we NEED it; we must verify that status... unless the
library does it for us anyway? */ library does it for us anyway? */
if ((i = OCSP_basic_verify(basic_response, sk, NULL, verify_flags)) < 0) 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); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
debug_printf("OCSP response verify failure: %s\n", US ssl_errstring); debug_printf("OCSP response verify failure: %s\n", US ssl_errstring);
} }
goto bad; goto bad;
} }
/* Here's the simplifying assumption: there's only one response, for the /* 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 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 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 (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()). right cert in the stack and then calls OCSP_single_get0_status()).
skipping to change at line 938 skipping to change at line 1122
{ {
DEBUG(D_tls) debug_printf("OCSP status invalid times.\n"); DEBUG(D_tls) debug_printf("OCSP status invalid times.\n");
goto bad; goto bad;
} }
supply_response: supply_response:
cbinfo->u_ocsp.server.response = resp; /*XXX stack?*/ cbinfo->u_ocsp.server.response = resp; /*XXX stack?*/
return; return;
bad: bad:
if (running_in_test_harness) if (f.running_in_test_harness)
{ {
extern char ** environ; extern char ** environ;
uschar ** p; uschar ** p;
if (environ) for (p = USS environ; *p; p++) if (environ) for (p = USS environ; *p; p++)
if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0) if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0)
{ {
DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n"); DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n");
goto supply_response; goto supply_response;
} }
} }
skipping to change at line 973 skipping to change at line 1157
where = US"allocating pkey"; where = US"allocating pkey";
if (!(pkey = EVP_PKEY_new())) if (!(pkey = EVP_PKEY_new()))
goto err; goto err;
where = US"allocating cert"; where = US"allocating cert";
if (!(x509 = X509_new())) if (!(x509 = X509_new()))
goto err; goto err;
where = US"generating pkey"; where = US"generating pkey";
if (!(rsa = rsa_callback(NULL, 0, 1024))) if (!(rsa = rsa_callback(NULL, 0, 2048)))
goto err; goto err;
where = US"assigning pkey"; where = US"assigning pkey";
if (!EVP_PKEY_assign_RSA(pkey, rsa)) if (!EVP_PKEY_assign_RSA(pkey, rsa))
goto err; goto err;
X509_set_version(x509, 2); /* N+1 - version 3 */ X509_set_version(x509, 2); /* N+1 - version 3 */
ASN1_INTEGER_set(X509_get_serialNumber(x509), 0); ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
X509_gmtime_adj(X509_get_notBefore(x509), 0); X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), (long)60 * 60); /* 1 hour */ X509_gmtime_adj(X509_get_notAfter(x509), (long)60 * 60); /* 1 hour */
X509_set_pubkey(x509, pkey); X509_set_pubkey(x509, pkey);
name = X509_get_subject_name(x509); name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", X509_NAME_add_entry_by_txt(name, "C",
MBSTRING_ASC, CUS "UK", -1, -1, 0); MBSTRING_ASC, CUS "UK", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", X509_NAME_add_entry_by_txt(name, "O",
MBSTRING_ASC, CUS "Exim Developers", -1, -1, 0); MBSTRING_ASC, CUS "Exim Developers", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", X509_NAME_add_entry_by_txt(name, "CN",
skipping to change at line 1065 skipping to change at line 1249
static int 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 ** errstr)
{ {
uschar *expanded; uschar *expanded;
if (!cbinfo->certificate) if (!cbinfo->certificate)
{ {
if (!cbinfo->is_server) /* client */ if (!cbinfo->is_server) /* client */
return OK; return OK;
/* server */ /* server */
if (tls_install_selfsign(sctx, errstr) != OK) if (tls_install_selfsign(sctx, errstr) != OK)
return DEFER; return DEFER;
} }
else else
{ {
int err; int err;
if (Ustrstr(cbinfo->certificate, US"tls_sni") || if (Ustrstr(cbinfo->certificate, US"tls_sni") ||
Ustrstr(cbinfo->certificate, US"tls_in_sni") || Ustrstr(cbinfo->certificate, US"tls_in_sni") ||
Ustrstr(cbinfo->certificate, US"tls_out_sni") Ustrstr(cbinfo->certificate, US"tls_out_sni")
skipping to change at line 1097 skipping to change at line 1281
uschar * file; uschar * file;
while (file = string_nextinlist(&file_list, &sep, NULL, 0)) while (file = string_nextinlist(&file_list, &sep, NULL, 0))
if ((err = tls_add_certfile(sctx, cbinfo, file, errstr))) if ((err = tls_add_certfile(sctx, cbinfo, file, errstr)))
return err; return err;
} }
else /* would there ever be a need for multiple client certs? */ else /* would there ever be a need for multiple client certs? */
if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr))) if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr)))
return err; return err;
if (cbinfo->privatekey != NULL && if ( cbinfo->privatekey
!expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr)) && !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr)
)
return DEFER; return DEFER;
/* If expansion was forced to fail, key_expanded will be NULL. If the result /* 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 of the expansion is an empty string, ignore it also, and assume the private
key is in the same file as the certificate. */ key is in the same file as the certificate. */
if (expanded && *expanded) if (expanded && *expanded)
if (cbinfo->is_server) if (cbinfo->is_server)
{ {
const uschar * file_list = expanded; const uschar * file_list = expanded;
skipping to change at line 1190 skipping to change at line 1374
tls_in.sni = string_copy(US servername); tls_in.sni = string_copy(US servername);
store_pool = old_pool; store_pool = old_pool;
if (!reexpand_tls_files_for_sni) if (!reexpand_tls_files_for_sni)
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
/* Can't find an SSL_CTX_clone() or equivalent, so we do it manually; /* 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. not confident that memcpy wouldn't break some internal reference counting.
Especially since there's a references struct member, which would be off. */ Especially since there's a references struct member, which would be off. */
#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
if (!(server_sni = SSL_CTX_new(TLS_server_method())))
#else
if (!(server_sni = SSL_CTX_new(SSLv23_server_method()))) if (!(server_sni = SSL_CTX_new(SSLv23_server_method())))
#endif
{ {
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring); DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring);
return SSL_TLSEXT_ERR_NOACK; goto bad;
} }
/* Not sure how many of these are actually needed, since SSL object /* Not sure how many of these are actually needed, since SSL object
already exists. Might even need this selfsame callback, for reneg? */ already exists. Might even need this selfsame callback, for reneg? */
SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(server_ctx)); SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(server_ctx));
SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(server_ctx)); SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(server_ctx));
SSL_CTX_set_options(server_sni, SSL_CTX_get_options(server_ctx)); SSL_CTX_set_options(server_sni, SSL_CTX_get_options(server_ctx));
SSL_CTX_set_timeout(server_sni, SSL_CTX_get_timeout(server_ctx)); 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_callback(server_sni, tls_servername_cb);
SSL_CTX_set_tlsext_servername_arg(server_sni, cbinfo); SSL_CTX_set_tlsext_servername_arg(server_sni, cbinfo);
if ( !init_dh(server_sni, cbinfo->dhparam, NULL, &dummy_errstr) if ( !init_dh(server_sni, cbinfo->dhparam, NULL, &dummy_errstr)
|| !init_ecdh(server_sni, NULL, &dummy_errstr) || !init_ecdh(server_sni, NULL, &dummy_errstr)
) )
return SSL_TLSEXT_ERR_NOACK; goto bad;
if ( cbinfo->server_cipher_list
&& !SSL_CTX_set_cipher_list(server_sni, CS cbinfo->server_cipher_list))
goto bad;
if (cbinfo->server_cipher_list)
SSL_CTX_set_cipher_list(server_sni, CS cbinfo->server_cipher_list);
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
if (cbinfo->u_ocsp.server.file) if (cbinfo->u_ocsp.server.file)
{ {
SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb); SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
SSL_CTX_set_tlsext_status_arg(server_sni, cbinfo); SSL_CTX_set_tlsext_status_arg(server_sni, cbinfo);
} }
#endif #endif
if ((rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE, if ((rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE,
verify_callback_server, &dummy_errstr)) != OK) verify_callback_server, &dummy_errstr)) != OK)
return SSL_TLSEXT_ERR_NOACK; goto bad;
/* do this after setup_certs, because this can require the certs for verifying /* do this after setup_certs, because this can require the certs for verifying
OCSP information. */ OCSP information. */
if ((rc = tls_expand_session_files(server_sni, cbinfo, &dummy_errstr)) != OK) if ((rc = tls_expand_session_files(server_sni, cbinfo, &dummy_errstr)) != OK)
return SSL_TLSEXT_ERR_NOACK; goto bad;
DEBUG(D_tls) debug_printf("Switching SSL context.\n"); DEBUG(D_tls) debug_printf("Switching SSL context.\n");
SSL_set_SSL_CTX(s, server_sni); SSL_set_SSL_CTX(s, server_sni);
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
bad: return SSL_TLSEXT_ERR_ALERT_FATAL;
} }
#endif /* EXIM_HAVE_OPENSSL_TLSEXT */ #endif /* EXIM_HAVE_OPENSSL_TLSEXT */
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
/************************************************* /*************************************************
* Callback to handle OCSP Stapling * * Callback to handle OCSP Stapling *
*************************************************/ *************************************************/
/* Called when acting as server during the TLS session setup if the client /* Called when acting as server during the TLS session setup if the client
skipping to change at line 1497 skipping to change at line 1688
else else
cbinfo->u_ocsp.client.verify_store = NULL; cbinfo->u_ocsp.client.verify_store = NULL;
#endif #endif
cbinfo->dhparam = dhparam; cbinfo->dhparam = dhparam;
cbinfo->server_cipher_list = NULL; cbinfo->server_cipher_list = NULL;
cbinfo->host = host; cbinfo->host = host;
#ifndef DISABLE_EVENT #ifndef DISABLE_EVENT
cbinfo->event_action = NULL; cbinfo->event_action = NULL;
#endif #endif
#ifdef EXIM_NEED_OPENSSL_INIT
SSL_load_error_strings(); /* basic set up */ SSL_load_error_strings(); /* basic set up */
OpenSSL_add_ssl_algorithms(); OpenSSL_add_ssl_algorithms();
#endif
#ifdef EXIM_HAVE_SHA256 #ifdef EXIM_HAVE_SHA256
/* SHA256 is becoming ever more popular. This makes sure it gets added to the /* SHA256 is becoming ever more popular. This makes sure it gets added to the
list of available digests. */ list of available digests. */
EVP_add_digest(EVP_sha256()); EVP_add_digest(EVP_sha256());
#endif #endif
/* Create a context. /* Create a context.
The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant
negotiation in the different methods; as far as I can tell, the only negotiation in the different methods; as far as I can tell, the only
*_{server,client}_method which allows negotiation is SSLv23, which exists even *_{server,client}_method which allows negotiation is SSLv23, which exists even
when OpenSSL is built without SSLv2 support. when OpenSSL is built without SSLv2 support.
By disabling with openssl_options, we can let admins re-enable with the By disabling with openssl_options, we can let admins re-enable with the
existing knob. */ existing knob. */
#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
if (!(ctx = SSL_CTX_new(host ? TLS_client_method() : TLS_server_method())))
#else
if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())) ) if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())) )
#endif
return tls_error(US"SSL_CTX_new", host, NULL, errstr); 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 /* 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 order to get the full complement of ciphers to work. It took me roughly a day
of work to discover this by experiment. of work to discover this by experiment.
On systems that have /dev/urandom, SSL may automatically seed itself from On systems that have /dev/urandom, SSL may automatically seed itself from
there. Otherwise, we have to make something up as best we can. Double check there. Otherwise, we have to make something up as best we can. Double check
afterwards. */ afterwards. */
skipping to change at line 1604 skipping to change at line 1801
#ifdef EXIM_HAVE_OPENSSL_TLSEXT #ifdef EXIM_HAVE_OPENSSL_TLSEXT
# ifndef DISABLE_OCSP # ifndef DISABLE_OCSP
if (!(cbinfo->verify_stack = sk_X509_new_null())) if (!(cbinfo->verify_stack = sk_X509_new_null()))
{ {
DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n"); DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n");
return FAIL; return FAIL;
} }
# endif # endif
if (host == NULL) /* server */ if (!host) /* server */
{ {
# ifndef DISABLE_OCSP # ifndef DISABLE_OCSP
/* We check u_ocsp.server.file, not server.response, because we care about if /* 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 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 change the certificate and OCSP file in use between now and the time the
callback is invoked. */ callback is invoked. */
if (cbinfo->u_ocsp.server.file) if (cbinfo->u_ocsp.server.file)
{ {
SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb); SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
SSL_CTX_set_tlsext_status_arg(ctx, cbinfo); SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
skipping to change at line 1670 skipping to change at line 1867
Argument: pointer to an SSL structure for the connection Argument: pointer to an SSL structure for the connection
buffer to use for answer buffer to use for answer
size of buffer size of buffer
pointer to number of bits for cipher pointer to number of bits for cipher
Returns: nothing Returns: nothing
*/ */
static void static void
construct_cipher_name(SSL *ssl, uschar *cipherbuf, int bsize, int *bits) construct_cipher_name(SSL *ssl, uschar *cipherbuf, int bsize, int *bits)
{ {
/* With OpenSSL 1.0.0a, this needs to be const but the documentation doesn't /* With OpenSSL 1.0.0a, 'c' needs to be const but the documentation doesn't
yet reflect that. It should be a safe change anyway, even 0.9.8 versions have yet reflect that. It should be a safe change anyway, even 0.9.8 versions have
the accessor functions use const in the prototype. */ the accessor functions use const in the prototype. */
const SSL_CIPHER *c;
const uschar *ver;
ver = (const uschar *)SSL_get_version(ssl); const uschar * ver = CUS SSL_get_version(ssl);
const SSL_CIPHER * c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
SSL_CIPHER_get_bits(c, bits); SSL_CIPHER_get_bits(c, bits);
string_format(cipherbuf, bsize, "%s:%s:%u", ver, string_format(cipherbuf, bsize, "%s:%s:%u", ver,
SSL_CIPHER_get_name(c), *bits); SSL_CIPHER_get_name(c), *bits);
DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf); DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf);
} }
static void static void
peer_cert(SSL * ssl, tls_support * tlsp, uschar * peerdn, unsigned bsize) peer_cert(SSL * ssl, tls_support * tlsp, uschar * peerdn, unsigned siz)
{ {
/*XXX we might consider a list-of-certs variable for the cert chain. /*XXX we might consider a list-of-certs variable for the cert chain.
SSL_get_peer_cert_chain(SSL*). We'd need a new variable type and support SSL_get_peer_cert_chain(SSL*). We'd need a new variable type and support
in list-handling functions, also consider the difference between the entire in list-handling functions, also consider the difference between the entire
chain and the elements sent by the peer. */ chain and the elements sent by the peer. */
tlsp->peerdn = NULL;
/* Will have already noted peercert on a verify fail; possibly not the leaf */ /* Will have already noted peercert on a verify fail; possibly not the leaf */
if (!tlsp->peercert) if (!tlsp->peercert)
tlsp->peercert = SSL_get_peer_certificate(ssl); tlsp->peercert = SSL_get_peer_certificate(ssl);
/* Beware anonymous ciphers which lead to server_cert being NULL */ /* Beware anonymous ciphers which lead to server_cert being NULL */
if (tlsp->peercert) if (tlsp->peercert)
{ if (!X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, siz))
X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, bsize); { DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); }
peerdn[bsize-1] = '\0'; else
tlsp->peerdn = peerdn; /*XXX a static buffer... */ {
} peerdn[siz-1] = '\0';
else tlsp->peerdn = peerdn; /*XXX a static buffer... */
tlsp->peerdn = NULL; }
} }
/************************************************* /*************************************************
* Set up for verifying certificates * * Set up for verifying certificates *
*************************************************/ *************************************************/
#ifndef DISABLE_OCSP
/* Load certs from file, return TRUE on success */ /* Load certs from file, return TRUE on success */
static BOOL static BOOL
chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack) chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack)
{ {
BIO * bp; BIO * bp;
X509 * x; X509 * x;
while (sk_X509_num(verify_stack) > 0) while (sk_X509_num(verify_stack) > 0)
X509_free(sk_X509_pop(verify_stack)); X509_free(sk_X509_pop(verify_stack));
if (!(bp = BIO_new_file(CS file, "r"))) return FALSE; if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL))) while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)))
sk_X509_push(verify_stack, x); sk_X509_push(verify_stack, x);
BIO_free(bp); BIO_free(bp);
return TRUE; return TRUE;
} }
#endif
/* Called by both client and server startup; on the server possibly /* Called by both client and server startup; on the server possibly
repeated after a Server Name Indication. repeated after a Server Name Indication.
Arguments: Arguments:
sctx SSL_CTX* to initialise sctx SSL_CTX* to initialise
certs certs file or NULL certs certs file or NULL
crl CRL file or NULL crl CRL file or NULL
host NULL in a server; the remote host in a client host NULL in a server; the remote host in a client
optional TRUE if called from a server for a host in tls_try_verify_hosts; optional TRUE if called from a server for a host in tls_try_verify_hosts;
skipping to change at line 1887 skipping to change at line 2086
X509_STORE_set_flags(cvstore, X509_STORE_set_flags(cvstore,
X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
} }
} }
#endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ #endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */
/* If verification is optional, don't fail if no certificate */ /* If verification is optional, don't fail if no certificate */
SSL_CTX_set_verify(sctx, SSL_CTX_set_verify(sctx,
SSL_VERIFY_PEER | (optional? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT), SSL_VERIFY_PEER | (optional ? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
cert_vfy_cb); cert_vfy_cb);
} }
return OK; return OK;
} }
/************************************************* /*************************************************
* Start a TLS session in a server * * Start a TLS session in a server *
*************************************************/ *************************************************/
skipping to change at line 1923 skipping to change at line 2122
tls_server_start(const uschar * require_ciphers, uschar ** errstr) tls_server_start(const uschar * require_ciphers, uschar ** errstr)
{ {
int rc; int rc;
uschar * expciphers; uschar * expciphers;
tls_ext_ctx_cb * cbinfo; tls_ext_ctx_cb * cbinfo;
static uschar peerdn[256]; static uschar peerdn[256];
static uschar cipherbuf[256]; static uschar cipherbuf[256];
/* Check for previous activation */ /* Check for previous activation */
if (tls_in.active >= 0) if (tls_in.active.sock >= 0)
{ {
tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr); tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr);
smtp_printf("554 Already in TLS\r\n", FALSE); smtp_printf("554 Already in TLS\r\n", FALSE);
return FAIL; return FAIL;
} }
/* Initialize the SSL library. If it fails, it will already have logged /* Initialize the SSL library. If it fails, it will already have logged
the error. */ the error. */
rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey, rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey,
skipping to change at line 1947 skipping to change at line 2146
NULL, &server_static_cbinfo, errstr); NULL, &server_static_cbinfo, errstr);
if (rc != OK) return rc; if (rc != OK) return rc;
cbinfo = server_static_cbinfo; cbinfo = server_static_cbinfo;
if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers, errstr) ) if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers, errstr) )
return FAIL; return FAIL;
/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they /* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
were historically separated by underscores. So that I can use either form in my 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. tests, and also for general convenience, we turn underscores into hyphens here.
XXX SSL_CTX_set_cipher_list() is replaced by SSL_CTX_set_ciphersuites()
for TLS 1.3 . Since we do not call it at present we get the default list:
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
*/ */
if (expciphers) if (expciphers)
{ {
uschar * s = expciphers; uschar * s = expciphers;
while (*s != 0) { if (*s == '_') *s = '-'; s++; } while (*s != 0) { if (*s == '_') *s = '-'; s++; }
DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers); DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
if (!SSL_CTX_set_cipher_list(server_ctx, CS expciphers)) if (!SSL_CTX_set_cipher_list(server_ctx, CS expciphers))
return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr); return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
cbinfo->server_cipher_list = expciphers; cbinfo->server_cipher_list = expciphers;
skipping to change at line 1971 skipping to change at line 2174
tls_in.certificate_verified = FALSE; tls_in.certificate_verified = FALSE;
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
tls_in.dane_verified = FALSE; tls_in.dane_verified = FALSE;
#endif #endif
server_verify_callback_called = FALSE; server_verify_callback_called = FALSE;
if (verify_check_host(&tls_verify_hosts) == OK) if (verify_check_host(&tls_verify_hosts) == OK)
{ {
rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL, rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
FALSE, verify_callback_server, errstr); FALSE, verify_callback_server, errstr);
if (rc != OK) return rc; if (rc != OK) return rc;
server_verify_optional = FALSE; server_verify_optional = FALSE;
} }
else if (verify_check_host(&tls_try_verify_hosts) == OK) else if (verify_check_host(&tls_try_verify_hosts) == OK)
{ {
rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL, rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
TRUE, verify_callback_server, errstr); TRUE, verify_callback_server, errstr);
if (rc != OK) return rc; if (rc != OK) return rc;
server_verify_optional = TRUE; server_verify_optional = TRUE;
} }
/* Prepare for new connection */ /* Prepare for new connection */
if (!(server_ssl = SSL_new(server_ctx))) if (!(server_ssl = SSL_new(server_ctx)))
return tls_error(US"SSL_new", NULL, NULL, errstr); return tls_error(US"SSL_new", NULL, NULL, errstr);
/* Warning: we used to SSL_clear(ssl) here, it was removed. /* Warning: we used to SSL_clear(ssl) here, it was removed.
skipping to change at line 2024 skipping to change at line 2227
/* Now negotiate the TLS session. We put our own timer on it, since it seems /* Now negotiate the TLS session. We put our own timer on it, since it seems
that the OpenSSL library doesn't. */ that the OpenSSL library doesn't. */
SSL_set_wfd(server_ssl, fileno(smtp_out)); SSL_set_wfd(server_ssl, fileno(smtp_out));
SSL_set_rfd(server_ssl, fileno(smtp_in)); SSL_set_rfd(server_ssl, fileno(smtp_in));
SSL_set_accept_state(server_ssl); SSL_set_accept_state(server_ssl);
DEBUG(D_tls) debug_printf("Calling SSL_accept\n"); DEBUG(D_tls) debug_printf("Calling SSL_accept\n");
sigalrm_seen = FALSE; sigalrm_seen = FALSE;
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
rc = SSL_accept(server_ssl); rc = SSL_accept(server_ssl);
alarm(0); ALARM_CLR(0);
if (rc <= 0) if (rc <= 0)
{ {
(void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, er rstr); (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, er rstr);
return FAIL; return FAIL;
} }
DEBUG(D_tls) debug_printf("SSL_accept was successful\n"); DEBUG(D_tls) debug_printf("SSL_accept was successful\n");
ERR_clear_error(); /* Even success can leave errors in the stack. Seen with
anon-authentication ciphersuite negociated. */
/* TLS has been set up. Adjust the input functions to read via TLS, /* TLS has been set up. Adjust the input functions to read via TLS,
and initialize things. */ and initialize things. */
peer_cert(server_ssl, &tls_in, peerdn, sizeof(peerdn)); peer_cert(server_ssl, &tls_in, peerdn, sizeof(peerdn));
construct_cipher_name(server_ssl, cipherbuf, sizeof(cipherbuf), &tls_in.bits); construct_cipher_name(server_ssl, cipherbuf, sizeof(cipherbuf), &tls_in.bits);
tls_in.cipher = cipherbuf; tls_in.cipher = cipherbuf;
DEBUG(D_tls) DEBUG(D_tls)
skipping to change at line 2074 skipping to change at line 2279
ssl_xfer_eof = ssl_xfer_error = FALSE; ssl_xfer_eof = ssl_xfer_error = FALSE;
receive_getc = tls_getc; receive_getc = tls_getc;
receive_getbuf = tls_getbuf; receive_getbuf = tls_getbuf;
receive_get_cache = tls_get_cache; receive_get_cache = tls_get_cache;
receive_ungetc = tls_ungetc; receive_ungetc = tls_ungetc;
receive_feof = tls_feof; receive_feof = tls_feof;
receive_ferror = tls_ferror; receive_ferror = tls_ferror;
receive_smtp_buffered = tls_smtp_buffered; receive_smtp_buffered = tls_smtp_buffered;
tls_in.active = fileno(smtp_out); tls_in.active.sock = fileno(smtp_out);
tls_in.active.tls_ctx = NULL; /* not using explicit ctx for server-side */
return OK; return OK;
} }
static int static int
tls_client_basic_ctx_init(SSL_CTX * ctx, 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) uschar ** errstr)
{ {
int rc; int rc;
/* stick to the old behaviour for compatibility if tls_verify_certificates is /* stick to the old behaviour for compatibility if tls_verify_certificates is
set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only
the specified host patterns if one of them is defined */ the specified host patterns if one of them is defined */
if ( ( !ob->tls_verify_hosts if ( ( !ob->tls_verify_hosts
&& (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts) && (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts)
) )
|| (verify_check_given_host(&ob->tls_verify_hosts, host) == OK) || verify_check_given_host(CUSS &ob->tls_verify_hosts, host) == OK
) )
client_verify_optional = FALSE; client_verify_optional = FALSE;
else if (verify_check_given_host(&ob->tls_try_verify_hosts, host) == OK) else if (verify_check_given_host(CUSS &ob->tls_try_verify_hosts, host) == OK)
client_verify_optional = TRUE; client_verify_optional = TRUE;
else else
return OK; return OK;
if ((rc = setup_certs(ctx, ob->tls_verify_certificates, if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
ob->tls_crl, host, client_verify_optional, verify_callback_client, ob->tls_crl, host, client_verify_optional, verify_callback_client,
errstr)) != OK) errstr)) != OK)
return rc; return rc;
if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK) if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
{ {
cbinfo->verify_cert_hostnames = cbinfo->verify_cert_hostnames =
#ifdef SUPPORT_I18N #ifdef SUPPORT_I18N
string_domain_utf8_to_alabel(host->name, NULL); string_domain_utf8_to_alabel(host->name, NULL);
#else #else
host->name; host->name;
#endif #endif
DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
cbinfo->verify_cert_hostnames); cbinfo->verify_cert_hostnames);
} }
skipping to change at line 2133 skipping to change at line 2339
dns_scan dnss; dns_scan dnss;
const char * hostnames[2] = { CS host->name, NULL }; const char * hostnames[2] = { CS host->name, NULL };
int found = 0; int found = 0;
if (DANESSL_init(ssl, NULL, hostnames) != 1) if (DANESSL_init(ssl, NULL, hostnames) != 1)
return tls_error(US"hostnames load", host, NULL, errstr); return tls_error(US"hostnames load", host, NULL, errstr);
for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
rr; rr;
rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
) if (rr->type == T_TLSA) ) if (rr->type == T_TLSA && rr->size > 3)
{ {
const uschar * p = rr->data; const uschar * p = rr->data;
uint8_t usage, selector, mtype; uint8_t usage, selector, mtype;
const char * mdname; const char * mdname;
usage = *p++; usage = *p++;
/* Only DANE-TA(2) and DANE-EE(3) are supported */ /* Only DANE-TA(2) and DANE-EE(3) are supported */
if (usage != 2 && usage != 3) continue; if (usage != 2 && usage != 3) continue;
skipping to change at line 2183 skipping to change at line 2389
#endif /*SUPPORT_DANE*/ #endif /*SUPPORT_DANE*/
/************************************************* /*************************************************
* Start a TLS session in a client * * Start a TLS session in a client *
*************************************************/ *************************************************/
/* Called from the smtp transport after STARTTLS has been accepted. /* Called from the smtp transport after STARTTLS has been accepted.
Argument: Argument:
fd the fd of the connection fd the fd of the connection
host connected host (for messages) host connected host (for messages and option-tests)
addr the first address addr the first address (for some randomness; can be NULL)
tb transport (always smtp) tb transport (always smtp)
tlsa_dnsa tlsa lookup, if DANE, else null tlsa_dnsa tlsa lookup, if DANE, else null
tlsp record details of channel configuration here; must be non-NULL
errstr error string pointer errstr error string pointer
Returns: OK on success Returns: Pointer to TLS session context, or NULL on error
FAIL otherwise - note that tls_error() will not give DEFER
because this is not a server
*/ */
int void *
tls_client_start(int fd, host_item *host, address_item *addr, tls_client_start(int fd, host_item *host, address_item *addr,
transport_instance * tb, transport_instance * tb,
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
dns_answer * tlsa_dnsa, dns_answer * tlsa_dnsa,
#endif #endif
uschar ** errstr) tls_support * tlsp, uschar ** errstr)
{ {
smtp_transport_options_block * ob = smtp_transport_options_block * ob = tb
(smtp_transport_options_block *)tb->options_block; ? (smtp_transport_options_block *)tb->options_block
: &smtp_transport_option_defaults;
exim_openssl_client_tls_ctx * exim_client_ctx;
static uschar peerdn[256]; static uschar peerdn[256];
uschar * expciphers; uschar * expciphers;
int rc; int rc;
static uschar cipherbuf[256]; static uschar cipherbuf[256];
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
BOOL request_ocsp = FALSE; BOOL request_ocsp = FALSE;
BOOL require_ocsp = FALSE; BOOL require_ocsp = FALSE;
#endif #endif
rc = store_pool;
store_pool = POOL_PERM;
exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx));
store_pool = rc;
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
tls_out.tlsa_usage = 0; tlsp->tlsa_usage = 0;
#endif #endif
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
{ {
# ifdef SUPPORT_DANE # ifdef SUPPORT_DANE
if ( tlsa_dnsa if ( tlsa_dnsa
&& ob->hosts_request_ocsp[0] == '*' && ob->hosts_request_ocsp[0] == '*'
&& ob->hosts_request_ocsp[1] == '\0' && ob->hosts_request_ocsp[1] == '\0'
) )
{ {
/* Unchanged from default. Use a safer one under DANE */ /* Unchanged from default. Use a safer one under DANE */
request_ocsp = TRUE; request_ocsp = TRUE;
ob->hosts_request_ocsp = US"${if or { {= {0}{$tls_out_tlsa_usage}} " ob->hosts_request_ocsp = US"${if or { {= {0}{$tls_out_tlsa_usage}} "
" {= {4}{$tls_out_tlsa_usage}} } " " {= {4}{$tls_out_tlsa_usage}} } "
" {*}{}}"; " {*}{}}";
} }
# endif # endif
if ((require_ocsp = if ((require_ocsp =
verify_check_given_host(&ob->hosts_require_ocsp, host) == OK)) verify_check_given_host(CUSS &ob->hosts_require_ocsp, host) == OK))
request_ocsp = TRUE; request_ocsp = TRUE;
else else
# ifdef SUPPORT_DANE # ifdef SUPPORT_DANE
if (!request_ocsp) if (!request_ocsp)
# endif # endif
request_ocsp = request_ocsp =
verify_check_given_host(&ob->hosts_request_ocsp, host) == OK; verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK;
} }
#endif #endif
rc = tls_init(&client_ctx, host, NULL, rc = tls_init(&exim_client_ctx->ctx, host, NULL,
ob->tls_certificate, ob->tls_privatekey, ob->tls_certificate, ob->tls_privatekey,
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
(void *)(long)request_ocsp, (void *)(long)request_ocsp,
#endif #endif
addr, &client_static_cbinfo, errstr); addr, &client_static_cbinfo, errstr);
if (rc != OK) return rc; if (rc != OK) return NULL;
tls_out.certificate_verified = FALSE; tlsp->certificate_verified = FALSE;
client_verify_callback_called = FALSE; client_verify_callback_called = FALSE;
expciphers = NULL; expciphers = NULL;
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
if (tlsa_dnsa) if (tlsa_dnsa)
{ {
/* We fall back to tls_require_ciphers if unset, empty or forced failure, but /* We fall back to tls_require_ciphers if unset, empty or forced failure, but
other failures should be treated as problems. */ other failures should be treated as problems. */
if (ob->dane_require_tls_ciphers && if (ob->dane_require_tls_ciphers &&
!expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers", !expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers",
&expciphers, errstr)) &expciphers, errstr))
return FAIL; return NULL;
if (expciphers && *expciphers == '\0') if (expciphers && *expciphers == '\0')
expciphers = NULL; expciphers = NULL;
} }
#endif #endif
if (!expciphers && if (!expciphers &&
!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers", !expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
&expciphers, errstr)) &expciphers, errstr))
return FAIL; return NULL;
/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they /* 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 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. */ also for general convenience, we turn underscores into hyphens here. */
if (expciphers) if (expciphers)
{ {
uschar *s = expciphers; uschar *s = expciphers;
while (*s) { if (*s == '_') *s = '-'; s++; } while (*s) { if (*s == '_') *s = '-'; s++; }
DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers); DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
if (!SSL_CTX_set_cipher_list(client_ctx, CS expciphers)) if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers))
return tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr); {
tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr);
return NULL;
}
} }
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
if (tlsa_dnsa) if (tlsa_dnsa)
{ {
SSL_CTX_set_verify(client_ctx, SSL_CTX_set_verify(exim_client_ctx->ctx,
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
verify_callback_client_dane); verify_callback_client_dane);
if (!DANESSL_library_init()) if (!DANESSL_library_init())
return tls_error(US"library init", host, NULL, errstr); {
if (DANESSL_CTX_init(client_ctx) <= 0) tls_error(US"library init", host, NULL, errstr);
return tls_error(US"context init", host, NULL, errstr); return NULL;
}
if (DANESSL_CTX_init(exim_client_ctx->ctx) <= 0)
{
tls_error(US"context init", host, NULL, errstr);
return NULL;
}
} }
else else
#endif #endif
if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob, if (tls_client_basic_ctx_init(exim_client_ctx->ctx, host, ob,
client_static_cbinfo, errstr)) != OK) client_static_cbinfo, errstr) != OK)
return rc; return NULL;
if ((client_ssl = SSL_new(client_ctx)) == NULL) if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
return tls_error(US"SSL_new", host, NULL, errstr); {
SSL_set_session_id_context(client_ssl, sid_ctx, Ustrlen(sid_ctx)); tls_error(US"SSL_new", host, NULL, errstr);
SSL_set_fd(client_ssl, fd); return NULL;
SSL_set_connect_state(client_ssl); }
SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
SSL_set_fd(exim_client_ctx->ssl, fd);
SSL_set_connect_state(exim_client_ctx->ssl);
if (ob->tls_sni) if (ob->tls_sni)
{ {
if (!expand_check(ob->tls_sni, US"tls_sni", &tls_out.sni, errstr)) if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr))
return FAIL; return NULL;
if (!tls_out.sni) if (!tlsp->sni)
{ {
DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n"); DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n");
} }
else if (!Ustrlen(tls_out.sni)) else if (!Ustrlen(tlsp->sni))
tls_out.sni = NULL; tlsp->sni = NULL;
else else
{ {
#ifdef EXIM_HAVE_OPENSSL_TLSEXT #ifdef EXIM_HAVE_OPENSSL_TLSEXT
DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_out.sni); DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tlsp->sni);
SSL_set_tlsext_host_name(client_ssl, tls_out.sni); SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni);
#else #else
log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; igno ring \"%s\"\n", log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; igno ring \"%s\"\n",
tls_out.sni); tlsp->sni);
#endif #endif
} }
} }
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
if (tlsa_dnsa) if (tlsa_dnsa)
if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa, errstr)) != OK) if (dane_tlsa_load(exim_client_ctx->ssl, host, tlsa_dnsa, errstr) != OK)
return rc; return NULL;
#endif #endif
#ifndef DISABLE_OCSP #ifndef DISABLE_OCSP
/* Request certificate status at connection-time. If the server /* Request certificate status at connection-time. If the server
does OCSP stapling we will get the callback (set in tls_init()) */ does OCSP stapling we will get the callback (set in tls_init()) */
# ifdef SUPPORT_DANE # ifdef SUPPORT_DANE
if (request_ocsp) if (request_ocsp)
{ {
const uschar * s; const uschar * s;
if ( ((s = ob->hosts_require_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage")) if ( ((s = ob->hosts_require_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage"))
|| ((s = ob->hosts_request_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage")) || ((s = ob->hosts_request_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage"))
) )
{ /* Re-eval now $tls_out_tlsa_usage is populated. If { /* Re-eval now $tls_out_tlsa_usage is populated. If
this means we avoid the OCSP request, we wasted the setup this means we avoid the OCSP request, we wasted the setup
cost in tls_init(). */ cost in tls_init(). */
require_ocsp = verify_check_given_host(&ob->hosts_require_ocsp, host) == OK; require_ocsp = verify_check_given_host(CUSS &ob->hosts_require_ocsp, host) = = OK;
request_ocsp = require_ocsp request_ocsp = require_ocsp
|| verify_check_given_host(&ob->hosts_request_ocsp, host) == OK; || verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK;
} }
} }
# endif # endif
if (request_ocsp) if (request_ocsp)
{ {
SSL_set_tlsext_status_type(client_ssl, TLSEXT_STATUSTYPE_ocsp); SSL_set_tlsext_status_type(exim_client_ctx->ssl, TLSEXT_STATUSTYPE_ocsp);
client_static_cbinfo->u_ocsp.client.verify_required = require_ocsp; client_static_cbinfo->u_ocsp.client.verify_required = require_ocsp;
tls_out.ocsp = OCSP_NOT_RESP; tlsp->ocsp = OCSP_NOT_RESP;
} }
#endif #endif
#ifndef DISABLE_EVENT #ifndef DISABLE_EVENT
client_static_cbinfo->event_action = tb->event_action; client_static_cbinfo->event_action = tb ? tb->event_action : NULL;
#endif #endif
/* There doesn't seem to be a built-in timeout on connection. */ /* There doesn't seem to be a built-in timeout on connection. */
DEBUG(D_tls) debug_printf("Calling SSL_connect\n"); DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
sigalrm_seen = FALSE; sigalrm_seen = FALSE;
alarm(ob->command_timeout); ALARM(ob->command_timeout);
rc = SSL_connect(client_ssl); rc = SSL_connect(exim_client_ctx->ssl);
alarm(0); ALARM_CLR(0);
#ifdef SUPPORT_DANE #ifdef SUPPORT_DANE
if (tlsa_dnsa) if (tlsa_dnsa)
DANESSL_cleanup(client_ssl); DANESSL_cleanup(exim_client_ctx->ssl);
#endif #endif
if (rc <= 0) if (rc <= 0)
return tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL, {
errstr); tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL, errstr);
return NULL;
}
DEBUG(D_tls) debug_printf("SSL_connect succeeded\n"); DEBUG(D_tls) debug_printf("SSL_connect succeeded\n");
peer_cert(client_ssl, &tls_out, peerdn, sizeof(peerdn)); peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
construct_cipher_name(client_ssl, cipherbuf, sizeof(cipherbuf), &tls_out.bits); construct_cipher_name(exim_client_ctx->ssl, cipherbuf, sizeof(cipherbuf), &tlsp-
tls_out.cipher = cipherbuf; >bits);
tlsp->cipher = cipherbuf;
/* Record the certificate we presented */ /* Record the certificate we presented */
{ {
X509 * crt = SSL_get_certificate(client_ssl); X509 * crt = SSL_get_certificate(exim_client_ctx->ssl);
tls_out.ourcert = crt ? X509_dup(crt) : NULL; tlsp->ourcert = crt ? X509_dup(crt) : NULL;
} }
tls_out.active = fd; tlsp->active.sock = fd;
return OK; tlsp->active.tls_ctx = exim_client_ctx;
return exim_client_ctx;
} }
static BOOL static BOOL
tls_refill(unsigned lim) tls_refill(unsigned lim)
{ {
int error; int error;
int inbytes; int inbytes;
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl, DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
ssl_xfer_buffer, ssl_xfer_buffer_size); ssl_xfer_buffer, ssl_xfer_buffer_size);
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer, inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
MIN(ssl_xfer_buffer_size, lim)); MIN(ssl_xfer_buffer_size, lim));
error = SSL_get_error(server_ssl, inbytes); error = SSL_get_error(server_ssl, inbytes);
alarm(0); if (smtp_receive_timeout > 0) ALARM_CLR(0);
if (had_command_timeout) /* set by signal handler */
smtp_command_timeout_exit(); /* does not return */
if (had_command_sigterm)
smtp_command_sigterm_exit();
if (had_data_timeout)
smtp_data_timeout_exit();
if (had_data_sigint)
smtp_data_sigint_exit();
/* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been /* 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 closed down, not that the socket itself has been closed down. Revert to
non-SSL handling. */ non-SSL handling. */
if (error == SSL_ERROR_ZERO_RETURN) switch(error)
{ {
DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); case SSL_ERROR_NONE:
break;
receive_getc = smtp_getc; case SSL_ERROR_ZERO_RETURN:
receive_getbuf = smtp_getbuf; DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
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) receive_getc = smtp_getc;
SSL_shutdown(server_ssl); 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;
sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free); if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
SSL_free(server_ssl); SSL_shutdown(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; #ifndef DISABLE_OCSP
} sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
server_static_cbinfo->verify_stack = NULL;
#endif
SSL_free(server_ssl);
SSL_CTX_free(server_ctx);
server_ctx = NULL;
server_ssl = NULL;
tls_in.active.sock = -1;
tls_in.active.tls_ctx = NULL;
tls_in.bits = 0;
tls_in.cipher = NULL;
tls_in.peerdn = NULL;
tls_in.sni = NULL;
/* Handle genuine errors */ return FALSE;
else if (error == SSL_ERROR_SSL) /* Handle genuine errors */
{ case SSL_ERROR_SSL:
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring); log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
ssl_xfer_error = TRUE; ssl_xfer_error = TRUE;
return FALSE; return FALSE;
}
else if (error != SSL_ERROR_NONE) default:
{ DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
DEBUG(D_tls) debug_printf("Got SSL error %d\n", error); DEBUG(D_tls) if (error == SSL_ERROR_SYSCALL)
ssl_xfer_error = TRUE; debug_printf(" - syscall %s\n", strerror(errno));
return FALSE; ssl_xfer_error = TRUE;
return FALSE;
} }
#ifndef DISABLE_DKIM #ifndef DISABLE_DKIM
dkim_exim_verify_feed(ssl_xfer_buffer, inbytes); dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
#endif #endif
ssl_xfer_buffer_hwm = inbytes; ssl_xfer_buffer_hwm = inbytes;
ssl_xfer_buffer_lwm = 0; ssl_xfer_buffer_lwm = 0;
return TRUE; return TRUE;
} }
skipping to change at line 2552 skipping to change at line 2792
{ {
return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm || SSL_pending(server_ssl) > 0; return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm || SSL_pending(server_ssl) > 0;
} }
/************************************************* /*************************************************
* Read bytes from TLS channel * * Read bytes from TLS channel *
*************************************************/ *************************************************/
/* /*
Arguments: Arguments:
ct_ctx client context pointer, or NULL for the one global server context
buff buffer of data buff buffer of data
len size of buffer len size of buffer
Returns: the number of bytes read Returns: the number of bytes read
-1 after a failed read -1 after a failed read, including EOF
Only used by the client-side TLS. Only used by the client-side TLS.
*/ */
int int
tls_read(BOOL is_server, uschar *buff, size_t len) tls_read(void * ct_ctx, uschar *buff, size_t len)
{ {
SSL *ssl = is_server ? server_ssl : client_ssl; SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
int inbytes; int inbytes;
int error; int error;
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
buff, (unsigned int)len); buff, (unsigned int)len);
inbytes = SSL_read(ssl, CS buff, len); inbytes = SSL_read(ssl, CS buff, len);
error = SSL_get_error(ssl, inbytes); error = SSL_get_error(ssl, inbytes);
if (error == SSL_ERROR_ZERO_RETURN) if (error == SSL_ERROR_ZERO_RETURN)
skipping to change at line 2591 skipping to change at line 2832
return inbytes; return inbytes;
} }
/************************************************* /*************************************************
* Write bytes down TLS channel * * Write bytes down TLS channel *
*************************************************/ *************************************************/
/* /*
Arguments: Arguments:
is_server channel specifier ct_ctx client context pointer, or NULL for the one global server context
buff buffer of data buff buffer of data
len number of bytes len number of bytes
more further data expected soon more further data expected soon
Returns: the number of bytes after a successful write, Returns: the number of bytes after a successful write,
-1 after a failed write -1 after a failed write
Used by both server-side and client-side TLS. Used by both server-side and client-side TLS.
*/ */
int int
tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more) tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
{ {
int outbytes, error, left; int outbytes, error, left;
SSL *ssl = is_server ? server_ssl : client_ssl; SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
static gstring * corked = NULL; static gstring * corked = NULL;
DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__, DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
buff, (unsigned long)len, more ? ", more" : ""); buff, (unsigned long)len, more ? ", more" : "");
/* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when /* 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 "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 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. */ for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */
/*XXX + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there'
s
a store reset there. */
if (is_server && (more || corked)) if (!ct_ctx && (more || corked))
{ {
#ifdef EXPERIMENTAL_PIPE_CONNECT
int save_pool = store_pool;
store_pool = POOL_PERM;
#endif
corked = string_catn(corked, buff, len); corked = string_catn(corked, buff, len);
#ifdef EXPERIMENTAL_PIPE_CONNECT
store_pool = save_pool;
#endif
if (more) if (more)
return len; return len;
buff = CUS corked->s; buff = CUS corked->s;
len = corked->ptr; len = corked->ptr;
corked = NULL; corked = NULL;
} }
for (left = len; left > 0;) for (left = len; left > 0;)
{ {
DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left); DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left);
outbytes = SSL_write(ssl, CS buff, left); outbytes = SSL_write(ssl, CS buff, left);
error = SSL_get_error(ssl, outbytes); error = SSL_get_error(ssl, outbytes);
DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error); DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error);
switch (error) switch (error)
{ {
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring); log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring);
return -1; return -1;
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
left -= outbytes; left -= outbytes;
buff += outbytes; buff += outbytes;
break; break;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
log_write(0, LOG_MAIN, "SSL channel closed on write"); log_write(0, LOG_MAIN, "SSL channel closed on write");
skipping to change at line 2672 skipping to change at line 2925
/************************************************* /*************************************************
* Close down a TLS session * * Close down a TLS session *
*************************************************/ *************************************************/
/* This is also called from within a delivery subprocess forked from the /* This is also called from within a delivery subprocess forked from the
daemon, to shut down the TLS library, without actually doing a shutdown (which daemon, to shut down the TLS library, without actually doing a shutdown (which
would tamper with the SSL session in the parent process). would tamper with the SSL session in the parent process).
Arguments: Arguments:
ct_ctx client TLS context pointer, or NULL for the one global server con text
shutdown 1 if TLS close-alert is to be sent, shutdown 1 if TLS close-alert is to be sent,
2 if also response to be waited for 2 if also response to be waited for
Returns: nothing Returns: nothing
Used by both server-side and client-side TLS. Used by both server-side and client-side TLS.
*/ */
void void
tls_close(BOOL is_server, int shutdown) tls_close(void * ct_ctx, int shutdown)
{ {
SSL_CTX **ctxp = is_server ? &server_ctx : &client_ctx; exim_openssl_client_tls_ctx * o_ctx = ct_ctx;
SSL **sslp = is_server ? &server_ssl : &client_ssl; SSL_CTX **ctxp = o_ctx ? &o_ctx->ctx : &server_ctx;
int *fdp = is_server ? &tls_in.active : &tls_out.active; SSL **sslp = o_ctx ? &o_ctx->ssl : &server_ssl;
int *fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
if (*fdp < 0) return; /* TLS was not active */ if (*fdp < 0) return; /* TLS was not active */
if (shutdown) if (shutdown)
{ {
int rc; int rc;
DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
shutdown > 1 ? " (with response-wait)" : ""); shutdown > 1 ? " (with response-wait)" : "");
if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */
&& shutdown > 1) && shutdown > 1)
{ {
alarm(2); ALARM(2);
rc = SSL_shutdown(*sslp); /* wait for response */ rc = SSL_shutdown(*sslp); /* wait for response */
alarm(0); ALARM_CLR(0);
} }
if (rc < 0) DEBUG(D_tls) if (rc < 0) DEBUG(D_tls)
{ {
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
debug_printf("SSL_shutdown: %s\n", ssl_errstring); debug_printf("SSL_shutdown: %s\n", ssl_errstring);
} }
} }
if (is_server) #ifndef DISABLE_OCSP
if (!o_ctx) /* server side */
{ {
sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free); sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
server_static_cbinfo->verify_stack = NULL; server_static_cbinfo->verify_stack = NULL;
} }
#endif
SSL_CTX_free(*ctxp); SSL_CTX_free(*ctxp);
SSL_free(*sslp); SSL_free(*sslp);
*ctxp = NULL; *ctxp = NULL;
*sslp = NULL; *sslp = NULL;
*fdp = -1; *fdp = -1;
} }
/************************************************* /*************************************************
* Let tls_require_ciphers be checked at startup * * Let tls_require_ciphers be checked at startup *
skipping to change at line 2742 skipping to change at line 2999
uschar * uschar *
tls_validate_require_cipher(void) tls_validate_require_cipher(void)
{ {
SSL_CTX *ctx; SSL_CTX *ctx;
uschar *s, *expciphers, *err; uschar *s, *expciphers, *err;
/* this duplicates from tls_init(), we need a better "init just global /* this duplicates from tls_init(), we need a better "init just global
state, for no specific purpose" singleton function of our own */ state, for no specific purpose" singleton function of our own */
#ifdef EXIM_NEED_OPENSSL_INIT
SSL_load_error_strings(); SSL_load_error_strings();
OpenSSL_add_ssl_algorithms(); OpenSSL_add_ssl_algorithms();
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
/* SHA256 is becoming ever more popular. This makes sure it gets added to the /* SHA256 is becoming ever more popular. This makes sure it gets added to the
list of available digests. */ list of available digests. */
EVP_add_digest(EVP_sha256()); EVP_add_digest(EVP_sha256());
#endif #endif
if (!(tls_require_ciphers && *tls_require_ciphers)) if (!(tls_require_ciphers && *tls_require_ciphers))
return NULL; return NULL;
if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers,
skipping to change at line 2766 skipping to change at line 3025
if (!(expciphers && *expciphers)) if (!(expciphers && *expciphers))
return NULL; return NULL;
/* normalisation ripped from above */ /* normalisation ripped from above */
s = expciphers; s = expciphers;
while (*s != 0) { if (*s == '_') *s = '-'; s++; } while (*s != 0) { if (*s == '_') *s = '-'; s++; }
err = NULL; err = NULL;
ctx = SSL_CTX_new(SSLv23_server_method()); #ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
if (!ctx) if (!(ctx = SSL_CTX_new(TLS_server_method())))
#else
if (!(ctx = SSL_CTX_new(SSLv23_server_method())))
#endif
{ {
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
return string_sprintf("SSL_CTX_new() failed: %s", ssl_errstring); return string_sprintf("SSL_CTX_new() failed: %s", ssl_errstring);
} }
DEBUG(D_tls) DEBUG(D_tls)
debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers); debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers);
if (!SSL_CTX_set_cipher_list(ctx, CS expciphers)) if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
{ {
ERR_error_string(ERR_get_error(), ssl_errstring); ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed: %s", err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed: %s",
expciphers, ssl_errstring); expciphers, ssl_errstring);
} }
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
return err; return err;
} }
/************************************************* /*************************************************
skipping to change at line 2923 skipping to change at line 3185
*************************************************/ *************************************************/
/* Parse one option for tls_openssl_options_parse below /* Parse one option for tls_openssl_options_parse below
Arguments: Arguments:
name one option name name one option name
value place to store a value for it value place to store a value for it
Returns success or failure in parsing Returns success or failure in parsing
*/ */
struct exim_openssl_option {
uschar *name;
long value;
};
/* We could use a macro to expand, but we need the ifdef and not all the
options document which version they were introduced in. Policylet: include
all options unless explicitly for DTLS, let the administrator choose which
to apply.
This list is current as of:
==> 1.0.1b <==
Plus SSL_OP_SAFARI_ECDHE_ECDSA_BUG from 2013-June patch/discussion on openssl-de
v
*/
static struct exim_openssl_option exim_openssl_options[] = {
/* KEEP SORTED ALPHABETICALLY! */
#ifdef SSL_OP_ALL
{ US"all", SSL_OP_ALL },
#endif
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
{ US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIAT
ION },
#endif
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
{ US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
#endif
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
{ US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
#endif
#ifdef SSL_OP_EPHEMERAL_RSA
{ US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
#endif
#ifdef SSL_OP_LEGACY_SERVER_CONNECT
{ US"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT },
#endif
#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
{ US"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
#endif
#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
{ US"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG },
#endif
#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
{ US"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING },
#endif
#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
{ US"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG },
#endif
#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
{ US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BU
G },
#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
#ifdef SSL_OP_NO_SSLv2
{ US"no_sslv2", SSL_OP_NO_SSLv2 },
#endif
#ifdef SSL_OP_NO_SSLv3
{ US"no_sslv3", SSL_OP_NO_SSLv3 },
#endif
#ifdef SSL_OP_NO_TICKET
{ US"no_ticket", SSL_OP_NO_TICKET },
#endif
#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_SAFARI_ECDHE_ECDSA_BUG
{ US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
#endif
#ifdef SSL_OP_SINGLE_DH_USE
{ US"single_dh_use", SSL_OP_SINGLE_DH_USE },
#endif
#ifdef SSL_OP_SINGLE_ECDH_USE
{ US"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE },
#endif
#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
{ US"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
#endif
#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
{ US"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
#endif
#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
{ US"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG },
#endif
#ifdef SSL_OP_TLS_D5_BUG
{ US"tls_d5_bug", SSL_OP_TLS_D5_BUG },
#endif
#ifdef SSL_OP_TLS_ROLLBACK_BUG
{ US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
#endif
};
static int exim_openssl_options_size =
sizeof(exim_openssl_options)/sizeof(struct exim_openssl_option);
static BOOL static BOOL
tls_openssl_one_option_parse(uschar *name, long *value) tls_openssl_one_option_parse(uschar *name, long *value)
{ {
int first = 0; int first = 0;
int last = exim_openssl_options_size; int last = exim_openssl_options_size;
while (last > first) while (last > first)
{ {
int middle = (first + last)/2; int middle = (first + last)/2;
int c = Ustrcmp(name, exim_openssl_options[middle].name); int c = Ustrcmp(name, exim_openssl_options[middle].name);
if (c == 0) if (c == 0)
skipping to change at line 3123 skipping to change at line 3280
result |= item; result |= item;
else else
result &= ~item; result &= ~item;
s = end; s = end;
} }
*results = result; *results = result;
return TRUE; return TRUE;
} }
#endif /*!MACRO_PREDEF*/
/* vi: aw ai sw=2 /* vi: aw ai sw=2
*/ */
/* End of tls-openssl.c */ /* End of tls-openssl.c */
 End of changes. 134 change blocks. 
290 lines changed or deleted 450 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)