summaryrefslogtreecommitdiffstats
path: root/debian/patches/82_TLS-use-RFC-6125-rules-for-certifucate-name-checks-w.patch
blob: 10e54e3d287756c42a0f11103e7ae289df933a26 (plain)
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;