NULL, /* hosts_try_prdr */
#endif
#ifndef DISABLE_OCSP
- US"*", /* hosts_request_ocsp (except under DANE) */
+ US"*", /* hosts_request_ocsp (except under DANE; tls_client_start()) */
NULL, /* hosts_require_ocsp */
#endif
NULL, /* hosts_require_tls */
+#ifdef EXPERIMENTAL_DANE
+int
+tlsa_lookup(host_item * host, dns_answer * dnsa,
+ BOOL dane_required, BOOL * dane)
+{
+/* move this out to host.c given the similarity to dns_lookup() ? */
+uschar buffer[300];
+uschar * fullname = buffer;
+
+/* TLSA lookup string */
+(void)sprintf(CS buffer, "_%d._tcp.%.256s", host->port, host->name);
+
+switch (dns_lookup(dnsa, buffer, T_TLSA, &fullname))
+ {
+ case DNS_AGAIN:
+ return DEFER; /* just defer this TLS'd conn */
+
+ default:
+ case DNS_FAIL:
+ if (dane_required)
+ {
+ log_write(0, LOG_MAIN, "DANE error: TLSA lookup failed");
+ return FAIL;
+ }
+ break;
+
+ case DNS_SUCCEED:
+ if (!dns_is_secure(dnsa))
+ {
+ log_write(0, LOG_MAIN, "DANE error: TLSA lookup not DNSSEC");
+ return DEFER;
+ }
+ *dane = TRUE;
+ break;
+ }
+return OK;
+}
+#endif
+
+
/*************************************************
* Deliver address list to given host *
*************************************************/
#ifdef EXPERIMENTAL_DSN
BOOL dsn_all_lasthop = TRUE;
#endif
+#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
+BOOL dane = FALSE;
+dns_answer tlsa_dnsa;
+#endif
smtp_inblock inblock;
smtp_outblock outblock;
int max_rcpt = tblock->max_addresses;
return DEFER;
}
+#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
+ {
+ BOOL dane_required;
+
+ tls_out.dane_verified = FALSE;
+ tls_out.tlsa_usage = 0;
+
+ dane_required = verify_check_this_host(&ob->hosts_require_dane, NULL,
+ host->name, host->address, NULL) == OK;
+
+ if (host->dnssec == DS_YES)
+ {
+ if( dane_required
+ || verify_check_this_host(&ob->hosts_try_dane, NULL,
+ host->name, host->address, NULL) == OK
+ )
+ if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK)
+ return rc;
+ }
+ else if (dane_required)
+ {
+ log_write(0, LOG_MAIN, "DANE error: %s lookup not DNSSEC", host->name);
+ return FAIL;
+ }
+
+ if (dane)
+ ob->tls_tempfail_tryclear = FALSE;
+ }
+#endif /*DANE*/
+
/* Expand the greeting message while waiting for the initial response. (Makes
sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
delayed till here so that $sending_interface and $sending_port are set. */
else
TLS_NEGOTIATE:
{
- int rc = tls_client_start(inblock.sock, host, addrlist, tblock);
+ int rc = tls_client_start(inblock.sock, host, addrlist, tblock
+# ifdef EXPERIMENTAL_DANE
+ , dane ? &tlsa_dnsa : NULL
+# endif
+ );
/* TLS negotiation failed; give an error. From outside, this function may
be called again to try in clear on a new connection, if the options permit
/* If the host is required to use a secure channel, ensure that we
have one. */
-else if ( verify_check_this_host(&(ob->hosts_require_tls), NULL, host->name,
- host->address, NULL) == OK
-#ifdef EXPERIMENTAL_DANE
- || verify_check_this_host(&(ob->hosts_require_dane), NULL, host->name,
+else if (
+# ifdef EXPERIMENTAL_DANE
+ dane ||
+# endif
+ verify_check_this_host(&(ob->hosts_require_tls), NULL, host->name,
host->address, NULL) == OK
-#endif
)
{
save_errno = ERRNO_TLSREQUIRED;
"the server did not offer TLS support");
goto TLS_FAILED;
}
-#endif
+#endif /*SUPPORT_TLS*/
/* If TLS is active, we have just started it up and re-done the EHLO command,
so its response needs to be analyzed. If TLS is not active and this is a
&& ob->tls_tempfail_tryclear
&& verify_check_this_host(&(ob->hosts_require_tls), NULL, host->name,
host->address, NULL) != OK
-# ifdef EXPERIMENTAL_DANE
- && verify_check_this_host(&(ob->hosts_require_dane), NULL, host->name,
- host->address, NULL) != OK
-# endif
)
{
log_write(0, LOG_MAIN, "TLS session failure: delivering unencrypted "