Support optional server certificate name checking. Bug 1479
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 20 May 2014 20:25:10 +0000 (21:25 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 20 May 2014 20:25:10 +0000 (21:25 +0100)
Enable EXPERIMENTAL_CERTNAMES to include.

24 files changed:
doc/doc-txt/experimental-spec.txt
src/src/EDITME
src/src/config.h.defaults
src/src/exim.c
src/src/functions.h
src/src/tls-gnu.c
src/src/tls-openssl.c
src/src/tls.c
src/src/tlscert-gnu.c
src/src/tlscert-openssl.c
src/src/transports/smtp.c
src/src/transports/smtp.h
test/confs/2012
test/confs/2112
test/confs/5440 [new file with mode: 0644]
test/confs/5450 [new file with mode: 0644]
test/log/2012
test/log/2112
test/log/5440 [new file with mode: 0644]
test/log/5450 [new file with mode: 0644]
test/scripts/5440-certnames-GnuTLS/5440 [new file with mode: 0644]
test/scripts/5440-certnames-GnuTLS/REQUIRES [new file with mode: 0644]
test/scripts/5450-certnames-OpenSSL/5450 [new file with mode: 0644]
test/scripts/5450-certnames-OpenSSL/REQUIRES [new file with mode: 0644]

index d8c26bf931063dd131dc3ab37170bd1052d62c24..58854345420d60d97ee58f20cf268f2fd2f41402 100644 (file)
@@ -1147,6 +1147,25 @@ QUIT
 
 
 
+Certificate name checking
+--------------------------------------------------------------
+The X509 certificates used for TLS are supposed be verified
+that they are owned by the expected host.  The coding of TLS
+support to date has not made these checks.
+
+If built with EXPERIMENTAL_CERTNAMES defined, code is
+included to do so, and a new smtp transport option
+"tls_verify_cert_hostname" supported which takes a list of
+names for which the checks must be made.  The host must
+also be in "tls_verify_hosts".
+
+Both Subject and Subject-Alternate-Name certificate fields
+are supported, as are wildcard certificates (limited to
+a single wildcard being the initial component of a 3-or-more
+component FQDN).
+
+
+
 --------------------------------------------------------------
 End of file
 --------------------------------------------------------------
index 7d58af74418bccc5c81cc2cc5a730b60603bce21..83ca43cd1ab2d3407e25a69bcbf8e7cacc17eb47 100644 (file)
@@ -485,6 +485,10 @@ EXIM_MONITOR=eximon.bin
 # Uncomment the following line to enable Experimental Proxy Protocol
 # EXPERIMENTAL_PROXY=yes
 
+# Uncomment the following line to enable support for checking certiticate
+# ownership
+# EXPERIMENTAL_CERTNAMES=yes
+
 
 ###############################################################################
 #                 THESE ARE THINGS YOU MIGHT WANT TO SPECIFY                  #
index 69df842e73281f3dfad7b094f8fd0f1a5fa81147..3ab73d861c48a22348bea9f9b43f3ce243be2a03 100644 (file)
@@ -165,6 +165,7 @@ it's a default value. */
 
 /* EXPERIMENTAL features */
 #define EXPERIMENTAL_BRIGHTMAIL
+#define EXPERIMENTAL_CERTNAMES
 #define EXPERIMENTAL_DCC
 #define EXPERIMENTAL_DMARC
 #define EXPERIMENTAL_OCSP
index ded12fa34d62a5735d396b0ad122192d9152a3a9..bca6cc8a4fbd39c6e4e56dd5236445c6d7ddb0d8 100644 (file)
@@ -831,6 +831,9 @@ fprintf(f, "Support for:");
 #ifdef EXPERIMENTAL_REDIS
   fprintf(f, " Experimental_Redis");
 #endif
+#ifdef EXPERIMENTAL_CERTNAMES
+  fprintf(f, " Experimental_Certnames");
+#endif
 fprintf(f, "\n");
 
 fprintf(f, "Lookups (built-in):");
index 741b632a9e200b2c08261d8751fac968eb6ba01a..a6257a913cabe7afbe8ef98f1fe1e5e8837c1e68 100644 (file)
@@ -59,10 +59,13 @@ extern int     tls_ungetc(int);
 extern int     tls_write(BOOL, const uschar *, size_t);
 extern uschar *tls_validate_require_cipher(void);
 extern void    tls_version_report(FILE *);
-#ifndef USE_GNUTLS
+# ifndef USE_GNUTLS
 extern BOOL    tls_openssl_options_parse(uschar *, long *);
-#endif
+# endif
 extern uschar * tls_field_from_dn(uschar *, uschar *);
+# ifdef EXPERIMENTAL_CERTNAMES
+extern BOOL    tls_is_name_for_cert(uschar *, void *);
+# endif
 #endif /*SUPPORT_TLS*/
 
 
index 3c926c0d4ab3f515a1aa13ffb647d5838a7439ce..af43686e42fde592d7711404586436264808705e 100644 (file)
@@ -60,7 +60,12 @@ Changes:
 
 /* Values for verify_requirement */
 
-enum peer_verify_requirement { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED };
+enum peer_verify_requirement
+  { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED
+#ifdef EXPERIMENTAL_CERTNAMES
+    ,VERIFY_WITHHOST
+#endif
+  };
 
 /* This holds most state for server or client; with this, we can set up an
 outbound TLS-enabled connection in an ACL callout, while not stomping all
@@ -95,6 +100,7 @@ typedef struct exim_gnutls_state {
   const uschar *tls_verify_certificates;
   const uschar *tls_crl;
   const uschar *tls_require_ciphers;
+
   uschar *exp_tls_certificate;
   uschar *exp_tls_privatekey;
   uschar *exp_tls_sni;
@@ -102,6 +108,9 @@ typedef struct exim_gnutls_state {
   uschar *exp_tls_crl;
   uschar *exp_tls_require_ciphers;
   uschar *exp_tls_ocsp_file;
+#ifdef EXPERIMENTAL_CERTNAMES
+  uschar *exp_tls_verify_cert_hostnames;
+#endif
 
   tls_support *tlsp;   /* set in tls_init() */
 
@@ -117,6 +126,9 @@ static const exim_gnutls_state_st exim_gnutls_state_init = {
   NULL, NULL, NULL, NULL,
   NULL, NULL, NULL, NULL, NULL, NULL,
   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+#ifdef EXPERIMENTAL_CERTNAMES
+                                            NULL,
+#endif
   NULL,
   NULL, 0, 0, 0, 0,
 };
@@ -178,18 +190,18 @@ before, for now. */
 #define expand_check_tlsvar(Varname) expand_check(state->Varname, US #Varname, &state->exp_##Varname)
 
 #if GNUTLS_VERSION_NUMBER >= 0x020c00
-#define HAVE_GNUTLS_SESSION_CHANNEL_BINDING
-#define HAVE_GNUTLS_SEC_PARAM_CONSTANTS
-#define HAVE_GNUTLS_RND
+# define HAVE_GNUTLS_SESSION_CHANNEL_BINDING
+# define HAVE_GNUTLS_SEC_PARAM_CONSTANTS
+# define HAVE_GNUTLS_RND
 /* The security fix we provide with the gnutls_allow_auto_pkcs11 option
  * (4.82 PP/09) introduces a compatibility regression. The symbol simply
  * isn't available sometimes, so this needs to become a conditional
  * compilation; the sanest way to deal with this being a problem on
  * older OSes is to block it in the Local/Makefile with this compiler
  * definition  */
-#ifndef AVOID_GNUTLS_PKCS11
-#define HAVE_GNUTLS_PKCS11
-#endif /* AVOID_GNUTLS_PKCS11 */
+# ifndef AVOID_GNUTLS_PKCS11
+#  define HAVE_GNUTLS_PKCS11
+# endif /* AVOID_GNUTLS_PKCS11 */
 #endif
 
 
@@ -294,10 +306,16 @@ tls_error(when, msg, state->host);
 *        Set various Exim expansion vars         *
 *************************************************/
 
-#define exim_gnutls_cert_err(Label) do { \
-  if (rc != GNUTLS_E_SUCCESS) { \
-    DEBUG(D_tls) debug_printf("TLS: cert problem: %s: %s\n", (Label), gnutls_strerror(rc)); \
-    return rc; } } while (0)
+#define exim_gnutls_cert_err(Label) \
+  do \
+    { \
+    if (rc != GNUTLS_E_SUCCESS) \
+      { \
+      DEBUG(D_tls) debug_printf("TLS: cert problem: %s: %s\n", \
+       (Label), gnutls_strerror(rc)); \
+      return rc; \
+      } \
+    } while (0)
 
 static int
 import_cert(const gnutls_datum * cert, gnutls_x509_crt_t * crtp)
@@ -1220,7 +1238,7 @@ if (cert_list == NULL || cert_list_size == 0)
   {
   DEBUG(D_tls) debug_printf("TLS: no certificate from peer (%p & %d)\n",
       cert_list, cert_list_size);
-  if (state->verify_requirement == VERIFY_REQUIRED)
+  if (state->verify_requirement >= VERIFY_REQUIRED)
     return tls_error(US"certificate verification failed",
         "no certificate received from peer", state->host);
   return OK;
@@ -1232,17 +1250,23 @@ if (ct != GNUTLS_CRT_X509)
   const char *ctn = gnutls_certificate_type_get_name(ct);
   DEBUG(D_tls)
     debug_printf("TLS: peer cert not X.509 but instead \"%s\"\n", ctn);
-  if (state->verify_requirement == VERIFY_REQUIRED)
+  if (state->verify_requirement >= VERIFY_REQUIRED)
     return tls_error(US"certificate verification not possible, unhandled type",
         ctn, state->host);
   return OK;
   }
 
-#define exim_gnutls_peer_err(Label) do { \
-  if (rc != GNUTLS_E_SUCCESS) { \
-    DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", (Label), gnutls_strerror(rc)); \
-    if (state->verify_requirement == VERIFY_REQUIRED) { return tls_error((Label), gnutls_strerror(rc), state->host); } \
-    return OK; } } while (0)
+#define exim_gnutls_peer_err(Label) \
+  do { \
+    if (rc != GNUTLS_E_SUCCESS) \
+      { \
+      DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", \
+       (Label), gnutls_strerror(rc)); \
+      if (state->verify_requirement >= VERIFY_REQUIRED) \
+       return tls_error((Label), gnutls_strerror(rc), state->host); \
+      return OK; \
+      } \
+    } while (0)
 
 rc = import_cert(&cert_list[0], &crt);
 exim_gnutls_peer_err(US"cert 0");
@@ -1306,7 +1330,9 @@ else
 /* Handle the result of verification. INVALID seems to be set as well
 as REVOKED, but leave the test for both. */
 
-if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
+if (rc < 0 ||
+    verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)
+   )
   {
   state->peer_cert_verified = FALSE;
   if (!*error)
@@ -1314,21 +1340,42 @@ if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
       ? "certificate revoked" : "certificate invalid";
 
   DEBUG(D_tls)
-    debug_printf("TLS certificate verification failed (%s): peerdn=%s\n",
+    debug_printf("TLS certificate verification failed (%s): peerdn=\"%s\"\n",
         *error, state->peerdn ? state->peerdn : US"<unset>");
 
-  if (state->verify_requirement == VERIFY_REQUIRED)
+  if (state->verify_requirement >= VERIFY_REQUIRED)
     {
-    gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE);
+    gnutls_alert_send(state->session,
+      GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE);
     return FALSE;
     }
   DEBUG(D_tls)
     debug_printf("TLS verify failure overridden (host in tls_try_verify_hosts)\n");
   }
+
 else
   {
+#ifdef EXPERIMENTAL_CERTNAMES
+  if (state->verify_requirement == VERIFY_WITHHOST)
+    {
+    int sep = 0;
+    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");
+      gnutls_alert_send(state->session,
+       GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE);
+      return FALSE;
+      }
+    }
+#endif
   state->peer_cert_verified = TRUE;
-  DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%s\n",
+  DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=\"%s\"\n",
       state->peerdn ? state->peerdn : US"<unset>");
   }
 
@@ -1517,19 +1564,22 @@ optional, set up appropriately. */
 
 if (verify_check_host(&tls_verify_hosts) == OK)
   {
-  DEBUG(D_tls) debug_printf("TLS: a client certificate will be required.\n");
+  DEBUG(D_tls)
+    debug_printf("TLS: a client certificate will be required.\n");
   state->verify_requirement = VERIFY_REQUIRED;
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
   }
 else if (verify_check_host(&tls_try_verify_hosts) == OK)
   {
-  DEBUG(D_tls) debug_printf("TLS: a client certificate will be requested but not required.\n");
+  DEBUG(D_tls)
+    debug_printf("TLS: a client certificate will be requested but not required.\n");
   state->verify_requirement = VERIFY_OPTIONAL;
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST);
   }
 else
   {
-  DEBUG(D_tls) debug_printf("TLS: a client certificate will not be requested.\n");
+  DEBUG(D_tls)
+    debug_printf("TLS: a client certificate will not be requested.\n");
   state->verify_requirement = VERIFY_NONE;
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
   }
@@ -1699,19 +1749,40 @@ if ((  state->exp_tls_verify_certificates
     verify_check_host(&ob->tls_verify_hosts) == OK
    )
   {
-  DEBUG(D_tls) debug_printf("TLS: server certificate verification required.\n");
-  state->verify_requirement = VERIFY_REQUIRED;
+#ifdef EXPERIMENTAL_CERTNAMES
+  if (ob->tls_verify_cert_hostnames)
+    {
+    DEBUG(D_tls)
+      debug_printf("TLS: server cert incl. hostname verification required.\n");
+    state->verify_requirement = VERIFY_WITHHOST;
+    if (!expand_check(ob->tls_verify_cert_hostnames,
+                     US"tls_verify_cert_hostnames",
+                     &state->exp_tls_verify_cert_hostnames))
+      return FAIL;
+    if (state->exp_tls_verify_cert_hostnames)
+      DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
+                     state->exp_tls_verify_cert_hostnames);
+    }
+  else
+#endif
+    {
+    DEBUG(D_tls)
+      debug_printf("TLS: server certificate verification required.\n");
+    state->verify_requirement = VERIFY_REQUIRED;
+    }
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
   }
 else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
   {
-  DEBUG(D_tls) debug_printf("TLS: server certificate verification optional.\n");
+  DEBUG(D_tls)
+    debug_printf("TLS: server certificate verification optional.\n");
   state->verify_requirement = VERIFY_OPTIONAL;
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST);
   }
 else
   {
-  DEBUG(D_tls) debug_printf("TLS: server certificate verification not required.\n");
+  DEBUG(D_tls)
+    debug_printf("TLS: server certificate verification not required.\n");
   state->verify_requirement = VERIFY_NONE;
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
   }
index 3000b8fcb1f8db8d7e52970023eba3ea500f8eec..1d6b91470aa87d94eb5fe951470a500471afbc2e 100644 (file)
@@ -23,7 +23,7 @@ functions from the OpenSSL library. */
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #ifdef EXPERIMENTAL_OCSP
-#include <openssl/ocsp.h>
+# include <openssl/ocsp.h>
 #endif
 
 #ifdef EXPERIMENTAL_OCSP
@@ -32,7 +32,7 @@ functions from the OpenSSL library. */
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
-#define EXIM_HAVE_OPENSSL_TLSEXT
+# define EXIM_HAVE_OPENSSL_TLSEXT
 #endif
 
 /* Structure for collecting random data for seeding. */
@@ -107,6 +107,10 @@ typedef struct tls_ext_ctx_cb {
   uschar *server_cipher_list;
   /* only passed down to tls_error: */
   host_item *host;
+
+#ifdef EXPERIMENTAL_CERTNAMES
+  uschar * verify_cert_hostnames;
+#endif
 } tls_ext_ctx_cb;
 
 /* should figure out a cleanup of API to handle state preserved per
@@ -268,8 +272,7 @@ verify_callback(int state, X509_STORE_CTX *x509ctx,
 X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
 static uschar txt[256];
 
-X509_NAME_oneline(X509_get_subject_name(cert),
-  CS txt, sizeof(txt));
+X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt));
 
 if (state == 0)
   {
@@ -306,8 +309,43 @@ else if (X509_STORE_CTX_get_error_depth(x509ctx) != 0)
   }
 else
   {
+#ifdef EXPERIMENTAL_CERTNAMES
+  uschar * verify_cert_hostnames;
+#endif
+
   tlsp->peerdn = txt;
   tlsp->peercert = X509_dup(cert);
+
+#ifdef EXPERIMENTAL_CERTNAMES
+  if (  tlsp == &tls_out
+     && ((verify_cert_hostnames = client_static_cbinfo->verify_cert_hostnames)))
+       /* client, wanting hostname check */
+
+# if OPENSSL_VERSION_NUMBER >= 0x010100000L || OPENSSL_VERSION_NUMBER >= 0x010002000L
+    {
+    int sep = 0;
+    uschar * list = verify_cert_hostnames;
+    uschar * name;
+    while (name = string_nextinlist(&list, &sep, NULL, 0))
+      if (X509_check_host(cert, name, 0, 0))
+       break;
+    if (!name)
+      {
+      log_write(0, LOG_MAIN,
+       "SSL verify error: certificate name mismatch: \"%s\"\n", txt);
+      return 0;                                /* reject */
+      }
+    }
+# else
+    if (!tls_is_name_for_cert(verify_cert_hostnames, cert))
+      {
+      log_write(0, LOG_MAIN,
+       "SSL verify error: certificate name mismatch: \"%s\"\n", txt);
+      return 0;                                /* reject */
+      }
+# endif
+#endif
+
   DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n",
     *calledp ? "" : " authenticated", txt);
   if (!*calledp) tlsp->certificate_verified = TRUE;
@@ -955,8 +993,8 @@ return i;
 *            Initialize for TLS                  *
 *************************************************/
 
-/* Called from both server and client code, to do preliminary initialization of
-the library.
+/* Called from both server and client code, to do preliminary initialization
+of the library.  We allocate and return a context structure.
 
 Arguments:
   host            connected host, if client; NULL if server
@@ -965,6 +1003,7 @@ Arguments:
   privatekey      private key
   ocsp_file       file of stapling info (server); flag for require ocsp (client)
   addr            address if client; NULL if server (for some randomness)
+  cbp             place to put allocated context
 
 Returns:          OK/DEFER/FAIL
 */
@@ -1118,6 +1157,10 @@ else                     /* client */
 # endif
 #endif
 
+#ifdef EXPERIMENTAL_CERTNAMES
+cbinfo->verify_cert_hostnames = NULL;
+#endif
+
 /* Set up the RSA callback */
 
 SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
@@ -1545,6 +1588,7 @@ if (expciphers != NULL)
 /* stick to the old behaviour for compatibility if tls_verify_certificates is 
    set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only
    the specified host patterns if one of them is defined */
+
 if ((!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) ||
     (verify_check_host(&ob->tls_verify_hosts) == OK))
   {
@@ -1552,6 +1596,19 @@ if ((!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) ||
        ob->tls_crl, host, FALSE, verify_callback_client)) != OK)
     return rc;
   client_verify_optional = FALSE;
+
+#ifdef EXPERIMENTAL_CERTNAMES
+  if (ob->tls_verify_cert_hostnames)
+    {
+    if (!expand_check(ob->tls_verify_cert_hostnames,
+                     US"tls_verify_cert_hostnames",
+                     &client_static_cbinfo->verify_cert_hostnames))
+      return FAIL;
+    if (client_static_cbinfo->verify_cert_hostnames)
+      DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
+                     client_static_cbinfo->verify_cert_hostnames);
+    }
+#endif
   }
 else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
   {
index 75c46e9e4560b65f641718bc319cfa15ba5bc3a3..b5ef965951ff3634471f7777438ebf2052877481 100644 (file)
@@ -255,6 +255,80 @@ return list;
 }
 
 
+#ifdef EXPERIMENTAL_CERTNAMES
+/* Compare a domain name with a possibly-wildcarded name. Wildcards
+are restricted to a single one, as the first element of patterns
+having at least three dot-separated elements.  Case-independent.
+Return TRUE for a match
+*/
+static BOOL
+is_name_match(const uschar * name, const uschar * pat)
+{
+uschar * cp;
+return *pat == '*'             /* possible wildcard match */
+  ?    *++pat == '.'           /* starts star, dot              */
+    && !Ustrchr(++pat, '*')    /* has no more stars             */
+    && Ustrchr(pat, '.')       /* and has another dot.          */
+    && (cp = Ustrchr(name, '.'))/* The name has at least one dot */
+    && strcmpic(++cp, pat) == 0 /* and we only compare after it. */
+  :    !Ustrchr(pat+1, '*')
+    && strcmpic(name, pat) == 0;
+}
+
+/* Compare a list of names with the dnsname elements
+of the Subject Alternate Name, if any, and the
+Subject otherwise.
+
+Arguments:
+       namelist names to compare
+       cert     certificate
+
+Returns:
+       TRUE/FALSE
+*/
+
+BOOL
+tls_is_name_for_cert(uschar * namelist, void * cert)
+{
+uschar * altnames = tls_cert_subject_altname(cert, US"dns");
+uschar * subjdn;
+uschar * certname;
+int cmp_sep = 0;
+uschar * cmpname;
+
+if ((altnames = tls_cert_subject_altname(cert, US"dns")))
+  {
+  int alt_sep = '\n';
+  while (cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0))
+    {
+    uschar * an = altnames;
+    while (certname = string_nextinlist(&an, &alt_sep, NULL, 0))
+      if (is_name_match(cmpname, certname))
+       return TRUE;
+    }
+  }
+
+else if ((subjdn = tls_cert_subject(cert, NULL)))
+  {
+  int sn_sep = ',';
+  uschar * sn;
+
+  dn_to_list(subjdn);
+  while (cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0))
+    {
+    uschar * sn = subjdn;
+    while (certname = string_nextinlist(&sn, &sn_sep, NULL, 0))
+      if (  *certname++ == 'C'
+        && *certname++ == 'N'
+        && *certname++ == '='
+        && is_name_match(cmpname, certname)
+        )
+       return TRUE;
+    }
+  }
+return FALSE;
+}
+#endif
 
 /* vi: aw ai sw=2
 */
index 9b9c83d8b559f92e41e0fcd47abb4f5e32daa5a5..73763730257f989e3a03c926f8c7ddbf7b21738f 100644 (file)
@@ -268,7 +268,7 @@ for(index = 0;; index++)
   {
   siz = 0;
   switch(ret = gnutls_x509_crt_get_subject_alt_name(
-    (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL))
+      (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL))
     {
     case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
       return list;     /* no more elements; normal exit */
@@ -286,7 +286,8 @@ for(index = 0;; index++)
     return g_err("gs1", __FUNCTION__, ret);
   ele[siz] = '\0';
 
-  if (match != -1 && match != ret)
+  if (  match != -1 && match != ret    /* wrong type of SAN */
+     || Ustrlen(ele) != siz)           /* contains a NUL */
     continue;
   switch (ret)
     {
index 29095782acd20d5643ff87c768732d7272d73556..0614b4025c8c0700c5739978bf988ff4e07e403b 100644 (file)
@@ -237,6 +237,7 @@ uschar sep = '\n';
 uschar * tag = US"";
 uschar * ele;
 int match = -1;
+int len;
 
 if (!san) return NULL;
 
@@ -262,19 +263,26 @@ while (sk_GENERAL_NAME_num(san) > 0)
     case GEN_DNS:
       tag = US"DNS";
       ele = ASN1_STRING_data(namePart->d.dNSName);
+      len = ASN1_STRING_length(namePart->d.dNSName);
       break;
     case GEN_URI:
       tag = US"URI";
       ele = ASN1_STRING_data(namePart->d.uniformResourceIdentifier);
+      len = ASN1_STRING_length(namePart->d.uniformResourceIdentifier);
       break;
     case GEN_EMAIL:
       tag = US"MAIL";
       ele = ASN1_STRING_data(namePart->d.rfc822Name);
+      len = ASN1_STRING_length(namePart->d.rfc822Name);
       break;
     default:
       continue;        /* ignore unrecognised types */
     }
-  list = string_append_listele(list, sep,
+  if (ele[len])        /* not nul-terminated */
+    ele = string_copyn(ele, len);
+
+  if (strnlen(CS ele, len) == len)     /* ignore any with embedded nul */
+    list = string_append_listele(list, sep,
          match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
   }
 
index 71a9f23760feac72e949c55a6f49f36289c0024a..c175d2ffe941ba1519befcf1bcc438be76ae2f28 100644 (file)
@@ -163,6 +163,10 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) },
   { "tls_try_verify_hosts", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_try_verify_hosts) },
+#ifdef EXPERIMENTAL_CERTNAMES
+  { "tls_verify_cert_hostnames", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block,tls_verify_cert_hostnames)},
+#endif
   { "tls_verify_certificates", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) },
   { "tls_verify_hosts",     opt_stringptr,
@@ -245,6 +249,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   TRUE,                /* tls_tempfail_tryclear */
   NULL,                /* tls_verify_hosts */
   NULL                 /* tls_try_verify_hosts */
+# ifdef EXPERIMENTAL_CERTNAMES
+ ,NULL                 /* tls_verify_cert_hostnames */
+# endif
 #endif
 #ifndef DISABLE_DKIM
  ,NULL,                /* dkim_canon */
index c7de0091ae23a0aa38f95ce0c72d520cb55733e3..a481943bb2971c2522646dd5ae69eaa6d90cd85f 100644 (file)
@@ -55,7 +55,7 @@ typedef struct {
   BOOL    keepalive;
   BOOL    lmtp_ignore_quota;
   BOOL    retry_include_ip_address;
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   uschar *tls_certificate;
   uschar *tls_crl;
   uschar *tls_privatekey;
@@ -69,18 +69,21 @@ typedef struct {
   BOOL    tls_tempfail_tryclear;
   uschar *tls_verify_hosts;
   uschar *tls_try_verify_hosts;
-  #endif
-  #ifndef DISABLE_DKIM
+# ifdef EXPERIMENTAL_CERTNAMES
+  uschar *tls_verify_cert_hostnames;
+# endif
+#endif
+#ifndef DISABLE_DKIM
   uschar *dkim_domain;
   uschar *dkim_private_key;
   uschar *dkim_selector;
   uschar *dkim_canon;
   uschar *dkim_sign_headers;
   uschar *dkim_strict;
-  #endif
-  #ifdef EXPERIMENTAL_TPDA
+#endif
+#ifdef EXPERIMENTAL_TPDA
   uschar *tpda_host_defer_action;
-  #endif
+#endif
 } smtp_transport_options_block;
 
 /* Data for reading the private options. */
index 26303443509426a1110f526195e8bb0879eb42e6..97dc25e75f18a8f839a7eed2b9efa5f1552b8f64 100644 (file)
@@ -12,6 +12,16 @@ log_file_path = DIR/spool/log/SERVER%slog
 gecos_pattern = ""
 gecos_name = CALLER_NAME
 
+FX = DIR/aux-fixed
+S1 = FX/exim-ca/example.com/server1.example.com
+
+CA1 =   S1/ca_chain.pem 
+CERT1 = S1/server1.example.com.pem
+KEY1 =  S1/server1.example.com.unlocked.key
+CA2 =   FX/cert2
+CERT2 = FX/cert2
+KEY2 =  FX/cert2
+
 # ----- Main settings -----
 
 acl_smtp_rcpt = accept
@@ -25,11 +35,11 @@ tls_advertise_hosts = *
 
 # Set certificate only if server
 
-tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_certificate = ${if eq {SERVER}{server}{CERT1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{KEY1}fail}
 
 tls_verify_hosts = *
-tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
+tls_verify_certificates = ${if eq {SERVER}{server}{CERT2}fail}
 
 
 # ----- Routers -----
@@ -66,6 +76,18 @@ client_q:
   retry_use_local_part
   transport = send_to_server_req_fail
 
+client_r:
+  driver = accept
+  local_parts = userr
+  retry_use_local_part
+  transport = send_to_server_req_failname
+
+client_s:
+  driver = accept
+  local_parts = users
+  retry_use_local_part
+  transport = send_to_server_req_passname
+
 
 # ----- Transports -----
 
@@ -78,8 +100,10 @@ send_to_server_failcert:
   hosts = HOSTIPV4
   hosts_require_tls = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
 
 # this will fail to verify the cert at HOSTIPV4 so fail the crypt, then retry on 127.1; ok
 send_to_server_retry:
@@ -88,19 +112,23 @@ send_to_server_retry:
   hosts = HOSTIPV4 : 127.0.0.1
   hosts_require_tls = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
   tls_verify_certificates = \
-       ${if eq{$host_address}{127.0.0.1}{DIR/aux-fixed/cert1}{DIR/aux-fixed/cert2}}
+    ${if eq{$host_address}{127.0.0.1}{CA1}{CA2}}
 
-# this will fail to verify the cert at HOSTIPV4 but continue unverified though crypted
+# this will fail to verify the cert but continue unverified though crypted
 send_to_server_crypt:
   driver = smtp
   allow_localhost
   hosts = HOSTIPV4
   hosts_require_tls = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
   tls_try_verify_hosts = *
 
 # this will fail to verify the cert at HOSTIPV4 and fallback to unencrypted
@@ -109,8 +137,36 @@ send_to_server_req_fail:
   allow_localhost
   hosts = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
   tls_verify_hosts = *
 
+# # this will fail to verify the cert name and fallback to unencrypted
+# send_to_server_req_failname:
+#   driver = smtp
+#   allow_localhost
+#   hosts = HOSTIPV4
+#   port = PORT_D
+#   tls_certificate = CERT2
+#   tls_privatekey = CERT2
+# 
+#   tls_verify_certificates = CA1
+#   tls_verify_cert_hostnames = server1.example.net : server1.example.org
+#   tls_verify_hosts = *
+# 
+# # this will pass the cert verify including name check
+# send_to_server_req_passname:
+#   driver = smtp
+#   allow_localhost
+#   hosts = HOSTIPV4
+#   port = PORT_D
+#   tls_certificate = CERT2
+#   tls_privatekey = CERT2
+# 
+#   tls_verify_certificates = CA1
+#   tls_verify_cert_hostnames = noway.example.com : server1.example.com
+#   tls_verify_hosts = *
+
 # End
index deb02944df7747202316c62c2394a9429b45e8c0..4751e60150ff4a0963ce016263e301fdea34dcd1 100644 (file)
@@ -12,6 +12,16 @@ log_file_path = DIR/spool/log/SERVER%slog
 gecos_pattern = ""
 gecos_name = CALLER_NAME
 
+FX = DIR/aux-fixed
+S1 = FX/exim-ca/example.com/server1.example.com
+
+CA1 =   S1/ca_chain.pem 
+CERT1 = S1/server1.example.com.pem
+KEY1 =  S1/server1.example.com.unlocked.key
+CA2 =   FX/cert2
+CERT2 = FX/cert2
+KEY2 =  FX/cert2
+
 # ----- Main settings -----
 
 acl_smtp_rcpt = accept
@@ -25,11 +35,11 @@ tls_advertise_hosts = *
 
 # Set certificate only if server
 
-tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_certificate = ${if eq {SERVER}{server}{CERT1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{KEY1}fail}
 
 tls_verify_hosts = *
-tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
+tls_verify_certificates = ${if eq {SERVER}{server}{CERT2}fail}
 
 
 # ----- Routers -----
@@ -66,6 +76,18 @@ client_q:
   retry_use_local_part
   transport = send_to_server_req_fail
 
+client_r:
+  driver = accept
+  local_parts = userr
+  retry_use_local_part
+  transport = send_to_server_req_failname
+
+client_s:
+  driver = accept
+  local_parts = users
+  retry_use_local_part
+  transport = send_to_server_req_passname
+
 
 # ----- Transports -----
 
@@ -78,8 +100,10 @@ send_to_server_failcert:
   hosts = HOSTIPV4
   hosts_require_tls = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
 
 # this will fail to verify the cert at HOSTIPV4 so fail the crypt, then retry on 127.1; ok
 send_to_server_retry:
@@ -88,9 +112,11 @@ send_to_server_retry:
   hosts = HOSTIPV4 : 127.0.0.1
   hosts_require_tls = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
   tls_verify_certificates = \
-    ${if eq{$host_address}{127.0.0.1}{DIR/aux-fixed/cert1}{DIR/aux-fixed/cert2}}
+    ${if eq{$host_address}{127.0.0.1}{CA1}{CA2}}
 
 # this will fail to verify the cert but continue unverified though crypted
 send_to_server_crypt:
@@ -99,8 +125,10 @@ send_to_server_crypt:
   hosts = HOSTIPV4
   hosts_require_tls = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
   tls_try_verify_hosts = *
 
 # this will fail to verify the cert at HOSTIPV4 and fallback to unencrypted
@@ -109,8 +137,36 @@ send_to_server_req_fail:
   allow_localhost
   hosts = HOSTIPV4
   port = PORT_D
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
   tls_verify_hosts = *
 
+# # this will fail to verify the cert name and fallback to unencrypted
+# send_to_server_req_failname:
+#   driver = smtp
+#   allow_localhost
+#   hosts = HOSTIPV4
+#   port = PORT_D
+#   tls_certificate = CERT2
+#   tls_privatekey = CERT2
+# 
+#   tls_verify_certificates = CA1
+#   tls_verify_cert_hostnames = server1.example.net : server1.example.org
+#   tls_verify_hosts = *
+# 
+# # this will pass the cert verify including name check
+# send_to_server_req_passname:
+#   driver = smtp
+#   allow_localhost
+#   hosts = HOSTIPV4
+#   port = PORT_D
+#   tls_certificate = CERT2
+#   tls_privatekey = CERT2
+# 
+#   tls_verify_certificates = CA1
+#   tls_verify_cert_hostnames = noway.example.com : server1.example.com
+#   tls_verify_hosts = *
+
 # End
diff --git a/test/confs/5440 b/test/confs/5440
new file mode 100644 (file)
index 0000000..9556412
--- /dev/null
@@ -0,0 +1,172 @@
+# Exim test configuration 2012
+# TLS client: verify certificate from server - fails
+
+SERVER=
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/SERVER%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+FX = DIR/aux-fixed
+S1 = FX/exim-ca/example.com/server1.example.com
+
+CA1 =   S1/ca_chain.pem 
+CERT1 = S1/server1.example.com.pem
+KEY1 =  S1/server1.example.com.unlocked.key
+CA2 =   FX/cert2
+CERT2 = FX/cert2
+KEY2 =  FX/cert2
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector =  +tls_peerdn+tls_certificate_verified
+
+queue_only
+queue_run_in_order
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{CERT1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{KEY1}fail}
+
+tls_verify_hosts = *
+tls_verify_certificates = ${if eq {SERVER}{server}{CERT2}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+server_dump:
+  driver = redirect
+  condition = ${if eq {SERVER}{server}{yes}{no}}
+  data = :blackhole:
+
+client_x:
+  driver = accept
+  local_parts = userx
+  retry_use_local_part
+  transport = send_to_server_failcert
+  errors_to = ""
+
+client_y:
+  driver = accept
+  local_parts = usery
+  retry_use_local_part
+  transport = send_to_server_retry
+
+client_z:
+  driver = accept
+  local_parts = userz
+  retry_use_local_part
+  transport = send_to_server_crypt
+
+client_q:
+  driver = accept
+  local_parts = userq
+  retry_use_local_part
+  transport = send_to_server_req_fail
+
+client_r:
+  driver = accept
+  local_parts = userr
+  retry_use_local_part
+  transport = send_to_server_req_failname
+
+client_s:
+  driver = accept
+  local_parts = users
+  retry_use_local_part
+  transport = send_to_server_req_passname
+
+
+# ----- Transports -----
+
+begin transports
+
+# this will fail to verify the cert at HOSTIPV4 so fail the crypt requirement
+send_to_server_failcert:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  hosts_require_tls = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
+
+# this will fail to verify the cert at HOSTIPV4 so fail the crypt, then retry on 127.1; ok
+send_to_server_retry:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4 : 127.0.0.1
+  hosts_require_tls = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = \
+    ${if eq{$host_address}{127.0.0.1}{CA1}{CA2}}
+
+# this will fail to verify the cert but continue unverified though crypted
+send_to_server_crypt:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  hosts_require_tls = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
+  tls_try_verify_hosts = *
+
+# this will fail to verify the cert at HOSTIPV4 and fallback to unencrypted
+send_to_server_req_fail:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
+  tls_verify_hosts = *
+
+# this will fail to verify the cert name and fallback to unencrypted
+send_to_server_req_failname:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA1
+  tls_verify_cert_hostnames = server1.example.net : server1.example.org
+  tls_verify_hosts = *
+
+# this will pass the cert verify including name check
+send_to_server_req_passname:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA1
+  tls_verify_cert_hostnames = noway.example.com : server1.example.com
+  tls_verify_hosts = *
+
+# End
diff --git a/test/confs/5450 b/test/confs/5450
new file mode 100644 (file)
index 0000000..398871c
--- /dev/null
@@ -0,0 +1,172 @@
+# Exim test configuration 2112
+# TLS client: verify certificate from server - fails
+
+SERVER=
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/SERVER%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+FX = DIR/aux-fixed
+S1 = FX/exim-ca/example.com/server1.example.com
+
+CA1 =   S1/ca_chain.pem 
+CERT1 = S1/server1.example.com.pem
+KEY1 =  S1/server1.example.com.unlocked.key
+CA2 =   FX/cert2
+CERT2 = FX/cert2
+KEY2 =  FX/cert2
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector =  +tls_peerdn+tls_certificate_verified
+
+queue_only
+queue_run_in_order
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{CERT1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{KEY1}fail}
+
+tls_verify_hosts = *
+tls_verify_certificates = ${if eq {SERVER}{server}{CERT2}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+server_dump:
+  driver = redirect
+  condition = ${if eq {SERVER}{server}{yes}{no}}
+  data = :blackhole:
+
+client_x:
+  driver = accept
+  local_parts = userx
+  retry_use_local_part
+  transport = send_to_server_failcert
+  errors_to = ""
+
+client_y:
+  driver = accept
+  local_parts = usery
+  retry_use_local_part
+  transport = send_to_server_retry
+
+client_z:
+  driver = accept
+  local_parts = userz
+  retry_use_local_part
+  transport = send_to_server_crypt
+
+client_q:
+  driver = accept
+  local_parts = userq
+  retry_use_local_part
+  transport = send_to_server_req_fail
+
+client_r:
+  driver = accept
+  local_parts = userr
+  retry_use_local_part
+  transport = send_to_server_req_failname
+
+client_s:
+  driver = accept
+  local_parts = users
+  retry_use_local_part
+  transport = send_to_server_req_passname
+
+
+# ----- Transports -----
+
+begin transports
+
+# this will fail to verify the cert at HOSTIPV4 so fail the crypt requirement
+send_to_server_failcert:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  hosts_require_tls = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
+
+# this will fail to verify the cert at HOSTIPV4 so fail the crypt, then retry on 127.1; ok
+send_to_server_retry:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4 : 127.0.0.1
+  hosts_require_tls = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = \
+    ${if eq{$host_address}{127.0.0.1}{CA1}{CA2}}
+
+# this will fail to verify the cert but continue unverified though crypted
+send_to_server_crypt:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  hosts_require_tls = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
+  tls_try_verify_hosts = *
+
+# this will fail to verify the cert at HOSTIPV4 and fallback to unencrypted
+send_to_server_req_fail:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA2
+  tls_verify_hosts = *
+
+# this will fail to verify the cert name and fallback to unencrypted
+send_to_server_req_failname:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA1
+  tls_verify_cert_hostnames = server1.example.net : server1.example.org
+  tls_verify_hosts = *
+
+# this will pass the cert verify including name check
+send_to_server_req_passname:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  tls_certificate = CERT2
+  tls_privatekey = CERT2
+
+  tls_verify_certificates = CA1
+  tls_verify_cert_hostnames = noway.example.com : server1.example.com
+  tls_verify_hosts = *
+
+# End
index dbb3273affa36316be241931c11cc6d36188822f..bcb1e6fd8309f064d7b965bb87f3c12b3a491400 100644 (file)
@@ -9,9 +9,9 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 userx@test.ex: error ignored
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (certificate verification failed): certificate invalid
-1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client_y T=send_to_server_retry H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=yes DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client_y T=send_to_server_retry H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=yes DN="CN=server1.example.com" C="250 OK id=10HmbB-0005vi-00"
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client_z T=send_to_server_crypt H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client_z T=send_to_server_crypt H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbA-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (certificate verification failed): certificate invalid
 1999-03-02 09:44:33 10HmbA-0005vi-00 TLS session failure: delivering unencrypted to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
index 3f77e65ea870807c58846bb1fd09ce8c85103eaf..ea09dd9a96b6c246881a37f57cf5e1d6d7fe1676 100644 (file)
@@ -3,20 +3,22 @@
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
-1999-03-02 09:44:33 10HmaX-0005vi-00 SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmaX-0005vi-00 SSL verify error: depth=0 error=unable to get local issuer certificate cert=/CN=server1.example.com
 1999-03-02 09:44:33 10HmaX-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (SSL_connect): error: <<detail omitted>>
 1999-03-02 09:44:33 10HmaX-0005vi-00 == userx@test.ex R=client_x T=send_to_server_failcert defer (-37): failure while setting up TLS session
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@test.ex: retry timeout exceeded
 1999-03-02 09:44:33 10HmaX-0005vi-00 userx@test.ex: error ignored
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmaY-0005vi-00 SSL verify error: depth=0 error=unable to get local issuer certificate cert=/CN=server1.example.com
 1999-03-02 09:44:33 10HmaY-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client_y T=send_to_server_retry H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=yes DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client_y T=send_to_server_retry H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbB-0005vi-00"
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client_z T=send_to_server_crypt H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 SSL verify error: depth=0 error=unable to get local issuer certificate cert=/CN=server1.example.com
+1999-03-02 09:44:33 10HmaZ-0005vi-00 SSL verify error: depth=0 error=certificate not trusted cert=/CN=server1.example.com
+1999-03-02 09:44:33 10HmaZ-0005vi-00 SSL verify error: depth=0 error=unable to verify the first certificate cert=/CN=server1.example.com
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client_z T=send_to_server_crypt H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=no DN="/CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbA-0005vi-00 SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbA-0005vi-00 SSL verify error: depth=0 error=unable to get local issuer certificate cert=/CN=server1.example.com
 1999-03-02 09:44:33 10HmbA-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (SSL_connect): error: <<detail omitted>>
 1999-03-02 09:44:33 10HmbA-0005vi-00 TLS session failure: delivering unencrypted to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
 1999-03-02 09:44:33 10HmbA-0005vi-00 => userq@test.ex R=client_q T=send_to_server_req_fail H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbD-0005vi-00"
diff --git a/test/log/5440 b/test/log/5440
new file mode 100644 (file)
index 0000000..4d600eb
--- /dev/null
@@ -0,0 +1,17 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (certificate verification failed)
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session failure: delivering unencrypted to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userr@test.ex R=client_r T=send_to_server_req_failname H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaZ-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => users@test.ex R=client_s T=send_to_server_req_passname H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=yes DN="CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 TLS error on connection from the.local.host.name [ip4.ip4.ip4.ip4] (recv): A TLS fatal alert has been received.: Certificate is bad
+1999-03-02 09:44:33 TLS error on connection from the.local.host.name [ip4.ip4.ip4.ip4] (send): The specified session has been invalidated for some reason.
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=yes DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" S=sss id=E10HmaY-0005vi-00@myhost.test.ex
diff --git a/test/log/5450 b/test/log/5450
new file mode 100644 (file)
index 0000000..2a8aec4
--- /dev/null
@@ -0,0 +1,28 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 SSL verify error: depth=0 error=unable to get local issuer certificate cert=/CN=server1.example.com
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (SSL_connect): error: <<detail omitted>>
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session failure: delivering unencrypted to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userq@test.ex R=client_q T=send_to_server_req_fail H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 SSL verify error: certificate name mismatch: "/CN=server1.example.com"
+
+1999-03-02 09:44:33 10HmaY-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (SSL_connect): error: <<detail omitted>>
+1999-03-02 09:44:33 10HmaY-0005vi-00 TLS session failure: delivering unencrypted to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userr@test.ex R=client_r T=send_to_server_req_failname H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => users@test.ex R=client_s T=send_to_server_req_passname H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 TLS error on connection from the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] (SSL_accept): error: <<detail omitted>>
+1999-03-02 09:44:33 TLS client disconnected cleanly (rejected our certificate?)
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 TLS error on connection from the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] (SSL_accept): error: <<detail omitted>>
+1999-03-02 09:44:33 TLS client disconnected cleanly (rejected our certificate?)
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaY-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=yes DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" S=sss id=E10HmaZ-0005vi-00@myhost.test.ex
diff --git a/test/scripts/5440-certnames-GnuTLS/5440 b/test/scripts/5440-certnames-GnuTLS/5440
new file mode 100644 (file)
index 0000000..fea9551
--- /dev/null
@@ -0,0 +1,14 @@
+# TLS client: verify certificate from server - fails
+gnutls
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim userr@test.ex
+Testing
+****
+exim users@test.ex
+Testing
+****
+exim -qf
+****
+killdaemon
+no_msglog_check
diff --git a/test/scripts/5440-certnames-GnuTLS/REQUIRES b/test/scripts/5440-certnames-GnuTLS/REQUIRES
new file mode 100644 (file)
index 0000000..5a5fac1
--- /dev/null
@@ -0,0 +1,3 @@
+support GnuTLS
+support Experimental_Certnames
+running IPv4
diff --git a/test/scripts/5450-certnames-OpenSSL/5450 b/test/scripts/5450-certnames-OpenSSL/5450
new file mode 100644 (file)
index 0000000..c94d1a5
--- /dev/null
@@ -0,0 +1,16 @@
+# TLS client: verify certificate from server - fails
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim userq@test.ex
+Testing
+****
+exim userr@test.ex
+Testing
+****
+exim users@test.ex
+Testing
+****
+exim -qf
+****
+killdaemon
+no_msglog_check
diff --git a/test/scripts/5450-certnames-OpenSSL/REQUIRES b/test/scripts/5450-certnames-OpenSSL/REQUIRES
new file mode 100644 (file)
index 0000000..663b390
--- /dev/null
@@ -0,0 +1,3 @@
+support OpenSSL
+support Experimental_Certnames
+running IPv4