1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
Description: TLS: use RFC 6125 rules for certificate name checks when
CNAMES are present. Bug 2594
Origin: upstream https://git.exim.org/exim.git/commit/0851a3bbf4667081d47f5d85b6b3a5cb33cbdba6
Bug: https://bugs.exim.org/show_bug.cgi?id=2594
Forwarded: not-needed
Last-Update: 2021-03-02
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -41,10 +41,15 @@ JH/10 OpenSSL: Fix aggregation of messag
JH/11 Harden plaintext authenticator against a badly misconfigured client-send
string. Previously it was possible to cause undefined behaviour in a
library routine (usually a crash). Found by "zerons".
+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.
+
JH/18 GnuTLS: fix $tls_out_ocsp under hosts_request_ocsp. Previously the
verification result was not updated unless hosts_require_ocsp applied.
JH/20 Bug 2389: fix server advertising of usable certificates, under GnuTLS in
--- a/src/host.c
+++ b/src/host.c
@@ -1966,10 +1966,17 @@ host_item *last = NULL;
BOOL temp_error = FALSE;
#if HAVE_IPV6
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. */
dns_init((flags & HOST_FIND_QUALIFY_SINGLE) != 0,
(flags & HOST_FIND_SEARCH_PARENTS) != 0,
@@ -2132,10 +2139,13 @@ for (i = 1; i <= times;
else
{
host_item *next = store_get(sizeof(host_item));
next->name = host->name;
+#ifndef DISABLE_TLS
+ next->certname = host->certname;
+#endif
next->mx = host->mx;
next->address = text_address;
next->port = PORT_NONE;
next->status = hstatus_unknown;
next->why = hwhy_unknown;
@@ -2150,16 +2160,16 @@ for (i = 1; i <= times;
/* If no hosts were found, the address field in the original host block will be
NULL. If temp_error is set, at least one of the lookups gave a temporary error,
so we pass that back. */
-if (host->address == NULL)
+if (!host->address)
{
uschar *msg =
#ifndef STAND_ALONE
- (message_id[0] == 0 && smtp_in != NULL)?
- string_sprintf("no IP address found for host %s (during %s)", host->name,
+ message_id[0] == 0 && smtp_in
+ ? string_sprintf("no IP address found for host %s (during %s)", host->name,
smtp_get_connection_info()) :
#endif
string_sprintf("no IP address found for host %s", host->name);
HDEBUG(D_host_lookup) debug_printf("%s\n", msg);
@@ -2277,10 +2287,17 @@ dns_record *rr;
host_item *thishostlast = NULL; /* Indicates not yet filled in anything */
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. */
if (allow_ip && string_is_ip_address(host->name, NULL) != 0)
--- a/src/structs.h
+++ b/src/structs.h
@@ -77,18 +77,21 @@ host addresses is done using this struct
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;
/* Chain of rewrite rules, read from the rewrite config, or parsed from the
rewrite_headers field of a transport. */
--- a/src/tls-gnu.c
+++ b/src/tls-gnu.c
@@ -2191,13 +2191,13 @@ tls_client_setup_hostname_checks(host_it
{
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",
state->exp_tls_verify_cert_hostnames);
}
--- a/src/tls-openssl.c
+++ b/src/tls-openssl.c
@@ -309,18 +309,18 @@ typedef struct tls_ext_ctx_cb {
X509_STORE *verify_store; /* non-null if status requested */
BOOL verify_required;
} 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;
/* should figure out a cleanup of API to handle state preserved per
implementation, for various reasons, which can be void * in the APIs.
@@ -2359,13 +2359,13 @@ if ((rc = setup_certs(ctx, ob->tls_verif
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);
}
return OK;
|