X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b367453a08bff7123dfe0b841de290e17372ad7c..ef2e5890df09193717f9d345ffaaa406e2d8aae7:/src/src/tls-gnu.c diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 796581b0e..4f1039903 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3,10 +3,9 @@ *************************************************/ /* 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 */ +/* Copyright (c) The Exim Maintainers 2020 - 2021 */ +/* See the file NOTICE for conditions of use and distribution. */ /* This file provides TLS/SSL support for Exim using the GnuTLS library, one of the available supported implementations. This file is #included into @@ -90,9 +89,6 @@ 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 >= 0x030600 -# define GNUTLS_AUTO_DHPARAMS -#endif #if GNUTLS_VERSION_NUMBER >= 0x030603 # define EXIM_HAVE_TLS1_3 # define SUPPORT_GNUTLS_EXT_RAW_PARSE @@ -266,13 +262,11 @@ static exim_gnutls_state_st state_server = { .fd_out = -1, }; -#ifndef GNUTLS_AUTO_DHPARAMS /* dh_params are initialised once within the lifetime of a process using TLS; if we used TLS in a long-lived daemon, we'd have to reconsider this. But we don't want to repeat this. */ static gnutls_dh_params_t dh_server_params = NULL; -#endif static int ssl_session_timeout = 7200; /* Two hours */ @@ -689,7 +683,6 @@ if (!state->host) -#ifndef GNUTLS_AUTO_DHPARAMS /************************************************* * Setup up DH parameters * *************************************************/ @@ -712,7 +705,7 @@ init_server_dh(uschar ** errstr) { int fd, rc; unsigned int dh_bits; -gnutls_datum_t m = {.data = NULL, .size = 0}; +gnutls_datum_t m; uschar filename_buf[PATH_MAX]; uschar *filename = NULL; size_t sz; @@ -725,6 +718,9 @@ DEBUG(D_tls) debug_printf("Initialising GnuTLS server params\n"); if ((rc = gnutls_dh_params_init(&dh_server_params))) return tls_error_gnu(NULL, US"gnutls_dh_params_init", rc, errstr); +m.data = NULL; +m.size = 0; + if (!expand_check(tls_dhparam, US"tls_dhparam", &exp_tls_dhparam, errstr)) return DEFER; @@ -874,12 +870,14 @@ if (rc < 0) return tls_error_sys(US"Unable to open temp file", errno, NULL, errstr); (void)exim_chown(temp_fn, exim_uid, exim_gid); /* Probably not necessary */ - /* GnuTLS overshoots! If we ask for 2236, we might get 2237 or more. But - there's no way to ask GnuTLS how many bits there really are. We can ask - how many bits were used in a TLS session, but that's it! The prime itself - is hidden behind too much abstraction. So we ask for less, and proceed on - a wing and a prayer. First attempt, subtracted 3 for 2233 and got 2240. */ - + /* GnuTLS overshoots! + * If we ask for 2236, we might get 2237 or more. + * But there's no way to ask GnuTLS how many bits there really are. + * We can ask how many bits were used in a TLS session, but that's it! + * The prime itself is hidden behind too much abstraction. + * So we ask for less, and proceed on a wing and a prayer. + * First attempt, subtracted 3 for 2233 and got 2240. + */ if (dh_bits >= EXIM_CLIENT_DH_MIN_BITS + 10) { dh_bits_gen = dh_bits - 10; @@ -942,7 +940,6 @@ if (rc < 0) DEBUG(D_tls) debug_printf("initialized server D-H parameters\n"); return OK; } -#endif @@ -1079,7 +1076,8 @@ static int tls_server_clienthello_ext(void * ctx, unsigned tls_id, const uschar * data, unsigned size) { -/* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */ +/* The values for tls_id are documented here: +https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */ switch (tls_id) { case 5: /* Status Request */ @@ -1952,7 +1950,6 @@ tls_set_remaining_x509(exim_gnutls_state_st *state, uschar ** errstr) int rc; const host_item *host = state->host; /* macro should be reconsidered? */ -#ifndef GNUTLS_AUTO_DHPARAMS /* Create D-H parameters, or read them from the cache file. This function does its own SMTP error messaging. This only happens for the server, TLS D-H ignores client-side params. */ @@ -1962,10 +1959,10 @@ if (!state->host) if (!dh_server_params) if ((rc = init_server_dh(errstr)) != OK) return rc; - /* Unnecessary & discouraged with 3.6.0 or later */ + /* Unnecessary & discouraged with 3.6.0 or later, according to docs. But without it, + no DHE- ciphers are advertised. */ gnutls_certificate_set_dh_params(state->lib_state.x509_cred, dh_server_params); } -#endif /* Link the credentials to the session. */ @@ -2112,7 +2109,7 @@ if (!state->lib_state.pri_string) if ((rc = creds_load_pristring(state, p, &errpos))) return tls_error_gnu(state, string_sprintf( "gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"", - p, errpos - CS p, errpos), + p, (long)(errpos - CS p), errpos), rc, errstr); } else @@ -3046,6 +3043,9 @@ ALARM_CLR(0); if (rc != GNUTLS_E_SUCCESS) { + DEBUG(D_tls) debug_printf(" error %d from gnutls_handshake: %s\n", + rc, gnutls_strerror(rc)); + /* It seems that, except in the case of a timeout, we have to close the connection right here; otherwise if the other end is running OpenSSL it hangs until the server times out. */ @@ -3053,11 +3053,13 @@ if (rc != GNUTLS_E_SUCCESS) if (sigalrm_seen) { tls_error(US"gnutls_handshake", US"timed out", NULL, errstr); + (void) event_raise(event_action, US"tls:fail:connect", *errstr); gnutls_db_remove_session(state->session); } else { tls_error_gnu(state, US"gnutls_handshake", rc, errstr); + (void) event_raise(event_action, US"tls:fail:connect", *errstr); (void) gnutls_alert_send_appropriate(state->session, rc); gnutls_deinit(state->session); gnutls_certificate_free_credentials(state->lib_state.x509_cred); @@ -3137,10 +3139,10 @@ state->xfer_buffer = store_malloc(ssl_xfer_buffer_size); receive_getc = tls_getc; receive_getbuf = tls_getbuf; receive_get_cache = tls_get_cache; +receive_hasc = tls_hasc; receive_ungetc = tls_ungetc; receive_feof = tls_feof; receive_ferror = tls_ferror; -receive_smtp_buffered = tls_smtp_buffered; return OK; } @@ -3739,10 +3741,10 @@ if (!ct_ctx) /* server */ receive_getc = smtp_getc; receive_getbuf = smtp_getbuf; receive_get_cache = smtp_get_cache; + receive_hasc = smtp_hasc; receive_ungetc = smtp_ungetc; receive_feof = smtp_feof; receive_ferror = smtp_ferror; - receive_smtp_buffered = smtp_buffered; } gnutls_deinit(state->session); @@ -3853,6 +3855,13 @@ if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm) return state->xfer_buffer[state->xfer_buffer_lwm++]; } +BOOL +tls_hasc(void) +{ +exim_gnutls_state_st * state = &state_server; +return state->xfer_buffer_lwm < state->xfer_buffer_hwm; +} + uschar * tls_getbuf(unsigned * len) { @@ -3893,7 +3902,7 @@ if (n > 0) BOOL -tls_could_read(void) +tls_could_getc(void) { return state_server.xfer_buffer_lwm < state_server.xfer_buffer_hwm || gnutls_record_check_pending(state_server.session) > 0; @@ -4200,7 +4209,7 @@ DEBUG(D_tls) rc = gnutls_priority_init(&priority_cache, CS expciphers, &errpos); validate_check_rc(string_sprintf( "gnutls_priority_init(%s) failed at offset %ld, \"%.8s..\"", - expciphers, errpos - CS expciphers, errpos)); + expciphers, (long)(errpos - CS expciphers), errpos)); #undef return_deinit #undef validate_check_rc