From 3fe5ec41e81831028c992f77a15292872fbbac75 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Thu, 11 Jun 2020 20:45:05 +0100 Subject: [PATCH 10/26] TLS: use RFC 6125 rules for certifucate name checks when CNAMES are present. Bug 2594 (cherry picked from commit 0851a3bbf4667081d47f5d85b6b3a5cb33cbdba6) --- doc/ChangeLog | 7 ++- src/host.c | 17 +++++++ src/structs.h | 19 ++++---- src/tls-gnu.c | 4 +- src/tls-openssl.c | 20 ++++----- diff --git doc/ChangeLog doc/ChangeLog index b9c1ec29e..612005803 100644 --- doc/ChangeLog +++ doc/ChangeLog @@ -26,6 +26,11 @@ JH/05 Bug 2593: Fix "vacation" in Exim filter. Previously, when a "once" path, an error occurred on trying to open it. Use the transport's working directory. +JH/06 Bug 2594: Change the name used for certificate name checks in the smtp + transport. Previously it was the name on the DNS A-record; use instead + the head of the CNAME chain leading there (if there is one). This seems + to align better with RFC 6125. + Exim version 4.94 ----------------- @@ -331,7 +336,7 @@ JH/20 Bug 2389: fix server advertising of usable certificates, under GnuTLS in JH/21 The smtp transport option "hosts_noproxy_tls" is now unset by default. A single TCP connection by a client will now hold a TLS connection open - for multiple message deliveries, by default. Previoud the default was to + for multiple message deliveries, by default. Previously the default was to not do so. JH/22 The smtp transport option "hosts_try_dane" now enables all hosts by diff --git src/host.c src/host.c index 0e0e0130b..817d4446c 100644 --- src/host.c +++ src/host.c @@ -1950,6 +1950,13 @@ BOOL temp_error = FALSE; int af; #endif +#ifndef DISABLE_TLS +/* Copy the host name at this point to the value which is used for +TLS certificate name checking, before anything modifies it. */ + +host->certname = host->name; +#endif + /* Make sure DNS options are set as required. This appears to be necessary in some circumstances when the get..byname() function actually calls the DNS. */ @@ -2117,6 +2124,9 @@ for (int i = 1; i <= times; { host_item *next = store_get(sizeof(host_item), FALSE); next->name = host->name; +#ifndef DISABLE_TLS + next->certname = host->certname; +#endif next->mx = host->mx; next->address = text_address; next->port = PORT_NONE; @@ -2260,6 +2270,13 @@ BOOL v6_find_again = FALSE; BOOL dnssec_fail = FALSE; int i; +#ifndef DISABLE_TLS +/* Copy the host name at this point to the value which is used for +TLS certificate name checking, before any CNAME-following modifies it. */ + +host->certname = host->name; +#endif + /* If allow_ip is set, a name which is an IP address returns that value as its address. This is used for MX records when allow_mx_to_ip is set, for those sites that feel they have to flaunt the RFC rules. */ diff --git src/structs.h src/structs.h index c6700d513..206237f04 100644 --- src/structs.h +++ src/structs.h @@ -80,14 +80,17 @@ typedef enum {DS_UNK=-1, DS_NO, DS_YES} dnssec_status_t; typedef struct host_item { struct host_item *next; - const uschar *name; /* Host name */ - const uschar *address; /* IP address in text form */ - int port; /* port value in host order (if SRV lookup) */ - int mx; /* MX value if found via MX records */ - int sort_key; /* MX*1000 plus random "fraction" */ - int status; /* Usable, unusable, or unknown */ - int why; /* Why host is unusable */ - int last_try; /* Time of last try if known */ + const uschar *name; /* Host name */ +#ifndef DISABLE_TLS + const uschar *certname; /* Name used for certificate checks */ +#endif + const uschar *address; /* IP address in text form */ + int port; /* port value in host order (if SRV lookup) */ + int mx; /* MX value if found via MX records */ + int sort_key; /* MX*1000 plus random "fraction" */ + int status; /* Usable, unusable, or unknown */ + int why; /* Why host is unusable */ + int last_try; /* Time of last try if known */ dnssec_status_t dnssec; } host_item; diff --git src/tls-gnu.c src/tls-gnu.c index 24114f05e..875c82efa 100644 --- src/tls-gnu.c +++ src/tls-gnu.c @@ -2601,9 +2601,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) { state->exp_tls_verify_cert_hostnames = #ifdef SUPPORT_I18N - string_domain_utf8_to_alabel(host->name, NULL); + string_domain_utf8_to_alabel(host->certname, NULL); #else - host->name; + host->certname; #endif DEBUG(D_tls) debug_printf("TLS: server cert verification includes hostname: \"%s\".\n", diff --git src/tls-openssl.c src/tls-openssl.c index 8c9d8aa69..a62322928 100644 --- src/tls-openssl.c +++ src/tls-openssl.c @@ -372,10 +372,10 @@ typedef struct ocsp_resp { } ocsp_resplist; typedef struct tls_ext_ctx_cb { - tls_support * tlsp; - uschar *certificate; - uschar *privatekey; - BOOL is_server; + tls_support * tlsp; + uschar * certificate; + uschar * privatekey; + BOOL is_server; #ifndef DISABLE_OCSP STACK_OF(X509) *verify_stack; /* chain for verifying the proof */ union { @@ -390,14 +390,14 @@ typedef struct tls_ext_ctx_cb { } client; } u_ocsp; #endif - uschar *dhparam; + uschar * dhparam; /* these are cached from first expand */ - uschar *server_cipher_list; + uschar * server_cipher_list; /* only passed down to tls_error: */ - host_item *host; + host_item * host; const uschar * verify_cert_hostnames; #ifndef DISABLE_EVENT - uschar * event_action; + uschar * event_action; #endif } tls_ext_ctx_cb; @@ -2915,9 +2915,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) { cbinfo->verify_cert_hostnames = #ifdef SUPPORT_I18N - string_domain_utf8_to_alabel(host->name, NULL); + string_domain_utf8_to_alabel(host->certname, NULL); #else - host->name; + host->certname; #endif DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", cbinfo->verify_cert_hostnames); -- 2.24.3 (Apple Git-128)