Commit | Line | Data |
---|---|---|
0c0c20aa AM |
1 | Description: TLS: use RFC 6125 rules for certificate name checks when |
2 | CNAMES are present. Bug 2594 | |
3 | Origin: upstream https://git.exim.org/exim.git/commit/0851a3bbf4667081d47f5d85b6b3a5cb33cbdba6 | |
4 | Bug: https://bugs.exim.org/show_bug.cgi?id=2594 | |
5 | Forwarded: not-needed | |
6 | Last-Update: 2021-03-02 | |
7 | ||
8 | --- a/doc/ChangeLog | |
9 | +++ b/doc/ChangeLog | |
10 | @@ -41,10 +41,15 @@ JH/10 OpenSSL: Fix aggregation of messag | |
11 | ||
12 | JH/11 Harden plaintext authenticator against a badly misconfigured client-send | |
13 | string. Previously it was possible to cause undefined behaviour in a | |
14 | library routine (usually a crash). Found by "zerons". | |
15 | ||
16 | +JH/06 Bug 2594: Change the name used for certificate name checks in the smtp | |
17 | + transport. Previously it was the name on the DNS A-record; use instead | |
18 | + the head of the CNAME chain leading there (if there is one). This seems | |
19 | + to align better with RFC 6125. | |
20 | + | |
21 | ||
22 | JH/18 GnuTLS: fix $tls_out_ocsp under hosts_request_ocsp. Previously the | |
23 | verification result was not updated unless hosts_require_ocsp applied. | |
24 | ||
25 | JH/20 Bug 2389: fix server advertising of usable certificates, under GnuTLS in | |
26 | --- a/src/host.c | |
27 | +++ b/src/host.c | |
28 | @@ -1966,10 +1966,17 @@ host_item *last = NULL; | |
29 | BOOL temp_error = FALSE; | |
30 | #if HAVE_IPV6 | |
31 | int af; | |
32 | #endif | |
33 | ||
34 | +#ifndef DISABLE_TLS | |
35 | +/* Copy the host name at this point to the value which is used for | |
36 | +TLS certificate name checking, before anything modifies it. */ | |
37 | + | |
38 | +host->certname = host->name; | |
39 | +#endif | |
40 | + | |
41 | /* Make sure DNS options are set as required. This appears to be necessary in | |
42 | some circumstances when the get..byname() function actually calls the DNS. */ | |
43 | ||
44 | dns_init((flags & HOST_FIND_QUALIFY_SINGLE) != 0, | |
45 | (flags & HOST_FIND_SEARCH_PARENTS) != 0, | |
46 | @@ -2132,10 +2139,13 @@ for (i = 1; i <= times; | |
47 | ||
48 | else | |
49 | { | |
50 | host_item *next = store_get(sizeof(host_item)); | |
51 | next->name = host->name; | |
52 | +#ifndef DISABLE_TLS | |
53 | + next->certname = host->certname; | |
54 | +#endif | |
55 | next->mx = host->mx; | |
56 | next->address = text_address; | |
57 | next->port = PORT_NONE; | |
58 | next->status = hstatus_unknown; | |
59 | next->why = hwhy_unknown; | |
60 | @@ -2150,16 +2160,16 @@ for (i = 1; i <= times; | |
61 | ||
62 | /* If no hosts were found, the address field in the original host block will be | |
63 | NULL. If temp_error is set, at least one of the lookups gave a temporary error, | |
64 | so we pass that back. */ | |
65 | ||
66 | -if (host->address == NULL) | |
67 | +if (!host->address) | |
68 | { | |
69 | uschar *msg = | |
70 | #ifndef STAND_ALONE | |
71 | - (message_id[0] == 0 && smtp_in != NULL)? | |
72 | - string_sprintf("no IP address found for host %s (during %s)", host->name, | |
73 | + message_id[0] == 0 && smtp_in | |
74 | + ? string_sprintf("no IP address found for host %s (during %s)", host->name, | |
75 | smtp_get_connection_info()) : | |
76 | #endif | |
77 | string_sprintf("no IP address found for host %s", host->name); | |
78 | ||
79 | HDEBUG(D_host_lookup) debug_printf("%s\n", msg); | |
80 | @@ -2277,10 +2287,17 @@ dns_record *rr; | |
81 | host_item *thishostlast = NULL; /* Indicates not yet filled in anything */ | |
82 | BOOL v6_find_again = FALSE; | |
83 | BOOL dnssec_fail = FALSE; | |
84 | int i; | |
85 | ||
86 | +#ifndef DISABLE_TLS | |
87 | +/* Copy the host name at this point to the value which is used for | |
88 | +TLS certificate name checking, before any CNAME-following modifies it. */ | |
89 | + | |
90 | +host->certname = host->name; | |
91 | +#endif | |
92 | + | |
93 | /* If allow_ip is set, a name which is an IP address returns that value | |
94 | as its address. This is used for MX records when allow_mx_to_ip is set, for | |
95 | those sites that feel they have to flaunt the RFC rules. */ | |
96 | ||
97 | if (allow_ip && string_is_ip_address(host->name, NULL) != 0) | |
98 | --- a/src/structs.h | |
99 | +++ b/src/structs.h | |
100 | @@ -77,18 +77,21 @@ host addresses is done using this struct | |
101 | ||
102 | typedef enum {DS_UNK=-1, DS_NO, DS_YES} dnssec_status_t; | |
103 | ||
104 | typedef struct host_item { | |
105 | struct host_item *next; | |
106 | - const uschar *name; /* Host name */ | |
107 | - const uschar *address; /* IP address in text form */ | |
108 | - int port; /* port value in host order (if SRV lookup) */ | |
109 | - int mx; /* MX value if found via MX records */ | |
110 | - int sort_key; /* MX*1000 plus random "fraction" */ | |
111 | - int status; /* Usable, unusable, or unknown */ | |
112 | - int why; /* Why host is unusable */ | |
113 | - int last_try; /* Time of last try if known */ | |
114 | + const uschar *name; /* Host name */ | |
115 | +#ifndef DISABLE_TLS | |
116 | + const uschar *certname; /* Name used for certificate checks */ | |
117 | +#endif | |
118 | + const uschar *address; /* IP address in text form */ | |
119 | + int port; /* port value in host order (if SRV lookup) */ | |
120 | + int mx; /* MX value if found via MX records */ | |
121 | + int sort_key; /* MX*1000 plus random "fraction" */ | |
122 | + int status; /* Usable, unusable, or unknown */ | |
123 | + int why; /* Why host is unusable */ | |
124 | + int last_try; /* Time of last try if known */ | |
125 | dnssec_status_t dnssec; | |
126 | } host_item; | |
127 | ||
128 | /* Chain of rewrite rules, read from the rewrite config, or parsed from the | |
129 | rewrite_headers field of a transport. */ | |
130 | --- a/src/tls-gnu.c | |
131 | +++ b/src/tls-gnu.c | |
132 | @@ -2191,13 +2191,13 @@ tls_client_setup_hostname_checks(host_it | |
133 | { | |
134 | if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) | |
135 | { | |
136 | state->exp_tls_verify_cert_hostnames = | |
137 | #ifdef SUPPORT_I18N | |
138 | - string_domain_utf8_to_alabel(host->name, NULL); | |
139 | + string_domain_utf8_to_alabel(host->certname, NULL); | |
140 | #else | |
141 | - host->name; | |
142 | + host->certname; | |
143 | #endif | |
144 | DEBUG(D_tls) | |
145 | debug_printf("TLS: server cert verification includes hostname: \"%s\".\n", | |
146 | state->exp_tls_verify_cert_hostnames); | |
147 | } | |
148 | --- a/src/tls-openssl.c | |
149 | +++ b/src/tls-openssl.c | |
150 | @@ -309,18 +309,18 @@ typedef struct tls_ext_ctx_cb { | |
151 | X509_STORE *verify_store; /* non-null if status requested */ | |
152 | BOOL verify_required; | |
153 | } client; | |
154 | } u_ocsp; | |
155 | #endif | |
156 | - uschar *dhparam; | |
157 | + uschar * dhparam; | |
158 | /* these are cached from first expand */ | |
159 | - uschar *server_cipher_list; | |
160 | + uschar * server_cipher_list; | |
161 | /* only passed down to tls_error: */ | |
162 | - host_item *host; | |
163 | + host_item * host; | |
164 | const uschar * verify_cert_hostnames; | |
165 | #ifndef DISABLE_EVENT | |
166 | - uschar * event_action; | |
167 | + uschar * event_action; | |
168 | #endif | |
169 | } tls_ext_ctx_cb; | |
170 | ||
171 | /* should figure out a cleanup of API to handle state preserved per | |
172 | implementation, for various reasons, which can be void * in the APIs. | |
173 | @@ -2359,13 +2359,13 @@ if ((rc = setup_certs(ctx, ob->tls_verif | |
174 | ||
175 | if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) | |
176 | { | |
177 | cbinfo->verify_cert_hostnames = | |
178 | #ifdef SUPPORT_I18N | |
179 | - string_domain_utf8_to_alabel(host->name, NULL); | |
180 | + string_domain_utf8_to_alabel(host->certname, NULL); | |
181 | #else | |
182 | - host->name; | |
183 | + host->certname; | |
184 | #endif | |
185 | DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", | |
186 | cbinfo->verify_cert_hostnames); | |
187 | } | |
188 | return OK; |