X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Ftls-gnu.c;h=ff8064babc1e36ad2ef90efdb8e2ce5607787910;hb=5fd28bb83f80141b9f7671ed9ae3e1a4263134e3;hp=dfe09200b57f07ba7fb0be38c443b6f522bd9ee3;hpb=afdb5e9cf07fa49e26e128d8d5d2e3cab7a5fe42;p=exim.git diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index dfe09200b..ff8064bab 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -124,7 +124,7 @@ typedef struct exim_gnutls_state { BOOL peer_dane_verified; BOOL trigger_sni_changes; BOOL have_set_peerdn; - const struct host_item *host; + const struct host_item *host; /* NULL if server */ gnutls_x509_crt_t peercert; uschar *peerdn; uschar *ciphersuite; @@ -1625,8 +1625,7 @@ else # ifdef GNUTLS_BROKEN_DANE_VALIDATION /* Split the TLSA records into two sets, TA and EE selectors. Run the dane-verification separately so that we know which selector verified; - then we know whether to do CA-chain-verification and name-verification - (needed for TA but not EE). */ + then we know whether to do name-verification (needed for TA but not EE). */ if (usage == ((1<peer_dane_verified = TRUE; # ifdef GNUTLS_BROKEN_DANE_VALIDATION /* If a TA-mode TLSA record was used for verification we must additionally - verify the CA chain and the cert name. For EE-mode, skip it. */ + verify the cert name (but not the CA chain). For EE-mode, skip it. */ if (usage & (1 << DANESSL_USAGE_DANE_EE)) # endif { - state->peer_cert_verified = TRUE; + state->peer_dane_verified = state->peer_cert_verified = TRUE; goto goodcert; } +# ifdef GNUTLS_BROKEN_DANE_VALIDATION + /* Assume that the name on the A-record is the one that should be matching + the cert. An alternate view is that the domain part of the email address + is also permissible. */ + + if (gnutls_x509_crt_check_hostname(state->tlsp->peercert, + CS state->host->name)) + { + state->peer_dane_verified = state->peer_cert_verified = TRUE; + goto goodcert; + } +# endif } -#endif +#endif /*SUPPORT_DANE*/ rc = gnutls_certificate_verify_peers2(state->session, &verify); } @@ -1747,23 +1757,23 @@ if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) else { - if (state->exp_tls_verify_cert_hostnames) + /* Client side, check the server's certificate name versus the name on the + A-record for the connection we made. What to do for server side - what name + to use for client? We document that there is no such checking for server + side. */ + + if ( state->exp_tls_verify_cert_hostnames + && !gnutls_x509_crt_check_hostname(state->tlsp->peercert, + CS state->exp_tls_verify_cert_hostnames) + ) { - int sep = 0; - 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)) - break; - if (!name) - { - DEBUG(D_tls) - debug_printf("TLS certificate verification failed: cert name mismatch\n"); - if (state->verify_requirement >= VERIFY_REQUIRED) - goto badcert; - return TRUE; - } + DEBUG(D_tls) + debug_printf("TLS certificate verification failed: cert name mismatch\n"); + if (state->verify_requirement >= VERIFY_REQUIRED) + goto badcert; + return TRUE; } + state->peer_cert_verified = TRUE; DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=\"%s\"\n", state->peerdn ? state->peerdn : US""); @@ -1775,7 +1785,8 @@ goodcert: #ifdef SUPPORT_DANE tlsa_prob: - *errstr = string_sprintf("TLSA record problem: %s", dane_strerror(rc)); + *errstr = string_sprintf("TLSA record problem: %s", + rc == DANE_E_REQUESTED_DATA_NOT_AVAILABLE ? "none usable" : dane_strerror(rc)); #endif badcert: @@ -2147,7 +2158,7 @@ static void tls_client_setup_hostname_checks(host_item * host, exim_gnutls_state_st * state, smtp_transport_options_block * ob) { -if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK) +if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) { state->exp_tls_verify_cert_hostnames = #ifdef SUPPORT_I18N @@ -2273,9 +2284,9 @@ uschar *cipher_list = NULL; #ifndef DISABLE_OCSP BOOL require_ocsp = - verify_check_given_host(&ob->hosts_require_ocsp, host) == OK; + verify_check_given_host(CUSS &ob->hosts_require_ocsp, host) == OK; BOOL request_ocsp = require_ocsp ? TRUE - : verify_check_given_host(&ob->hosts_request_ocsp, host) == OK; + : verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK; #endif DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd); @@ -2335,7 +2346,7 @@ else && !ob->tls_verify_hosts && (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts) ) - || verify_check_given_host(&ob->tls_verify_hosts, host) == OK + || verify_check_given_host(CUSS &ob->tls_verify_hosts, host) == OK ) { tls_client_setup_hostname_checks(host, state, ob); @@ -2344,7 +2355,7 @@ else state->verify_requirement = VERIFY_REQUIRED; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE); } -else if (verify_check_given_host(&ob->tls_try_verify_hosts, host) == OK) +else if (verify_check_given_host(CUSS &ob->tls_try_verify_hosts, host) == OK) { tls_client_setup_hostname_checks(host, state, ob); DEBUG(D_tls) @@ -2580,6 +2591,7 @@ else if (inbytes == 0) else if (inbytes < 0) { +debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__); record_io_error(state, (int) inbytes, US"recv", NULL); state->xfer_error = TRUE; return FALSE; @@ -2707,7 +2719,11 @@ if (inbytes == 0) { DEBUG(D_tls) debug_printf("Got TLS_EOF\n"); } -else record_io_error(state, (int)inbytes, US"recv", NULL); +else +{ +debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__); +record_io_error(state, (int)inbytes, US"recv", NULL); +} return -1; } @@ -2754,6 +2770,7 @@ while (left > 0) DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes); if (outbytes < 0) { +debug_printf("%s: err from gnutls_record_send(\n", __FUNCTION__); record_io_error(state, outbytes, US"send", NULL); return -1; }