[exim-cvs] GnuTLS: simplify cert hostname checking

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] GnuTLS: simplify cert hostname checking
Gitweb: https://git.exim.org/exim.git/commitdiff/5fd28bb83f80141b9f7671ed9ae3e1a4263134e3
Commit:     5fd28bb83f80141b9f7671ed9ae3e1a4263134e3
Parent:     3fb3231cf83c8a9328499ea17b3663c1618210dc
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Tue Sep 18 15:05:59 2018 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Tue Sep 18 16:28:50 2018 +0100


    GnuTLS: simplify cert hostname checking
---
 doc/doc-docbook/spec.xfpt | 12 ++++++++++--
 src/src/tls-gnu.c         | 40 +++++++++++++++++++++++-----------------
 test/confs/2001           |  3 +++
 3 files changed, 36 insertions(+), 19 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index a93b394..8fde639 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -27773,7 +27773,7 @@ session with a client, you must set either &%tls_verify_hosts%& or
apply to all TLS connections. For any host that matches one of these options,
Exim requests a certificate as part of the setup of the TLS session. The
contents of the certificate are verified by comparing it with a list of
-expected certificates.
+expected trust-anchors or certificates.
These may be the system default set (depending on library version),
an explicit file or,
depending on library version, a directory, identified by
@@ -27790,6 +27790,9 @@ openssl x509 -hash -noout -in /cert/file
.endd
where &_/cert/file_& contains a single certificate.

+There is no checking of names of the client against the certificate
+Subject Name or Subject Alternate Names.
+
The difference between &%tls_verify_hosts%& and &%tls_try_verify_hosts%& is
what happens if the client does not supply a certificate, or if the certificate
does not match any of the certificates in the collection named by
@@ -27951,6 +27954,11 @@ The &%tls_verify_hosts%& and &%tls_try_verify_hosts%& options restrict
certificate verification to the listed servers. Verification either must
or need not succeed respectively.

+The &%tls_verify_cert_hostnames%& option lists hosts for which additional
+checks are made: that the host name (the one in the DNS A record)
+is valid for the certificate.
+The option defaults to always checking.
+
 The &(smtp)& transport has two OCSP-related options:
 &%hosts_require_ocsp%&; a host-list for which a Certificate Status
 is requested and required for the connection to proceed.  The default
@@ -28256,7 +28264,7 @@ this is appropriate for a single system, using a self-signed certificate.
 DANE-TA usage is effectively declaring a specific CA to be used; this might be a private CA or a public,
 well-known one.
 A private CA at simplest is just a self-signed certificate (with certain
-attributes) which is used to sign cerver certificates, but running one securely
+attributes) which is used to sign server certificates, but running one securely
 does require careful arrangement.
 With DANE-TA, as implemented in Exim and commonly in other MTAs,
 the server TLS handshake must transmit the entire certificate chain from CA to server-certificate.
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 9fcb50d..ff8064b 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -124,7 +124,7 @@ typedef struct exim_gnutls_state {
   BOOL            peer_dane_verified;
   BOOL            trigger_sni_changes;
   BOOL            have_set_peerdn;
-  const struct host_item *host;
+  const struct host_item *host;        /* NULL if server */
   gnutls_x509_crt_t    peercert;
   uschar        *peerdn;
   uschar        *ciphersuite;
@@ -1757,23 +1757,23 @@ if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))


 else
   {
-  if (state->exp_tls_verify_cert_hostnames)
+  /* Client side, check the server's certificate name versus the name on the
+  A-record for the connection we made.  What to do for server side - what name
+  to use for client?  We document that there is no such checking for server
+  side. */
+
+  if (  state->exp_tls_verify_cert_hostnames
+     && !gnutls_x509_crt_check_hostname(state->tlsp->peercert,
+        CS state->exp_tls_verify_cert_hostnames)
+     )
     {
-    int sep = 0;
-    const uschar * list = state->exp_tls_verify_cert_hostnames;
-    uschar * name;
-    while ((name = string_nextinlist(&list, &sep, NULL, 0)))
-      if (gnutls_x509_crt_check_hostname(state->tlsp->peercert, CS name))
-    break;
-    if (!name)
-      {
-      DEBUG(D_tls)
-    debug_printf("TLS certificate verification failed: cert name mismatch\n");
-      if (state->verify_requirement >= VERIFY_REQUIRED)
-    goto badcert;
-      return TRUE;
-      }
+    DEBUG(D_tls)
+      debug_printf("TLS certificate verification failed: cert name mismatch\n");
+    if (state->verify_requirement >= VERIFY_REQUIRED)
+      goto badcert;
+    return TRUE;
     }
+
   state->peer_cert_verified = TRUE;
   DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=\"%s\"\n",
       state->peerdn ? state->peerdn : US"<unset>");
@@ -2591,6 +2591,7 @@ else if (inbytes == 0)


else if (inbytes < 0)
{
+debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
record_io_error(state, (int) inbytes, US"recv", NULL);
state->xfer_error = TRUE;
return FALSE;
@@ -2718,7 +2719,11 @@ if (inbytes == 0)
{
DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
}
-else record_io_error(state, (int)inbytes, US"recv", NULL);
+else
+{
+debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+record_io_error(state, (int)inbytes, US"recv", NULL);
+}

 return -1;
 }
@@ -2765,6 +2770,7 @@ while (left > 0)
   DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes);
   if (outbytes < 0)
     {
+debug_printf("%s: err from gnutls_record_send(\n", __FUNCTION__);
     record_io_error(state, outbytes, US"send", NULL);
     return -1;
     }
diff --git a/test/confs/2001 b/test/confs/2001
index 9ab4cc3..715da4b 100644
--- a/test/confs/2001
+++ b/test/confs/2001
@@ -27,6 +27,9 @@ tls_verify_hosts = *
 tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}



+# so we can decode in wireshark
+tls_require_ciphers = NORMAL:-KX-ALL:+RSA
+
# ----- Routers -----

begin routers