Fix fakens TLSA generation and DANE TLSA lookup
[exim.git] / src / src / tls-openssl.c
index eb74605da04125ef77a51c3dd3641a5dbf48e6f4..79beffadf222175d9005a6a02b681a7b6d925ea1 100644 (file)
@@ -361,7 +361,7 @@ else
       return 0;                                /* reject */
       }
 # endif
-#endif
+#endif /*EXPERIMENTAL_CERTNAMES*/
 
   DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n",
     *calledp ? "" : " authenticated", txt);
@@ -385,6 +385,31 @@ return verify_callback(state, x509ctx, &tls_in, &server_verify_callback_called,
 }
 
 
+#ifdef EXPERIMENTAL_DANE
+
+/* This gets called *by* the dane library verify callback, which interposes
+itself.
+*/
+static int
+verify_callback_client_dane(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));
+
+DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s\n", txt);
+tls_out.peerdn = txt;
+tls_out.peercert = X509_dup(cert);
+
+if (state == 1)
+  tls_out.dane_verified =
+  tls_out.certificate_verified = TRUE;
+return 1;
+}
+
+#endif /*EXPERIMENTAL_DANE*/
+
 
 /*************************************************
 *           Information callback                 *
@@ -999,7 +1024,6 @@ return i;
 #endif /*!DISABLE_OCSP*/
 
 
-
 /*************************************************
 *            Initialize for TLS                  *
 *************************************************/
@@ -1421,6 +1445,9 @@ if (expciphers != NULL)
 optional, set up appropriately. */
 
 tls_in.certificate_verified = FALSE;
+#ifdef EXPERIMENTAL_DANE
+tls_in.dane_verified = FALSE;
+#endif
 server_verify_callback_called = FALSE;
 
 if (verify_check_host(&tls_verify_hosts) == OK)
@@ -1663,13 +1690,12 @@ if (host->dnssec == DS_YES)
   }
 else if (dane_required)
   {
-  /* Hmm - what lookup, precisely? */
   /*XXX a shame we only find this after making tcp & smtp connection */
+  /* move the test earlier? */
   log_write(0, LOG_MAIN, "DANE error: previous lookup not DNSSEC");
   return FAIL;
   }
 
-if (!dane)     /*XXX todo: enable ocsp with dane */
 #endif
 
 #ifndef DISABLE_OCSP
@@ -1691,6 +1717,9 @@ rc = tls_init(&client_ctx, host, NULL,
 if (rc != OK) return rc;
 
 tls_out.certificate_verified = FALSE;
+#ifdef EXPERIMENTAL_DANE
+tls_out.dane_verified = FALSE;
+#endif
 client_verify_callback_called = FALSE;
 
 if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
@@ -1713,10 +1742,12 @@ if (expciphers != NULL)
 #ifdef EXPERIMENTAL_DANE
 if (dane)
   {
+  SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER, verify_callback_client_dane);
+
   if (!DANESSL_library_init())
-    return tls_error(US"library init", host, US"DANE library error");
+    return tls_error(US"library init", host, NULL);
   if (DANESSL_CTX_init(client_ctx) <= 0)
-    return tls_error(US"context init", host, US"DANE library error");
+    return tls_error(US"context init", host, NULL);
   }
 else
 
@@ -1775,9 +1806,10 @@ if (dane)
   dns_record * rr;
   dns_scan dnss;
   uschar * hostnames[2] = { host->name, NULL };
+  int found = 0;
 
   if (DANESSL_init(client_ssl, NULL, hostnames) != 1)
-    return tls_error(US"hostnames load", host, US"DANE library error");
+    return tls_error(US"hostnames load", host, NULL);
 
   for (rr = dns_next_rr(&tlsa_dnsa, &dnss, RESET_ANSWERS);
        rr;
@@ -1788,16 +1820,19 @@ if (dane)
     int usage, selector, mtype;
     const char * mdname;
 
-    GETSHORT(usage, p);
-    GETSHORT(selector, p);
-    GETSHORT(mtype, p);
+    found++;
+    usage = *p++;
+    selector = *p++;
+    mtype = *p++;
 
     switch (mtype)
       {
-      default: /* log bad */ return FAIL;
+      default:
+       log_write(0, LOG_MAIN, "DANE error: TLSA record w/bad mtype 0x%x", mtype);
+       return FAIL;
       case 0:  mdname = NULL; break;
-      case 1:  mdname = "SHA2-256"; break;
-      case 2:  mdname = "SHA2-512"; break;
+      case 1:  mdname = "sha256"; break;
+      case 2:  mdname = "sha512"; break;
       }
 
     switch (DANESSL_add_tlsa(client_ssl,
@@ -1805,11 +1840,17 @@ if (dane)
                mdname, p, rr->size - (p - rr->data)))
       {
       default:
-      case 0:  /* action not taken; log error */
-        return FAIL;
+      case 0:  /* action not taken */
+       return tls_error(US"tlsa load", host, NULL);
       case 1:  break;
       }
     }
+
+  if (!found)
+    {
+    log_write(0, LOG_MAIN, "DANE error: No TLSA records");
+    return FAIL;
+    }
   }
 #endif