* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2019 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
/* Portions Copyright (c) The OpenSSL Project 1999 */
case SSL_ERROR_ZERO_RETURN:
DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
(void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
+#ifndef DISABLE_EVENT
(void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
-
+#endif
if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN)
SSL_shutdown(ssl);
|| r == SSL_R_UNKNOWN_PROTOCOL || r == SSL_R_UNSUPPORTED_PROTOCOL)
s = string_sprintf("(%s)", SSL_get_version(ssl));
(void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : s, errstr);
+#ifndef DISABLE_EVENT
(void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
+#endif
return FAIL;
}
if (!errno)
{
*errstr = US"SSL_accept: TCP connection closed by peer";
+#ifndef DISABLE_EVENT
(void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
+#endif
return FAIL;
}
DEBUG(D_tls) debug_printf(" - syscall %s\n", strerror(errno));
sigalrm_seen ? US"timed out"
: ERR_peek_error() ? NULL : string_sprintf("ret %d", error),
errstr);
+#ifndef DISABLE_EVENT
(void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
+#endif
return FAIL;
}
}
and apply it to the ssl-connection for attempted resumption. */
static void
-tls_retrieve_session(tls_support * tlsp, SSL * ssl, const uschar * key)
+tls_retrieve_session(tls_support * tlsp, SSL * ssl)
{
-tlsp->resumption |= RESUME_SUPPORTED;
if (tlsp->host_resumable)
{
+ const uschar * key = tlsp->resume_index;
dbdata_tls_session * dt;
int len;
open_db dbblock, * dbm_file;
tlsp->resumption |= RESUME_CLIENT_REQUESTED;
- DEBUG(D_tls) debug_printf("checking for resumable session for %s\n", key);
+ DEBUG(D_tls)
+ debug_printf("checking for resumable session for %s\n", tlsp->resume_index);
if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
{
- /* key for the db is the IP */
- if ((dt = dbfn_read_with_length(dbm_file, key, &len)))
+ if ((dt = dbfn_read_with_length(dbm_file, tlsp->resume_index, &len)))
{
SSL_SESSION * ss = NULL;
const uschar * sess_asn1 = dt->session;
if (lifetime + dt->time_stamp < time(NULL))
{
DEBUG(D_tls) debug_printf("session expired\n");
- dbfn_delete(dbm_file, key);
+ dbfn_delete(dbm_file, tlsp->resume_index);
}
else if (SSL_set_session(ssl, ss))
{
if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
{
- const uschar * key = cbinfo->host->address;
- dbfn_delete(dbm_file, key);
- dbfn_write(dbm_file, key, dt, dlen);
+ dbfn_write(dbm_file, tlsp->resume_index, dt, dlen);
dbfn_close(dbm_file);
DEBUG(D_tls) debug_printf("wrote session (len %u) to db\n",
(unsigned)dlen);
}
+/* Construct a key for session DB lookup, and setup the SSL_CTX for resumption */
+
static void
tls_client_ctx_resume_prehandshake(
- exim_openssl_client_tls_ctx * exim_client_ctx, tls_support * tlsp,
- smtp_transport_options_block * ob, host_item * host)
+ exim_openssl_client_tls_ctx * exim_client_ctx, smtp_connect_args * conn_args,
+ tls_support * tlsp, smtp_transport_options_block * ob)
{
-/* Should the client request a session resumption ticket? */
-if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
- {
- tlsp->host_resumable = TRUE;
+tlsp->host_resumable = TRUE;
+tls_client_resmption_key(tlsp, conn_args, ob);
- SSL_CTX_set_session_cache_mode(exim_client_ctx->ctx,
- SSL_SESS_CACHE_CLIENT
- | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
- SSL_CTX_sess_set_new_cb(exim_client_ctx->ctx, tls_save_session_cb);
- }
+SSL_CTX_set_session_cache_mode(exim_client_ctx->ctx,
+ SSL_SESS_CACHE_CLIENT
+ | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
+SSL_CTX_sess_set_new_cb(exim_client_ctx->ctx, tls_save_session_cb);
}
static BOOL
tlsp->resumption = RESUME_SUPPORTED;
/* Pick up a previous session, saved on an old ticket */
-tls_retrieve_session(tlsp, ssl, host->address);
+tls_retrieve_session(tlsp, ssl);
return TRUE;
}
#ifdef EXIM_HAVE_ALPN
/* Expand and convert an Exim list to an ALPN list. False return for fail.
NULL plist return for silent no-ALPN.
+
+Overwite the passed-in list with the expanded version.
*/
static BOOL
-tls_alpn_plist(const uschar * tls_alpn, const uschar ** plist, unsigned * plen,
+tls_alpn_plist(uschar ** tls_alpn, const uschar ** plist, unsigned * plen,
uschar ** errstr)
{
uschar * exp_alpn;
-if (!expand_check(tls_alpn, US"tls_alpn", &exp_alpn, errstr))
+if (!expand_check(*tls_alpn, US"tls_alpn", &exp_alpn, errstr))
return FALSE;
+*tls_alpn = exp_alpn;
if (!exp_alpn)
{
client_static_state, errstr) != OK)
return FALSE;
-#ifndef DISABLE_TLS_RESUME
-tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
-#endif
-
-
-if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
- {
- tls_error(US"SSL_new", host, NULL, errstr);
- return FALSE;
- }
-SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
-
-SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
-SSL_set_connect_state(exim_client_ctx->ssl);
-
if (ob->tls_sni)
{
if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr))
return FALSE;
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(tlsp->sni))
tlsp->sni = NULL;
else
{
-#ifdef EXIM_HAVE_OPENSSL_TLSEXT
- DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tlsp->sni);
- SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni);
-#else
+#ifndef EXIM_HAVE_OPENSSL_TLSEXT
log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; ignoring \"%s\"\n",
tlsp->sni);
+ tlsp->sni = NULL;
#endif
}
}
const uschar * plist;
unsigned plen;
- if (!tls_alpn_plist(ob->tls_alpn, &plist, &plen, errstr))
+ if (!tls_alpn_plist(&ob->tls_alpn, &plist, &plen, errstr))
return FALSE;
if (plist)
- if (SSL_set_alpn_protos(exim_client_ctx->ssl, plist, plen) != 0)
+ if (SSL_CTX_set_alpn_protos(exim_client_ctx->ctx, plist, plen) != 0)
{
tls_error(US"alpn init", host, NULL, errstr);
return FALSE;
ob->tls_alpn);
#endif
+#ifndef DISABLE_TLS_RESUME
+/*XXX have_lbserver: another cmdline arg possibly, for continued-conn, but use
+will be very low. */
+
+if (!conn_args->have_lbserver) /* wanted for tls_client_resmption_key() */
+ { DEBUG(D_tls) debug_printf("resumption not supported on continued-connection\n"); }
+else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
+ tls_client_ctx_resume_prehandshake(exim_client_ctx, conn_args, tlsp, ob);
+#endif
+
+
+if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
+ {
+ tls_error(US"SSL_new", host, NULL, errstr);
+ return FALSE;
+ }
+SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
+SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
+SSL_set_connect_state(exim_client_ctx->ssl);
+
+#ifdef EXIM_HAVE_OPENSSL_TLSEXT
+if (tlsp->sni)
+ {
+ DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tlsp->sni);
+ SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni);
+ }
+#endif
+
#ifdef SUPPORT_DANE
if (conn_args->dane)
if (dane_tlsa_load(exim_client_ctx->ssl, host, &conn_args->tlsa_dnsa, errstr) != OK)