X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Ftls-gnu.c;h=a351c34d671502076e2701c02f720b9b3b9addf4;hb=12b7f811de4a540d0724585aecfa33b5881e2a30;hp=2e1b9e4d36a207937eb6fe2ec859d0effedbe14f;hpb=50a3f20592c79da4acd409b59803dd5ff31b9781;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 2e1b9e4d3..a351c34d6 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 */ @@ -53,6 +54,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries). # warning "GnuTLS library version too old; tls:cert event unsupported" # define DISABLE_EVENT #endif +#if GNUTLS_VERSION_NUMBER >= 0x030000 +# define SUPPORT_SELFSIGN /* Uncertain what version is first usable but 2.12.23 is not */ +#endif #if GNUTLS_VERSION_NUMBER >= 0x030306 # define SUPPORT_CA_DIR #else @@ -107,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 @@ -127,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 @@ -262,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 @@ -322,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); @@ -333,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 @@ -824,13 +830,19 @@ gnutls_x509_privkey_t pkey = NULL; const uschar * where; int rc; +#ifndef SUPPORT_SELFSIGN +where = US"library too old"; +rc = GNUTLS_E_NO_CERTIFICATE_FOUND; +if (TRUE) goto err; +#endif + where = US"initialising pkey"; if ((rc = gnutls_x509_privkey_init(&pkey))) goto err; where = US"initialising cert"; if ((rc = gnutls_x509_crt_init(&cert))) goto err; -where = US"generating pkey"; +where = US"generating pkey"; /* Hangs on 2.12.23 */ if ((rc = gnutls_x509_privkey_generate(pkey, GNUTLS_PK_RSA, #ifdef SUPPORT_PARAM_TO_PK_BITS # ifndef GNUTLS_SEC_PARAM_MEDIUM @@ -990,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, @@ -1025,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 @@ -2318,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) @@ -2432,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 @@ -2540,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 @@ -2673,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 @@ -2806,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 */ /************************************************* @@ -2960,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 @@ -3060,7 +3072,7 @@ if (request_ocsp) } #endif -#ifdef EXPERIMENTAL_TLS_RESUME +#ifdef EXIM_HAVE_TLS_RESUME tls_client_resume_posthandshake(state, tlsp, host); #endif @@ -3353,9 +3365,14 @@ tls_write(void * ct_ctx, const uschar * buff, size_t len, BOOL more) ssize_t outbytes; size_t left = len; exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server; -#ifdef SUPPORT_CORK -if (more && !state->corked) gnutls_record_cork(state->session); +#ifdef SUPPORT_CORK +if (more && !state->corked) + { + DEBUG(D_tls) debug_printf("gnutls_record_cork(session=%p)\n", state->session); + gnutls_record_cork(state->session); + state->corked = TRUE; + } #endif DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__, @@ -3371,6 +3388,7 @@ while (left > 0) while (outbytes == GNUTLS_E_AGAIN); DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes); + if (outbytes < 0) { DEBUG(D_tls) debug_printf("%s: gnutls_record_send err\n", __FUNCTION__); @@ -3396,10 +3414,25 @@ if (len > INT_MAX) } #ifdef SUPPORT_CORK -if (more != state->corked) +if (!more && state->corked) { - if (!more) (void) gnutls_record_uncork(state->session, 0); - state->corked = more; + DEBUG(D_tls) debug_printf("gnutls_record_uncork(session=%p)\n", state->session); + 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