# define EXIM_HAVE_RAND_PSEUDO
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-# define EXIM_HAVE_SHA256 /*MMMM*/
+# define EXIM_HAVE_SHA256
#endif
-/*
- * X509_check_host provides sane certificate hostname checking, but was added
- * to OpenSSL late, after other projects forked off the code-base. So in
- * addition to guarding against the base version number, beware that LibreSSL
- * does not (at this time) support this function.
- *
- * 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
- * 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
- * change this guard and punt the issue for a while longer.
- */
+/* X509_check_host provides sane certificate hostname checking, but was added
+to OpenSSL late, after other projects forked off the code-base. So in
+addition to guarding against the base version number, beware that LibreSSL
+does not (at this time) support this function.
+
+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
+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
+change this guard and punt the issue for a while longer. */
+
#ifndef LIBRESSL_VERSION_NUMBER
# if OPENSSL_VERSION_NUMBER >= 0x010100000L
# define EXIM_HAVE_OPENSSL_CHECKHOST
# define EXIM_HAVE_OPENSSL_DH_BITS
# define EXIM_HAVE_OPENSSL_TLS_METHOD
+# else
+# define EXIM_NEED_OPENSSL_INIT
# endif
# if OPENSSL_VERSION_NUMBER >= 0x010000000L \
&& (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
|| LIBRESSL_VERSION_NUMBER >= 0x20010000L
# if !defined(OPENSSL_NO_ECDH)
# if OPENSSL_VERSION_NUMBER >= 0x0090800fL
-# define EXIM_HAVE_ECDH /*MMMM*/
+# define EXIM_HAVE_ECDH
# endif
# if OPENSSL_VERSION_NUMBER >= 0x10002000L
# define EXIM_HAVE_OPENSSL_EC_NIST2NID
# include <openssl/x509v3.h>
#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-dev
+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_RENEGOTIATION },
+#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_BUG },
+#endif
+#ifdef SSL_OP_NO_COMPRESSION
+ { US"no_compression", SSL_OP_NO_COMPRESSION },
+#endif
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
+#endif
+#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)
+{
+uschar buf[64];
+
+for (struct exim_openssl_option * 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. */
typedef struct randstuff {
{
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;
}
-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;
}
#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",
ssl_errstring);
return NULL;
x509_store_dump_cert_s_names(X509_STORE * store)
{
STACK_OF(X509_OBJECT) * roots= store->objs;
-int i;
static uschar name[256];
-for(i= 0; i<sk_X509_OBJECT_num(roots); i++)
+for (int i= 0; i < sk_X509_OBJECT_num(roots); i++)
{
X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i);
if(tmp_obj->type == X509_LU_X509)
{
- X509 * current_cert= tmp_obj->data.x509;
- X509_NAME_oneline(X509_get_subject_name(current_cert), CS name, sizeof(name));
- name[sizeof(name)-1] = '\0';
- debug_printf(" %s\n", name);
+ X509_NAME * sn = X509_get_subject_name(tmp_obj->data.x509);
+ if (X509_NAME_oneline(sn, CS name, sizeof(name)))
+ {
+ name[sizeof(name)-1] = '\0';
+ debug_printf(" %s\n", name);
+ }
}
}
}
*/
static int
-verify_callback(int preverify_ok, X509_STORE_CTX *x509ctx,
- tls_support *tlsp, BOOL *calledp, BOOL *optionalp)
+verify_callback(int preverify_ok, X509_STORE_CTX * x509ctx,
+ tls_support * tlsp, BOOL * calledp, BOOL * optionalp)
{
X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
int depth = X509_STORE_CTX_get_error_depth(x509ctx);
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';
if (preverify_ok == 0)
BOOL dummy_called, optional = FALSE;
#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';
DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n",
static void
info_callback(SSL *s, int where, int ret)
{
-where = where;
-ret = ret;
-DEBUG(D_tls) debug_printf("SSL info: %s\n", SSL_state_string_long(s));
+DEBUG(D_tls)
+ {
+ 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));
+ }
}
{
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);
}
goto bad;
return;
bad:
- if (running_in_test_harness)
+ if (f.running_in_test_harness)
{
extern char ** environ;
- uschar ** p;
- if (environ) for (p = USS environ; *p; p++)
+ if (environ) for (uschar ** p = USS environ; *p; p++)
if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0)
{
DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n");
goto err;
where = US"generating pkey";
-if (!(rsa = rsa_callback(NULL, 0, 1024)))
+if (!(rsa = rsa_callback(NULL, 0, 2048)))
goto err;
where = US"assigning pkey";
if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr)))
return err;
- if (cbinfo->privatekey != NULL &&
- !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
+ if ( cbinfo->privatekey
+ && !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
return DEFER;
/* If expansion was forced to fail, key_expanded will be NULL. If the result
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);
- return SSL_TLSEXT_ERR_NOACK;
+ goto bad;
}
/* Not sure how many of these are actually needed, since SSL object
if ( !init_dh(server_sni, cbinfo->dhparam, 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
if (cbinfo->u_ocsp.server.file)
{
if ((rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE,
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
OCSP information. */
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");
SSL_set_SSL_CTX(s, server_sni);
-
return SSL_TLSEXT_ERR_OK;
+
+bad: return SSL_TLSEXT_ERR_ALERT_FATAL;
}
#endif /* EXIM_HAVE_OPENSSL_TLSEXT */
cbinfo->event_action = NULL;
#endif
+#ifdef EXIM_NEED_OPENSSL_INIT
SSL_load_error_strings(); /* basic set up */
OpenSSL_add_ssl_algorithms();
+#endif
#ifdef EXIM_HAVE_SHA256
/* SHA256 is becoming ever more popular. This makes sure it gets added to the
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.
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
chain and the elements sent by the peer. */
+tlsp->peerdn = NULL;
+
/* Will have already noted peercert on a verify fail; possibly not the leaf */
if (!tlsp->peercert)
tlsp->peercert = SSL_get_peer_certificate(ssl);
/* Beware anonymous ciphers which lead to server_cert being NULL */
if (tlsp->peercert)
- {
- X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, bsize);
- peerdn[bsize-1] = '\0';
- tlsp->peerdn = peerdn; /*XXX a static buffer... */
- }
-else
- tlsp->peerdn = NULL;
+ if (!X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, siz))
+ { DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); }
+ else
+ {
+ peerdn[siz-1] = '\0';
+ tlsp->peerdn = peerdn; /*XXX a static buffer... */
+ }
}
/* Load the list of CAs for which we will accept certs, for sending
to the client. This is only for the one-file tls_verify_certificates
variant.
- If a list isn't loaded into the server, but
- some verify locations are set, the server end appears to make
- a wildcard request for client certs.
+ If a list isn't loaded into the server, but some verify locations are set,
+ the server end appears to make a wildcard request for client certs.
Meanwhile, the client library as default behaviour *ignores* the list
we send over the wire - see man SSL_CTX_set_client_cert_cb.
Because of this, and that the dir variant is likely only used for
- the public-CA bundle (not for a private CA), not worth fixing.
- */
+ the public-CA bundle (not for a private CA), not worth fixing. */
+
if (file)
{
STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
/* If verification is optional, don't fail if no certificate */
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);
}
DEBUG(D_tls) debug_printf("Calling SSL_accept\n");
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);
-alarm(0);
+ALARM_CLR(0);
if (rc <= 0)
{
}
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,
and initialize things. */
if ( ( !ob->tls_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;
-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;
else
return OK;
errstr)) != OK)
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 =
#ifdef SUPPORT_I18N
static int
dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa, uschar ** errstr)
{
-dns_record * rr;
dns_scan dnss;
const char * hostnames[2] = { CS host->name, NULL };
int found = 0;
if (DANESSL_init(ssl, NULL, hostnames) != 1)
return tls_error(US"hostnames load", host, NULL, errstr);
-for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
- rr;
+for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
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;
uint8_t usage, selector, mtype;
# endif
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;
else
# ifdef SUPPORT_DANE
if (!request_ocsp)
# endif
request_ocsp =
- verify_check_given_host(&ob->hosts_request_ocsp, host) == OK;
+ verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK;
}
#endif
{ /* Re-eval now $tls_out_tlsa_usage is populated. If
this means we avoid the OCSP request, we wasted the setup
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
- || verify_check_given_host(&ob->hosts_request_ocsp, host) == OK;
+ || verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK;
}
}
# endif
DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
sigalrm_seen = FALSE;
-alarm(ob->command_timeout);
+ALARM(ob->command_timeout);
rc = SSL_connect(exim_client_ctx->ssl);
-alarm(0);
+ALARM_CLR(0);
#ifdef SUPPORT_DANE
if (tlsa_dnsa)
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
ssl_xfer_buffer, ssl_xfer_buffer_size);
-if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
MIN(ssl_xfer_buffer_size, lim));
error = SSL_get_error(server_ssl, inbytes);
-if (smtp_receive_timeout > 0) 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 */
/* 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);
ssl_xfer_error = TRUE;
return FALSE;
int
tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
{
-int outbytes, error, left;
+size_t olen = len;
+int outbytes, error;
SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
static gstring * corked = NULL;
"more" is notified. This hack is only ok if small amounts are involved AND only
one stream does it, in one context (i.e. no store reset). Currently it is used
for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */
+/* + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
+a store reset there, so use POOL_PERM. */
+/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
-if (!ct_ctx && (more || corked))
+if ((more || corked))
{
+#ifdef EXPERIMENTAL_PIPE_CONNECT
+ int save_pool = store_pool;
+ store_pool = POOL_PERM;
+#endif
+
corked = string_catn(corked, buff, len);
+
+#ifdef EXPERIMENTAL_PIPE_CONNECT
+ store_pool = save_pool;
+#endif
+
if (more)
return len;
buff = CUS corked->s;
corked = NULL;
}
-for (left = len; left > 0;)
+for (int left = len; left > 0;)
{
DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left);
outbytes = SSL_write(ssl, CS buff, left);
switch (error)
{
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);
return -1;
return -1;
}
}
-return len;
+return olen;
}
if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */
&& shutdown > 1)
{
- alarm(2);
+ ALARM(2);
rc = SSL_shutdown(*sslp); /* wait for response */
- alarm(0);
+ ALARM_CLR(0);
}
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);
}
}
/* this duplicates from tls_init(), we need a better "init just global
state, for no specific purpose" singleton function of our own */
+#ifdef EXIM_NEED_OPENSSL_INIT
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
+#endif
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
/* SHA256 is becoming ever more popular. This makes sure it gets added to the
list of available digests. */
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);
}
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",
expciphers, ssl_errstring);
}
int i, needed_len;
static pid_t pidlast = 0;
pid_t pidnow;
-uschar *p;
uschar smallbuf[sizeof(r)];
if (max <= 1)
}
r = 0;
-for (p = smallbuf; needed_len; --needed_len, ++p)
- {
- r *= 256;
- r += *p;
- }
+for (uschar * p = smallbuf; needed_len; --needed_len, ++p)
+ r = 256 * r + *p;
/* We don't particularly care about weighted results; if someone wants
smooth distribution and cares enough then they should submit a patch then. */
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-dev
-*/
-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_RENEGOTIATION },
-#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_BUG },
-#endif
-#ifdef SSL_OP_NO_COMPRESSION
- { US"no_compression", SSL_OP_NO_COMPRESSION },
-#endif
-#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
- { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
-#endif
-#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
tls_openssl_options_parse(uschar *option_spec, long *results)
{
long result, item;
-uschar *s, *end;
+uschar *end;
uschar keep_c;
BOOL adding, item_parsed;
return TRUE;
}
-for (s=option_spec; *s != '\0'; /**/)
+for (uschar * s = option_spec; *s != '\0'; /**/)
{
while (isspace(*s)) ++s;
if (*s == '\0')
return TRUE;
}
+#endif /*!MACRO_PREDEF*/
/* vi: aw ai sw=2
*/
/* End of tls-openssl.c */