Do not permit multi-component wildcards on certificate names (OpenSSL, EXPERIMENTAL_C...
authorJeremy Harris <jgh146exb@wizmail.org>
Wed, 5 Nov 2014 18:24:00 +0000 (18:24 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 5 Nov 2014 19:02:19 +0000 (19:02 +0000)
1  2 
doc/doc-txt/ChangeLog
doc/doc-txt/experimental-spec.txt
src/src/tls-openssl.c

diff --combined doc/doc-txt/ChangeLog
index 5a298d161604b0db07acd6607946e99a9c176b94,b389a7deb6353b023b06dd24074fd4b8ebf14710..997a459c80fa35adbce2f5f6550299b0af5ba4c5
@@@ -59,9 -59,11 +59,14 @@@ JH/08 Rename the TPDA expermimental fac
        raised for inbound connections, if the main configuration event_action
        option is defined.
  
 +TL/06 In test suite, disable OCSP for old versions of openssl which contained
 +      early OCSP support, but no stapling (appears to be less than 1.0.0).
 +
+ JH/09 When compiled with OpenSSL and EXPERIMENTAL_CERTNAMES, the checks on
+       server certificate names available under the smtp transport option
+       "tls_verify_cert_hostname" now do not permit multi-component wildcard
+       matches.
  
  Exim version 4.84
  -----------------
index faa64df68685d133acf8e2ea4999c8d7bda10dcd,8192f3d76ac4a190fbd67892a6e49e085093435d..266e198914d9e8b35ca5b1f8b9b2a095724d7ec7
@@@ -1144,6 -1144,8 +1144,8 @@@ the next hop does not support DSN
  Adding it to a redirect router makes no difference.
  
  
  Certificate name checking
  --------------------------------------------------------------
  The X509 certificates used for TLS are supposed be verified
@@@ -1151,16 -1153,26 +1153,30 @@@ that they are owned by the expected hos
  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".
+ included to do so for server certificates, 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".
++"tls_verify_cert_hostnames" supported which takes a list of
++names for which the additional checks must be made.
++The option currently defaults to empty, but this may change in
++the future.  "*" is probably a suitable value.
++Whether certificate verification is done at all, and the result of
++it failing, is stll under the control of "tls_verify_hosts" nad
++"tls_try_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).
  
+ The equivalent check on the server for client certificates is not
+ implemented.  At least one major email provider is using a client
+ certificate which fails this check.  They do not retry either without
+ hte client certificate or in clear.
+ It is possible to duplicate the effect of this checking by
+ creative use of Events.
  
  DANE
  ------------------------------------------------------------
@@@ -1304,7 -1316,7 +1320,7 @@@ in the delivery log line will show as "
  
  There is a new variable $tls_out_dane which will have "yes" if
  verification succeeded using DANE and "no" otherwise (only useful
- in combination with EXPERIMENTAL_TPDA), and a new variable
+ in combination with EXPERIMENTAL_EVENT), and a new variable
  $tls_out_tlsa_usage (detailed above).
  
  
diff --combined src/src/tls-openssl.c
index fe1b208ac5b2e4d708b913e2f466e11733ad0450,afc898ca723d6f5aa5ab196076c846ea21f05eea..63bf83b1dddc125ab5e03cea5c35c80676b66ea0
@@@ -294,11 -294,8 +294,11 @@@ verify_callback(int state, X509_STORE_C
  {
  X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
  int depth = X509_STORE_CTX_get_error_depth(x509ctx);
 -uschar * ev;
  static uschar txt[256];
 +#ifdef EXPERIMENTAL_EVENT
 +uschar * ev;
 +uschar * yield;
 +#endif
  
  X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt));
  
@@@ -308,6 -305,7 +308,6 @@@ if (state == 0
      depth,
      X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)),
      txt);
 -  tlsp->certificate_verified = FALSE;
    *calledp = TRUE;
    if (!*optionalp)
      {
@@@ -337,15 -335,13 +337,15 @@@ else if (depth != 0
    if (ev)
      {
      tlsp->peercert = X509_dup(cert);
 -    if (event_raise(ev, US"tls:cert", string_sprintf("%d", depth)) == DEFER)
 +    if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth))))
        {
        log_write(0, LOG_MAIN, "SSL verify denied by event-action: "
 -                            "depth=%d cert=%s", depth, txt);
 -      tlsp->certificate_verified = FALSE;
 +                            "depth=%d cert=%s: %s", depth, txt, yield);
        *calledp = TRUE;
 -      return 0;                           /* reject */
 +      if (!*optionalp)
 +      return 0;                           /* reject */
 +      DEBUG(D_tls) debug_printf("Event-action verify failure overridden "
 +      "(host in tls_try_verify_hosts)\n");
        }
      X509_free(tlsp->peercert);
      tlsp->peercert = NULL;
@@@ -369,6 -365,9 +369,9 @@@ els
  # if EXIM_HAVE_OPENSSL_CHECKHOST
  #  ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
  #   define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0
+ #  endif
+ #  ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
+ #   define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0
  #  endif
      {
      int sep = 0;
      int rc;
      while ((name = string_nextinlist(&list, &sep, NULL, 0)))
        if ((rc = X509_check_host(cert, name, 0,
-                 X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS)))
+                 X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
+                 | X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS)))
        {
        if (rc < 0)
          {
        {
        log_write(0, LOG_MAIN,
        "SSL verify error: certificate name mismatch: \"%s\"\n", txt);
 -      return 0;                               /* reject */
 +      *calledp = TRUE;
 +      if (!*optionalp)
 +      return 0;                           /* reject */
 +      DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
 +      "tls_try_verify_hosts)\n");
        }
      }
  # else
        {
        log_write(0, LOG_MAIN,
        "SSL verify error: certificate name mismatch: \"%s\"\n", txt);
 -      return 0;                               /* reject */
 +      *calledp = TRUE;
 +      if (!*optionalp)
 +      return 0;                           /* reject */
 +      DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
 +      "tls_try_verify_hosts)\n");
        }
  # endif
  #endif        /*EXPERIMENTAL_CERTNAMES*/
  #ifdef EXPERIMENTAL_EVENT
    ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action;
    if (ev)
 -    if (event_raise(ev, US"tls:cert", US"0") == DEFER)
 +    if ((yield = event_raise(ev, US"tls:cert", US"0")))
        {
        log_write(0, LOG_MAIN, "SSL verify denied by event-action: "
 -                            "depth=0 cert=%s", txt);
 -      tlsp->certificate_verified = FALSE;
 +                            "depth=0 cert=%s: %s", txt, yield);
        *calledp = TRUE;
 -      return 0;                           /* reject */
 +      if (!*optionalp)
 +      return 0;                           /* reject */
 +      DEBUG(D_tls) debug_printf("Event-action verify failure overridden "
 +      "(host in tls_try_verify_hosts)\n");
        }
  #endif
  
@@@ -460,7 -450,6 +464,7 @@@ X509 * cert = X509_STORE_CTX_get_curren
  static uschar txt[256];
  #ifdef EXPERIMENTAL_EVENT
  int depth = X509_STORE_CTX_get_error_depth(x509ctx);
 +uschar * yield;
  #endif
  
  X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt));
@@@ -472,11 -461,11 +476,11 @@@ tls_out.peercert = X509_dup(cert)
  #ifdef EXPERIMENTAL_EVENT
    if (client_static_cbinfo->event_action)
      {
 -    if (event_raise(client_static_cbinfo->event_action,
 -                  US"tls:cert", string_sprintf("%d", depth)) == DEFER)
 +    if ((yield = event_raise(client_static_cbinfo->event_action,
 +                  US"tls:cert", string_sprintf("%d", depth))))
        {
        log_write(0, LOG_MAIN, "DANE verify denied by event-action: "
 -                            "depth=%d cert=%s", depth, txt);
 +                            "depth=%d cert=%s: %s", depth, txt, yield);
        tls_out.certificate_verified = FALSE;
        return 0;                           /* reject */
        }