X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/6e48a63849cd3f1dfb3555fe57094954b3f7f092..3d02b3144cdde92d99ee7fcd0eb6cc9ba7c272f3:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index d5c5778fc..7643c4c36 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -2,8 +2,8 @@ * 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 */ @@ -2417,8 +2417,12 @@ int i; DEBUG(D_tls) debug_printf("Received TLS status callback (OCSP stapling):\n"); len = SSL_get_tlsext_status_ocsp_resp(s, &p); if(!p) - { - /* Expect this when we requested ocsp but got none */ + { /* Expect this when we requested ocsp but got none */ + if (SSL_session_reused(s) && tls_out.ocsp == OCSP_VFIED) + { + DEBUG(D_tls) debug_printf(" null, but resumed; ocsp vfy stored with session is good\n"); + return 1; + } if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher)) log_write(0, LOG_MAIN, "Required TLS certificate status not received"); else @@ -3337,8 +3341,9 @@ if (rc <= 0) 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); @@ -3357,7 +3362,9 @@ if (rc <= 0) || 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; } @@ -3368,7 +3375,9 @@ if (rc <= 0) 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)); @@ -3377,7 +3386,9 @@ if (rc <= 0) 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; } } @@ -3616,21 +3627,21 @@ return DEFER; 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; @@ -3656,24 +3667,21 @@ if (tlsp->host_resumable) if (lifetime + dt->time_stamp < time(NULL)) { DEBUG(D_tls) debug_printf("session expired\n"); - dbfn_delete(dbm_file, key); - } - else if (!SSL_set_session(ssl, ss)) - { - DEBUG(D_tls) - { - ERR_error_string_n(ERR_get_error(), - ssl_errstring, sizeof(ssl_errstring)); - debug_printf("applying session to ssl: %s\n", ssl_errstring); - } + dbfn_delete(dbm_file, tlsp->resume_index); } - else + else if (SSL_set_session(ssl, ss)) { DEBUG(D_tls) debug_printf("good session\n"); tlsp->resumption |= RESUME_CLIENT_SUGGESTED; tlsp->verify_override = dt->verify_override; tlsp->ocsp = dt->ocsp; } + else DEBUG(D_tls) + { + ERR_error_string_n(ERR_get_error(), + ssl_errstring, sizeof(ssl_errstring)); + debug_printf("applying session to ssl: %s\n", ssl_errstring); + } } } else @@ -3715,9 +3723,7 @@ if (SSL_SESSION_is_resumable(ss)) /* 1.1.1 */ 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); @@ -3727,21 +3733,20 @@ return 1; } +/* 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 @@ -3765,7 +3770,7 @@ if (tlsp->host_resumable) 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; } @@ -3785,16 +3790,19 @@ if (SSL_session_reused(exim_client_ctx->ssl)) #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) { @@ -3975,39 +3983,20 @@ if (tls_client_basic_ctx_init(exim_client_ctx->ctx, host, ob, 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 } } @@ -4018,10 +4007,10 @@ if (ob->tls_alpn) 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; @@ -4034,6 +4023,29 @@ if (ob->tls_alpn) ob->tls_alpn); #endif +#ifndef DISABLE_TLS_RESUME +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) @@ -4519,22 +4531,25 @@ int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock; if (*fdp < 0) return; /* TLS was not active */ -if (do_shutdown) +if (do_shutdown > TLS_NO_SHUTDOWN) { int rc; DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", - do_shutdown > 1 ? " (with response-wait)" : ""); + do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : ""); tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ - if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ - && do_shutdown > 1) + if ( ( do_shutdown >= TLS_SHUTDOWN_WONLY + || (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ + ) + && do_shutdown > TLS_SHUTDOWN_NOWAIT + ) { #ifdef EXIM_TCP_CORK (void) setsockopt(*fdp, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off)); #endif ALARM(2); - rc = SSL_shutdown(*sslp); /* wait for response */ + rc = SSL_shutdown(*sslp); /* wait for response */ ALARM_CLR(0); }