X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/0b049796b89a59fc322119b54199d92c404ef687..0851a3bbf4667081d47f5d85b6b3a5cb33cbdba6:/src/src/tls-gnu.c diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index cf899454f..fa489902a 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ /* Copyright (c) Phil Pennock 2012 */ @@ -110,9 +111,11 @@ require current GnuTLS, then we'll drop support for the ancient libraries). # endif #endif -#ifdef EXPERIMENTAL_TLS_RESUME -# if GNUTLS_VERSION_NUMBER < 0x030603 -# error GNUTLS version too early for session-resumption +#ifndef DISABLE_TLS_RESUME +# if GNUTLS_VERSION_NUMBER >= 0x030603 +# define EXIM_HAVE_TLS_RESUME +# else +# warning "GnuTLS library version too old; resumption unsupported" # endif #endif @@ -130,7 +133,7 @@ require current GnuTLS, then we'll drop support for the ancient libraries). void options_tls(void) { -# ifdef EXPERIMENTAL_TLS_RESUME +# ifndef DISABLE_TLS_RESUME builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING ); # endif # ifdef EXIM_HAVE_TLS1_3 @@ -265,7 +268,7 @@ static BOOL gnutls_buggy_ocsp = FALSE; static BOOL exim_testharness_disable_ocsp_validity_check = FALSE; #endif -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME static gnutls_datum_t server_sessticket_key; #endif @@ -325,7 +328,7 @@ static void exim_gnutls_logger_cb(int level, const char *message); static int exim_sni_handling_cb(gnutls_session_t session); -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME static int tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, unsigned incoming, const gnutls_datum_t * msg); @@ -336,7 +339,7 @@ tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, void tls_daemon_init(void) { -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME /* We are dependent on the GnuTLS implementation of the Session Ticket encryption; both the strength and the key rotation period. We hope that the strength at least matches that of the ciphersuite (but GnuTLS does not @@ -999,10 +1002,10 @@ return gnutls_ext_raw_parse(NULL, tls_server_servercerts_ext, msg, 0); "Handshake Protocol: Certificate" record. So we need to spot the Certificate handshake message, parse it and spot any status_request extension(s) -This is different to tls1.2 - where it is a separate record (wireshake term) / handshake message (gnutls term). +This is different to tls1.2 - where it is a separate record (wireshark term) / handshake message (gnutls term). */ -#if defined(EXPERIMENTAL_TLS_RESUME) || defined(SUPPORT_GNUTLS_EXT_RAW_PARSE) +#if defined(EXIM_HAVE_TLS_RESUME) || defined(SUPPORT_GNUTLS_EXT_RAW_PARSE) /* Callback for certificate-status, on server. We sent stapled OCSP. */ static int tls_server_certstatus_cb(gnutls_session_t session, unsigned int htype, @@ -1034,7 +1037,7 @@ switch (htype) # endif case GNUTLS_HANDSHAKE_CERTIFICATE_STATUS: return tls_server_certstatus_cb(sess, htype, when, incoming, msg); -# ifdef EXPERIMENTAL_TLS_RESUME +# ifdef EXIM_HAVE_TLS_RESUME case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: return tls_server_ticket_cb(sess, htype, when, incoming, msg); # endif @@ -2327,7 +2330,7 @@ else } -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME static int tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, unsigned incoming, const gnutls_datum_t * msg) @@ -2441,7 +2444,7 @@ DEBUG(D_tls) debug_printf("initialising GnuTLS as a server\n"); #endif } -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME tls_server_resume_prehandshake(state); #endif @@ -2513,7 +2516,7 @@ sigalrm_seen = FALSE; if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout); do rc = gnutls_handshake(state->session); -while (rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); +while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); ALARM_CLR(0); if (rc != GNUTLS_E_SUCCESS) @@ -2549,7 +2552,7 @@ if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET) tls_in.ext_master_secret = TRUE; #endif -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME tls_server_resume_posthandshake(state); #endif @@ -2600,9 +2603,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) { state->exp_tls_verify_cert_hostnames = #ifdef SUPPORT_I18N - string_domain_utf8_to_alabel(host->name, NULL); + string_domain_utf8_to_alabel(host->certname, NULL); #else - host->name; + host->certname; #endif DEBUG(D_tls) debug_printf("TLS: server cert verification includes hostname: \"%s\".\n", @@ -2682,7 +2685,7 @@ return TRUE; -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME /* On the client, get any stashed session for the given IP from hints db and apply it to the ssl-connection for attempted resumption. Although there is a gnutls_session_ticket_enable_client() interface it is @@ -2815,7 +2818,7 @@ if (gnutls_session_is_resumed(state->session)) tls_save_session(tlsp, state->session, host); } -#endif /* EXPERIMENTAL_TLS_RESUME */ +#endif /* !DISABLE_TLS_RESUME */ /************************************************* @@ -2969,7 +2972,7 @@ if (request_ocsp) } #endif -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME tls_client_resume_prehandshake(state, tlsp, host, ob); #endif @@ -2993,7 +2996,7 @@ sigalrm_seen = FALSE; ALARM(ob->command_timeout); do rc = gnutls_handshake(state->session); -while (rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); +while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); ALARM_CLR(0); if (rc != GNUTLS_E_SUCCESS) @@ -3069,7 +3072,7 @@ if (request_ocsp) } #endif -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME tls_client_resume_posthandshake(state, tlsp, host); #endif @@ -3157,7 +3160,10 @@ DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, buf sigalrm_seen = FALSE; if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout); -inbytes = gnutls_record_recv(state->session, state->xfer_buffer, MIN(ssl_xfer_buffer_size, lim)); +do + inbytes = gnutls_record_recv(state->session, state->xfer_buffer, + MIN(ssl_xfer_buffer_size, lim)); +while (inbytes == GNUTLS_E_AGAIN); if (smtp_receive_timeout > 0) ALARM_CLR(0); @@ -3314,7 +3320,9 @@ DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, len=" SIZE_T_FMT ")\n", state->session, buff, len); -inbytes = gnutls_record_recv(state->session, buff, len); +do + inbytes = gnutls_record_recv(state->session, buff, len); +while (inbytes == GNUTLS_E_AGAIN); if (inbytes > 0) return inbytes; if (inbytes == 0) @@ -3375,7 +3383,9 @@ while (left > 0) DEBUG(D_tls) debug_printf("gnutls_record_send(session=%p, buffer=%p, left=" SIZE_T_FMT ")\n", state->session, buff, left); - outbytes = gnutls_record_send(state->session, buff, left); + do + outbytes = gnutls_record_send(state->session, buff, left); + while (outbytes == GNUTLS_E_AGAIN); DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes); @@ -3407,14 +3417,21 @@ if (len > INT_MAX) if (!more && state->corked) { DEBUG(D_tls) debug_printf("gnutls_record_uncork(session=%p)\n", state->session); - do { - outbytes = gnutls_record_uncork(state->session, 0); - if (outbytes < 0) - { - record_io_error(state, len, US"uncork", NULL); - return -1; - } - } while (gnutls_record_check_corked(state->session) > 0); + do + /* We can't use GNUTLS_RECORD_WAIT here, as it retries on + GNUTLS_E_AGAIN || GNUTLS_E_INTR, which would break our timeout set by alarm(). + The GNUTLS_E_AGAIN should not happen ever, as our sockets are blocking anyway. + But who knows. (That all relies on the fact that GNUTLS_E_INTR and GNUTLS_E_AGAIN + match the EINTR and EAGAIN errno values.) */ + outbytes = gnutls_record_uncork(state->session, 0); + while (outbytes == GNUTLS_E_AGAIN); + + if (outbytes < 0) + { + record_io_error(state, len, US"uncork", NULL); + return -1; + } + state->corked = FALSE; } #endif