X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/17c761988f30054827a9951761d93ffeeaad0cb7..b34fc30c7704c469a25b5a933fc38867f5128630:/src/src/tls-gnu.c diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index f0e391f97..8391914b6 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -140,12 +140,6 @@ static const char * const exim_default_gnutls_priority = "NORMAL"; static BOOL exim_gnutls_base_init_done = FALSE; -/* ------------------------------------------------------------------------ */ -/* Callback declarations */ - -static void exim_gnutls_logger_cb(int level, const char *message); -static int exim_sni_handling_cb(gnutls_session_t session); - /* ------------------------------------------------------------------------ */ /* macros */ @@ -158,20 +152,37 @@ callbacks. */ #define EXIM_CLIENT_DH_MIN_BITS 1024 +/* With GnuTLS 2.12.x+ we have gnutls_sec_param_to_pk_bits() with which we +can ask for a bit-strength. Without that, we stick to the constant we had +before, for now. */ +#define EXIM_SERVER_DH_BITS_PRE2_12 1024 + #define exim_gnutls_err_check(Label) do { \ if (rc != GNUTLS_E_SUCCESS) { return tls_error((Label), gnutls_strerror(rc), host); } } while (0) -#define exim_gnutls_err_debugreturn0(Label) do { \ - if (rc != GNUTLS_E_SUCCESS) { \ - DEBUG(D_tls) debug_printf("TLS failure: %s: %s", (Label), gnutls_strerror(rc)); \ - return 0; } } while (0) - #define expand_check_tlsvar(Varname) expand_check(state->Varname, US #Varname, &state->exp_##Varname) #if GNUTLS_VERSION_NUMBER >= 0x020c00 #define HAVE_GNUTLS_SESSION_CHANNEL_BINDING +#define HAVE_GNUTLS_SEC_PARAM_CONSTANTS +#define HAVE_GNUTLS_RND #endif + + + +/* ------------------------------------------------------------------------ */ +/* Callback declarations */ + +#if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0 +static void exim_gnutls_logger_cb(int level, const char *message); +#endif + +static int exim_sni_handling_cb(gnutls_session_t session); + + + + /* ------------------------------------------------------------------------ */ /* Static functions */ @@ -380,21 +391,30 @@ gnutls_datum m; uschar filename[PATH_MAX]; size_t sz; host_item *host = NULL; /* dummy for macros */ -const char * const dh_param_fn_ext = "normal"; /* change as dh_bits changes */ DEBUG(D_tls) debug_printf("Initialising GnuTLS server params.\n"); rc = gnutls_dh_params_init(&dh_server_params); exim_gnutls_err_check(US"gnutls_dh_params_init"); -/* If you change this, also change dh_param_fn_ext so that we can use a +#ifdef HAVE_GNUTLS_SEC_PARAM_CONSTANTS +/* If you change this constant, also change dh_param_fn_ext so that we can use a different filename and ensure we have sufficient bits. */ dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL); if (!dh_bits) return tls_error(US"gnutls_sec_param_to_pk_bits() failed", NULL, NULL); +DEBUG(D_tls) + debug_printf("GnuTLS tells us that for D-H PK, NORMAL is %d bits.\n", + dh_bits); +#else +dh_bits = EXIM_SERVER_DH_BITS_PRE2_12; +DEBUG(D_tls) + debug_printf("GnuTLS lacks gnutls_sec_param_to_pk_bits(), using %d bits.\n", + dh_bits); +#endif if (!string_format(filename, sizeof(filename), - "%s/gnutls-params-%s", spool_directory, dh_param_fn_ext)) + "%s/gnutls-params-%d", spool_directory, dh_bits)) return tls_error(US"overlong filename", NULL, NULL); /* Open the cache file for reading and if successful, read it and set up the @@ -634,12 +654,12 @@ if (state->exp_tls_certificate && *state->exp_tls_certificate) if ((Ustrcmp(state->exp_tls_certificate, saved_tls_certificate) == 0) && (Ustrcmp(state->exp_tls_privatekey, saved_tls_privatekey) == 0)) { - DEBUG(D_tls) debug_printf("cert and key unchanged with SNI.\n"); + DEBUG(D_tls) debug_printf("TLS SNI: cert and key unchanged\n"); setit = FALSE; } else { - DEBUG(D_tls) debug_printf("SNI changed cert/key pair.\n"); + DEBUG(D_tls) debug_printf("TLS SNI: have a changed cert/key pair.\n"); } } @@ -651,8 +671,9 @@ if (state->exp_tls_certificate && *state->exp_tls_certificate) exim_gnutls_err_check( string_sprintf("cert/key setup: cert=%s key=%s", state->exp_tls_certificate, state->exp_tls_privatekey)); + DEBUG(D_tls) debug_printf("TLS: cert/key registered\n"); } - } + } /* tls_certificate */ /* Set the trusted CAs file if one is provided, and then add the CRL if one is provided. Experiment shows that, if the certificate file is empty, an unhelpful @@ -673,15 +694,32 @@ if (state->tls_verify_certificates && *state->tls_verify_certificates) if (state->received_sni) { - if (Ustrcmp(state->exp_tls_verify_certificates, saved_tls_verify_certificates) == 0) - setit_vc = FALSE; - if (Ustrcmp(state->exp_tls_crl, saved_tls_crl) == 0) - setit_crl = FALSE; + state->exp_tls_verify_certificates, state->exp_tls_verify_certificates, + saved_tls_verify_certificates, saved_tls_verify_certificates); + if (!(state->exp_tls_verify_certificates || saved_tls_verify_certificates)) + setit_vc = FALSE; /* never was set */ + else if (!state->exp_tls_verify_certificates || !saved_tls_verify_certificates) + setit_vc = TRUE; /* changed whether set */ + else if (Ustrcmp(state->exp_tls_verify_certificates, saved_tls_verify_certificates) == 0) + setit_vc = FALSE; /* not changed value */ + + state->exp_tls_crl, state->exp_tls_crl, + saved_tls_crl, saved_tls_crl); + if (!(state->exp_tls_crl || saved_tls_crl)) + setit_crl = FALSE; /* never was set */ + else if (!state->exp_tls_crl || !saved_tls_crl) + setit_crl = TRUE; /* changed whether set */ + else if (Ustrcmp(state->exp_tls_crl, saved_tls_crl) == 0) + setit_crl = FALSE; /* not changed value */ } /* nb: early exit; change if add more expansions to this function */ if (!(setit_vc || setit_crl)) + { + DEBUG(D_tls) + debug_printf("TLS SNI: no change to tls_crl or tls_verify_certificates\n"); return OK; + } if (Ustat(state->exp_tls_verify_certificates, &statbuf) < 0) { @@ -724,6 +762,10 @@ if (state->tls_verify_certificates && *state->tls_verify_certificates) } DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", cert_count); } + else + { + DEBUG(D_tls) debug_printf("TLS SNI: tls_verify_certificates unchanged\n"); + } if (setit_crl && state->tls_crl && *state->tls_crl) { @@ -735,6 +777,8 @@ if (state->tls_verify_certificates && *state->tls_verify_certificates) exim_gnutls_err_check(US"gnutls_certificate_set_x509_crl_file"); } } + DEBUG(D_tls) + if (!setit_crl) debug_printf("TLS SNI: tls_crl unchanged\n"); } /* statbuf.st_size */ } /* tls_verify_certificates */ @@ -1095,11 +1139,13 @@ return TRUE; * gnutls_global_set_log_function() * gnutls_global_set_log_level() 0..9 */ +#if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0 static void exim_gnutls_logger_cb(int level, const char *message) { DEBUG(D_tls) debug_printf("GnuTLS<%d>: %s\n", level, message); } +#endif /* Called after client hello, should handle SNI work. @@ -1127,7 +1173,18 @@ unsigned int sni_type; int rc, old_pool; rc = gnutls_server_name_get(session, sni_name, &data_len, &sni_type, 0); -exim_gnutls_err_debugreturn0("gnutls_server_name_get()"); +if (rc != GNUTLS_E_SUCCESS) + { + DEBUG(D_tls) { + if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + debug_printf("TLS: no SNI presented in handshake.\n"); + else + debug_printf("TLS failure: gnutls_server_name_get(): %s [%d]\n", + gnutls_strerror(rc), rc); + }; + return 0; + } + if (sni_type != GNUTLS_NAME_DNS) { DEBUG(D_tls) debug_printf("TLS: ignoring SNI of unhandled type %u\n", sni_type); @@ -1667,6 +1724,7 @@ Arguments: Returns a random number in range [0, max-1] */ +#ifdef HAVE_GNUTLS_RND int vaguely_random_number(int max) { @@ -1704,6 +1762,13 @@ for (p = smallbuf; needed_len; --needed_len, ++p) * smooth distribution and cares enough then they should submit a patch then. */ return r % max; } +#else /* HAVE_GNUTLS_RND */ +int +vaguely_random_number(int max) +{ + return vaguely_random_number_fallback(max); +} +#endif /* HAVE_GNUTLS_RND */