Fail a DANE-mode verify on totally missing certificate
[exim.git] / src / src / tls-openssl.c
index c489ea51da4f36fa50744bb44e7aaa330fb9528a..c23ac031f5b544f6486710e4e8b24344c0a539e6 100644 (file)
@@ -172,7 +172,7 @@ Returns:    OK/DEFER/FAIL
 */
 
 static int
-tls_error(uschar *prefix, host_item *host, uschar *msg)
+tls_error(uschar * prefix, const host_item * host, uschar *  msg)
 {
 if (!msg)
   {
@@ -308,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)
     {
@@ -342,9 +341,11 @@ else if (depth != 0)
       {
       log_write(0, LOG_MAIN, "SSL verify denied by event-action: "
                              "depth=%d cert=%s: %s", depth, txt, yield);
-      tlsp->certificate_verified = FALSE;
       *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;
@@ -368,6 +369,9 @@ else
 # 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;
@@ -376,7 +380,8 @@ else
     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)
          {
@@ -389,7 +394,11 @@ 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");
       }
     }
 # else
@@ -397,7 +406,11 @@ 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*/
@@ -409,9 +422,11 @@ else
       {
       log_write(0, LOG_MAIN, "SSL verify denied by event-action: "
                              "depth=0 cert=%s: %s", txt, yield);
-      tlsp->certificate_verified = FALSE;
       *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
 
@@ -526,7 +541,7 @@ Returns:    TRUE if OK (nothing to set up, or setup worked)
 */
 
 static BOOL
-init_dh(SSL_CTX *sctx, uschar *dhparam, host_item *host)
+init_dh(SSL_CTX *sctx, uschar *dhparam, const host_item *host)
 {
 BIO *bio;
 DH *dh;
@@ -1668,35 +1683,30 @@ int rc;
    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))
-  {
-  if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
-       ob->tls_crl, host, FALSE, verify_callback_client)) != OK)
-    return rc;
+if (  (!ob->tls_verify_hosts && !ob->tls_try_verify_hosts)
+   || (verify_check_this_host(&ob->tls_verify_hosts, NULL,
+               host->name, host->address, NULL) == OK)
+   )
   client_verify_optional = FALSE;
+else if (verify_check_this_host(&ob->tls_try_verify_hosts, NULL,
+               host->name, host->address, NULL) == OK)
+  client_verify_optional = TRUE;
+else
+  return OK;
+
+if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
+      ob->tls_crl, host, client_verify_optional, verify_callback_client)) != OK)
+  return rc;
 
 #ifdef EXPERIMENTAL_CERTNAMES
-  if (ob->tls_verify_cert_hostnames)
-    {
-    if (!expand_check(ob->tls_verify_cert_hostnames,
-                     US"tls_verify_cert_hostnames",
-                     &cbinfo->verify_cert_hostnames))
-      return FAIL;
-    if (cbinfo->verify_cert_hostnames)
-      DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
-                     cbinfo->verify_cert_hostnames);
-    }
-#endif
-  }
-else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
+if (verify_check_this_host(&ob->tls_verify_cert_hostnames, NULL,
+             host->name, host->address, NULL) == OK)
   {
-  if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
-       ob->tls_crl, host, TRUE, verify_callback_client)) != OK)
-    return rc;
-  client_verify_optional = TRUE;
+  cbinfo->verify_cert_hostnames = host->name;
+  DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
+                   cbinfo->verify_cert_hostnames);
   }
-
+#endif
 return OK;
 }
 
@@ -1862,7 +1872,9 @@ if (expciphers != NULL)
 #ifdef EXPERIMENTAL_DANE
 if (tlsa_dnsa)
   {
-  SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER, verify_callback_client_dane);
+  SSL_CTX_set_verify(client_ctx,
+    SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+    verify_callback_client_dane);
 
   if (!DANESSL_library_init())
     return tls_error(US"library init", host, NULL);