X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Ftls-gnu.c;h=d73188277be2b6171d419023b70f5b56e7814c0b;hp=3a45999aa3791b1c402259b70b4950c6be566bf8;hb=d51dbacf4da044f797cb4c07e026adc608f1bc98;hpb=f1fed05bfbcf83b7d504ea68d136c4a923d070ea diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 3a45999aa..d73188277 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2017 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* Copyright (c) Phil Pennock 2012 */ @@ -66,13 +66,17 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP) # define SUPPORT_SRV_OCSP_STACK #endif -#if GNUTLS_VERSION_NUMBER >= 0x030000 && defined(EXPERIMENTAL_DANE) -# define SUPPORT_DANE -# define DANESSL_USAGE_DANE_TA 2 -# define DANESSL_USAGE_DANE_EE 3 -#endif -#if GNUTLS_VERSION_NUMBER < 0x999999 && defined(EXPERIMENTAL_DANE) -# define GNUTLS_BROKEN_DANE_VALIDATION + +#ifdef SUPPORT_DANE +# if GNUTLS_VERSION_NUMBER >= 0x030000 +# define DANESSL_USAGE_DANE_TA 2 +# define DANESSL_USAGE_DANE_EE 3 +# else +# error GnuTLS version too early for DANE +# endif +# if GNUTLS_VERSION_NUMBER < 0x999999 +# define GNUTLS_BROKEN_DANE_VALIDATION +# endif #endif #ifndef DISABLE_OCSP @@ -152,8 +156,8 @@ typedef struct exim_gnutls_state { uschar *xfer_buffer; int xfer_buffer_lwm; int xfer_buffer_hwm; - int xfer_eof; - int xfer_error; + BOOL xfer_eof; /*XXX never gets set! */ + BOOL xfer_error; } exim_gnutls_state_st; static const exim_gnutls_state_st exim_gnutls_state_init = { @@ -194,8 +198,8 @@ static const exim_gnutls_state_st exim_gnutls_state_init = { .xfer_buffer = NULL, .xfer_buffer_lwm = 0, .xfer_buffer_hwm = 0, - .xfer_eof = 0, - .xfer_error = 0, + .xfer_eof = FALSE, + .xfer_error = FALSE, }; /* Not only do we have our own APIs which don't pass around state, assuming @@ -1617,7 +1621,7 @@ else (needed for TA but not EE). */ if (usage == ((1<session), - r, 0, + r, 0, # ifdef GNUTLS_BROKEN_DANE_VALIDATION usage == (1 << DANESSL_USAGE_DANE_EE) ? DANE_VFLAG_ONLY_CHECK_EE_USAGE : 0, @@ -1916,12 +1920,10 @@ int rc; uschar * yield; exim_gnutls_state_st * state = gnutls_session_get_ptr(session); -cert_list = gnutls_certificate_get_peers(session, &cert_list_size); -if (cert_list) +if ((cert_list = gnutls_certificate_get_peers(session, &cert_list_size))) while (cert_list_size--) { - rc = import_cert(&cert_list[cert_list_size], &crt); - if (rc != GNUTLS_E_SUCCESS) + if ((rc = import_cert(&cert_list[cert_list_size], &crt)) != GNUTLS_E_SUCCESS) { DEBUG(D_tls) debug_printf("TLS: peer cert problem: depth %d: %s\n", cert_list_size, gnutls_strerror(rc)); @@ -2249,7 +2251,7 @@ int tls_client_start(int fd, host_item *host, address_item *addr ARG_UNUSED, transport_instance * tb, -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE dns_answer * tlsa_dnsa, #endif uschar ** errstr) @@ -2258,6 +2260,7 @@ smtp_transport_options_block *ob = (smtp_transport_options_block *)tb->options_block; int rc; exim_gnutls_state_st * state = NULL; +uschar *cipher_list = NULL; #ifndef DISABLE_OCSP BOOL require_ocsp = verify_check_given_host(&ob->hosts_require_ocsp, host) == OK; @@ -2267,9 +2270,24 @@ BOOL request_ocsp = require_ocsp ? TRUE DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd); +#ifdef SUPPORT_DANE +if (tlsa_dnsa && ob->dane_require_tls_ciphers) + { + /* not using expand_check_tlsvar because not yet in state */ + if (!expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers", + &cipher_list, errstr)) + return DEFER; + cipher_list = cipher_list && *cipher_list + ? ob->dane_require_tls_ciphers : ob->tls_require_ciphers; + } +#endif + +if (!cipher_list) + cipher_list = ob->tls_require_ciphers; + if ((rc = tls_init(host, ob->tls_certificate, ob->tls_privatekey, ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl, - ob->tls_require_ciphers, &state, errstr)) != OK) + cipher_list, &state, errstr)) != OK) return rc; { @@ -2438,12 +2456,15 @@ return OK; daemon, to shut down the TLS library, without actually doing a shutdown (which would tamper with the TLS session in the parent process). -Arguments: TRUE if gnutls_bye is to be called +Arguments: + shutdown 1 if TLS close-alert is to be sent, + 2 if also response to be waited for + Returns: nothing */ void -tls_close(BOOL is_server, BOOL shutdown) +tls_close(BOOL is_server, int shutdown) { exim_gnutls_state_st *state = is_server ? &state_server : &state_client; @@ -2451,8 +2472,12 @@ if (!state->tlsp || state->tlsp->active < 0) return; /* TLS was not active */ if (shutdown) { - DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n"); - gnutls_bye(state->session, GNUTLS_SHUT_WR); + DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", + shutdown > 1 ? " (with response-wait)" : ""); + + alarm(2); + gnutls_bye(state->session, shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); + alarm(0); } gnutls_deinit(state->session); @@ -2460,9 +2485,10 @@ gnutls_certificate_free_credentials(state->x509_cred); state->tlsp->active = -1; +if (state->xfer_buffer) store_free(state->xfer_buffer); memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init)); -if ((state_server.session == NULL) && (state_client.session == NULL)) +if (!state_server.session && !state_client.session) { gnutls_global_deinit(); exim_gnutls_base_init_done = FALSE; @@ -2495,7 +2521,7 @@ alarm(0); if (sigalrm_seen) { DEBUG(D_tls) debug_printf("Got tls read timeout\n"); - state->xfer_error = 1; + state->xfer_error = TRUE; return FALSE; } @@ -2531,7 +2557,7 @@ else if (inbytes == 0) else if (inbytes < 0) { record_io_error(state, (int) inbytes, US"recv", NULL); - state->xfer_error = 1; + state->xfer_error = TRUE; return FALSE; } #ifndef DISABLE_DKIM