X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/aa2a70baf1a7ae2d6c579094a188c1d30d3d5fd5..98716abe2b636d275e866f3ad6374cb70bf6e504:/src/src/tls-gnu.c diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 9d72ebc66..e2ac17c88 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 - 2014 */ +/* Copyright (c) University of Cambridge 1995 - 2015 */ /* See the file NOTICE for conditions of use and distribution. */ /* Copyright (c) Phil Pennock 2012 */ @@ -56,6 +56,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #else # undef SUPPORT_CA_DIR #endif +#if GNUTLS_VERSION_NUMBER >= 0x030314 +# define SUPPORT_SYSDEFAULT_CABUNDLE +#endif #ifndef DISABLE_OCSP # include @@ -117,9 +120,7 @@ typedef struct exim_gnutls_state { uschar *exp_tls_crl; uschar *exp_tls_require_ciphers; uschar *exp_tls_ocsp_file; -#ifdef EXPERIMENTAL_CERTNAMES - uschar *exp_tls_verify_cert_hostnames; -#endif + const uschar *exp_tls_verify_cert_hostnames; #ifdef EXPERIMENTAL_EVENT uschar *event_action; #endif @@ -138,9 +139,7 @@ static const exim_gnutls_state_st exim_gnutls_state_init = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -#ifdef EXPERIMENTAL_CERTNAMES - NULL, -#endif + NULL, #ifdef EXPERIMENTAL_EVENT NULL, #endif @@ -843,7 +842,7 @@ if ( !host /* server */ gnutls_certificate_set_ocsp_status_request_function(state->x509_cred, server_ocsp_stapling_cb, state->exp_tls_ocsp_file); - DEBUG(D_tls) debug_printf("Set OCSP response file %s\n", &state->exp_tls_ocsp_file); + DEBUG(D_tls) debug_printf("OCSP response file = %s\n", state->exp_tls_ocsp_file); } #endif @@ -858,6 +857,10 @@ if (state->tls_verify_certificates && *state->tls_verify_certificates) { if (!expand_check_tlsvar(tls_verify_certificates)) return DEFER; +#ifndef SUPPORT_SYSDEFAULT_CABUNDLE + if (Ustrcmp(state->exp_tls_verify_certificates, "system") == 0) + state->exp_tls_verify_certificates = NULL; +#endif if (state->tls_crl && *state->tls_crl) if (!expand_check_tlsvar(tls_crl)) return DEFER; @@ -878,58 +881,65 @@ else return OK; } -if (Ustat(state->exp_tls_verify_certificates, &statbuf) < 0) +#ifdef SUPPORT_SYSDEFAULT_CABUNDLE +if (Ustrcmp(state->exp_tls_verify_certificates, "system") == 0) + cert_count = gnutls_certificate_set_x509_system_trust(state->x509_cred); +else +#endif { - log_write(0, LOG_MAIN|LOG_PANIC, "could not stat %s " - "(tls_verify_certificates): %s", state->exp_tls_verify_certificates, - strerror(errno)); - return DEFER; - } + if (Ustat(state->exp_tls_verify_certificates, &statbuf) < 0) + { + log_write(0, LOG_MAIN|LOG_PANIC, "could not stat %s " + "(tls_verify_certificates): %s", state->exp_tls_verify_certificates, + strerror(errno)); + return DEFER; + } #ifndef SUPPORT_CA_DIR -/* The test suite passes in /dev/null; we could check for that path explicitly, -but who knows if someone has some weird FIFO which always dumps some certs, or -other weirdness. The thing we really want to check is that it's not a -directory, since while OpenSSL supports that, GnuTLS does not. -So s/!S_ISREG/S_ISDIR/ and change some messsaging ... */ -if (S_ISDIR(statbuf.st_mode)) - { - DEBUG(D_tls) - debug_printf("verify certificates path is a dir: \"%s\"\n", - state->exp_tls_verify_certificates); - log_write(0, LOG_MAIN|LOG_PANIC, - "tls_verify_certificates \"%s\" is a directory", - state->exp_tls_verify_certificates); - return DEFER; - } + /* The test suite passes in /dev/null; we could check for that path explicitly, + but who knows if someone has some weird FIFO which always dumps some certs, or + other weirdness. The thing we really want to check is that it's not a + directory, since while OpenSSL supports that, GnuTLS does not. + So s/!S_ISREG/S_ISDIR/ and change some messsaging ... */ + if (S_ISDIR(statbuf.st_mode)) + { + DEBUG(D_tls) + debug_printf("verify certificates path is a dir: \"%s\"\n", + state->exp_tls_verify_certificates); + log_write(0, LOG_MAIN|LOG_PANIC, + "tls_verify_certificates \"%s\" is a directory", + state->exp_tls_verify_certificates); + return DEFER; + } #endif -DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n", - state->exp_tls_verify_certificates, statbuf.st_size); + DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n", + state->exp_tls_verify_certificates, statbuf.st_size); -if (statbuf.st_size == 0) - { - DEBUG(D_tls) - debug_printf("cert file empty, no certs, no verification, ignoring any CRL\n"); - return OK; - } + if (statbuf.st_size == 0) + { + DEBUG(D_tls) + debug_printf("cert file empty, no certs, no verification, ignoring any CRL\n"); + return OK; + } -cert_count = + cert_count = #ifdef SUPPORT_CA_DIR - (statbuf.st_mode & S_IFMT) == S_IFDIR - ? - gnutls_certificate_set_x509_trust_dir(state->x509_cred, - CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM) - : + (statbuf.st_mode & S_IFMT) == S_IFDIR + ? + gnutls_certificate_set_x509_trust_dir(state->x509_cred, + CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM) + : #endif - gnutls_certificate_set_x509_trust_file(state->x509_cred, - CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM); + gnutls_certificate_set_x509_trust_file(state->x509_cred, + CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM); + } if (cert_count < 0) { rc = cert_count; - exim_gnutls_err_check(US"gnutls_certificate_set_x509_trust_file"); + exim_gnutls_err_check(US"setting certificate trust"); } DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", cert_count); @@ -1385,11 +1395,10 @@ if (rc < 0 || else { -#ifdef EXPERIMENTAL_CERTNAMES if (state->exp_tls_verify_cert_hostnames) { int sep = 0; - uschar * list = state->exp_tls_verify_cert_hostnames; + const uschar * list = state->exp_tls_verify_cert_hostnames; uschar * name; while (name = string_nextinlist(&list, &sep, NULL, 0)) if (gnutls_x509_crt_check_hostname(state->tlsp->peercert, CS name)) @@ -1407,7 +1416,6 @@ else return TRUE; } } -#endif state->peer_cert_verified = TRUE; DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=\"%s\"\n", state->peerdn ? state->peerdn : US""); @@ -1771,21 +1779,23 @@ return OK; -#ifdef EXPERIMENTAL_CERTNAMES static void tls_client_setup_hostname_checks(host_item * host, exim_gnutls_state_st * state, smtp_transport_options_block * ob) { -if (verify_check_this_host(&ob->tls_verify_cert_hostnames, NULL, - host->name, host->address, NULL) == OK) +if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK) { - state->exp_tls_verify_cert_hostnames = host->name; + state->exp_tls_verify_cert_hostnames = +#ifdef EXPERIMENTAL_INTERNATIONAL + string_domain_utf8_to_alabel(host->name, NULL); +#else + host->name; +#endif DEBUG(D_tls) debug_printf("TLS: server cert verification includes hostname: \"%s\".\n", state->exp_tls_verify_cert_hostnames); } } -#endif /************************************************* @@ -1819,11 +1829,10 @@ int rc; const char *error; exim_gnutls_state_st *state = NULL; #ifndef DISABLE_OCSP -BOOL require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp, - NULL, host->name, host->address, NULL) == OK; +BOOL require_ocsp = + verify_check_given_host(&ob->hosts_require_ocsp, host) == OK; BOOL request_ocsp = require_ocsp ? TRUE - : verify_check_this_host(&ob->hosts_request_ocsp, - NULL, host->name, host->address, NULL) == OK; + : verify_check_given_host(&ob->hosts_request_ocsp, host) == OK; #endif DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd); @@ -1856,26 +1865,20 @@ the specified host patterns if one of them is defined */ if ( ( state->exp_tls_verify_certificates && !ob->tls_verify_hosts - && !ob->tls_try_verify_hosts + && (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts) ) - || verify_check_this_host(&ob->tls_verify_hosts, NULL, - host->name, host->address, NULL) == OK + || verify_check_given_host(&ob->tls_verify_hosts, host) == OK ) { -#ifdef EXPERIMENTAL_CERTNAMES tls_client_setup_hostname_checks(host, state, ob); -#endif DEBUG(D_tls) debug_printf("TLS: server certificate verification required.\n"); state->verify_requirement = VERIFY_REQUIRED; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE); } -else if (verify_check_this_host(&ob->tls_try_verify_hosts, NULL, - host->name, host->address, NULL) == OK) +else if (verify_check_given_host(&ob->tls_try_verify_hosts, host) == OK) { -#ifdef EXPERIMENTAL_CERTNAMES tls_client_setup_hostname_checks(host, state, ob); -#endif DEBUG(D_tls) debug_printf("TLS: server certificate verification optional.\n"); state->verify_requirement = VERIFY_OPTIONAL;