Merge branch 'debian'
[hcoop/debian/exim4.git] / debian / patches / 82_TLS-use-RFC-6125-rules-for-certifucate-name-checks-w.patch
diff --git a/debian/patches/82_TLS-use-RFC-6125-rules-for-certifucate-name-checks-w.patch b/debian/patches/82_TLS-use-RFC-6125-rules-for-certifucate-name-checks-w.patch
new file mode 100644 (file)
index 0000000..10e54e3
--- /dev/null
@@ -0,0 +1,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;