*************************************************/
/* 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
#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
.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 */
-#ifndef GNUTLS_AUTO_DHPARAMS
/*************************************************
* Setup up DH parameters *
*************************************************/
{
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;
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;
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;
DEBUG(D_tls) debug_printf("initialized server D-H parameters\n");
return OK;
}
-#endif
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. */
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);
}
-#else
-DEBUG(D_tls) if (tls_dhparam)
- debug_printf("Ignoring tls_dhparam (recent version GnuTLS)\n");
-#endif
/* Link the credentials to the session. */
state->tlsp->peercert = crt;
if ((yield = event_raise(state->event_action,
- US"tls:cert", string_sprintf("%d", cert_list_size))))
+ US"tls:cert", string_sprintf("%d", cert_list_size), &errno)))
{
log_write(0, LOG_MAIN,
"SSL verify denied by event-action: depth=%d: %s",
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. */
if (sigalrm_seen)
{
tls_error(US"gnutls_handshake", US"timed out", NULL, errstr);
+ (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
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, NULL);
(void) gnutls_alert_send_appropriate(state->session, rc);
gnutls_deinit(state->session);
gnutls_certificate_free_credentials(state->lib_state.x509_cred);
receive_ungetc = tls_ungetc;
receive_feof = tls_feof;
receive_ferror = tls_ferror;
-receive_smtp_buffered = tls_smtp_buffered;
return OK;
}
tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */
+#ifdef EXIM_TCP_CORK
+ if (do_shutdown > 1)
+ (void) setsockopt(tlsp->active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
+#endif
+
ALARM(2);
gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
ALARM_CLR(0);
receive_ungetc = smtp_ungetc;
receive_feof = smtp_feof;
receive_ferror = smtp_ferror;
- receive_smtp_buffered = smtp_buffered;
}
gnutls_deinit(state->session);
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;