#ifndef DISABLE_OCSP
# include <openssl/ocsp.h>
#endif
+#ifdef EXPERIMENTAL_DANE
+# include <danessl.h>
+#endif
+
#ifndef DISABLE_OCSP
# define EXIM_OCSP_SKEW_SECONDS (300L)
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
# define EXIM_HAVE_OPENSSL_TLSEXT
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x010100000L
+# define EXIM_HAVE_OPENSSL_CHECKHOST
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x010000000L \
+ && (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
+# define EXIM_HAVE_OPENSSL_CHECKHOST
+#endif
#if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP)
# warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
uschar *server_cipher_list;
/* only passed down to tls_error: */
host_item *host;
-
-#ifdef EXPERIMENTAL_CERTNAMES
- uschar * verify_cert_hostnames;
+ const uschar * verify_cert_hostnames;
+#ifdef EXPERIMENTAL_EVENT
+ uschar * event_action;
#endif
} tls_ext_ctx_cb;
*/
static int
-tls_error(uschar *prefix, host_item *host, uschar *msg)
+tls_error(uschar * prefix, const host_item * host, uschar * msg)
{
-if (msg == NULL)
+if (!msg)
{
ERR_error_string(ERR_get_error(), ssl_errstring);
msg = (uschar *)ssl_errstring;
}
-if (host == NULL)
+if (host)
+ {
+ log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection (%s): %s",
+ host->name, host->address, prefix, msg);
+ return FAIL;
+ }
+else
{
uschar *conn_info = smtp_get_connection_info();
if (Ustrncmp(conn_info, US"SMTP ", 5) == 0)
conn_info += 5;
+ /* I'd like to get separated H= here, but too hard for now */
log_write(0, LOG_MAIN, "TLS error on %s (%s): %s",
conn_info, prefix, msg);
return DEFER;
}
-else
- {
- log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s): %s",
- host->name, host->address, prefix, msg);
- return FAIL;
- }
}
{
X509 * current_cert= tmp_obj->data.x509;
X509_NAME_oneline(X509_get_subject_name(current_cert), CS name, sizeof(name));
+ txt[sizeof(name)-1] = '\0';
debug_printf(" %s\n", name);
}
}
optional verification for this case is done when requesting SSL to verify, by
setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT in the non-optional case.
+May be called multiple times for different issues with a certificate, even
+for a given "depth" in the certificate chain.
+
Arguments:
state current yes/no state as 1/0
x509ctx certificate information.
tls_support *tlsp, BOOL *calledp, BOOL *optionalp)
{
X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx);
+int depth = X509_STORE_CTX_get_error_depth(x509ctx);
static uschar txt[256];
+#ifdef EXPERIMENTAL_EVENT
+uschar * ev;
+uschar * yield;
+#endif
X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt));
+txt[sizeof(txt)-1] = '\0';
if (state == 0)
{
- log_write(0, LOG_MAIN, "SSL verify error: depth=%d error=%s cert=%s",
- X509_STORE_CTX_get_error_depth(x509ctx),
+ log_write(0, LOG_MAIN, "[%s] SSL verify error: depth=%d error=%s cert=%s",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ depth,
X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)),
txt);
- tlsp->certificate_verified = FALSE;
*calledp = TRUE;
if (!*optionalp)
{
"tls_try_verify_hosts)\n");
}
-else if (X509_STORE_CTX_get_error_depth(x509ctx) != 0)
+else if (depth != 0)
{
- DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n",
- X509_STORE_CTX_get_error_depth(x509ctx), txt);
+ DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, txt);
#ifndef DISABLE_OCSP
if (tlsp == &tls_out && client_static_cbinfo->u_ocsp.client.verify_store)
{ /* client, wanting stapling */
cert))
ERR_clear_error();
}
+#endif
+#ifdef EXPERIMENTAL_EVENT
+ ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action;
+ if (ev)
+ {
+ tlsp->peercert = X509_dup(cert);
+ if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth))))
+ {
+ log_write(0, LOG_MAIN, "[%s] SSL verify denied by event-action: "
+ "depth=%d cert=%s: %s",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ depth, txt, yield);
+ *calledp = TRUE;
+ 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;
+ }
#endif
}
else
{
-#ifdef EXPERIMENTAL_CERTNAMES
- uschar * verify_cert_hostnames;
-#endif
+ const uschar * verify_cert_hostnames;
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
+# 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;
- uschar * list = verify_cert_hostnames;
+ const uschar * list = verify_cert_hostnames;
uschar * name;
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: internal error\n");
+ log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address);
name = NULL;
}
break;
if (!name)
{
log_write(0, LOG_MAIN,
- "SSL verify error: certificate name mismatch: \"%s\"\n", txt);
- return 0; /* reject */
+ "[%s] SSL verify error: certificate name mismatch: \"%s\"",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ txt);
+ *calledp = TRUE;
+ if (!*optionalp)
+ return 0; /* reject */
+ DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
+ "tls_try_verify_hosts)\n");
}
}
# 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 */
+ "[%s] SSL verify error: certificate name mismatch: \"%s\"",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ txt);
+ *calledp = TRUE;
+ if (!*optionalp)
+ return 0; /* reject */
+ DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in "
+ "tls_try_verify_hosts)\n");
}
# endif
+
+#ifdef EXPERIMENTAL_EVENT
+ ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action;
+ if (ev)
+ if ((yield = event_raise(ev, US"tls:cert", US"0")))
+ {
+ log_write(0, LOG_MAIN, "[%s] SSL verify denied by event-action: "
+ "depth=0 cert=%s: %s",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ txt, yield);
+ *calledp = TRUE;
+ if (!*optionalp)
+ return 0; /* reject */
+ DEBUG(D_tls) debug_printf("Event-action verify failure overridden "
+ "(host in tls_try_verify_hosts)\n");
+ }
#endif
DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n",
*calledp = TRUE;
}
-return 1; /* accept */
+return 1; /* accept, at least for this level */
}
static int
}
+#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];
+#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));
+txt[sizeof(txt)-1] = '\0';
+
+DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s\n", txt);
+tls_out.peerdn = txt;
+tls_out.peercert = X509_dup(cert);
+
+#ifdef EXPERIMENTAL_EVENT
+ if (client_static_cbinfo->event_action)
+ {
+ 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: %s", depth, txt, yield);
+ tls_out.certificate_verified = FALSE;
+ return 0; /* reject */
+ }
+ if (depth != 0)
+ {
+ X509_free(tls_out.peercert);
+ tls_out.peercert = NULL;
+ }
+ }
+#endif
+
+if (state == 1)
+ tls_out.dane_verified =
+ tls_out.certificate_verified = TRUE;
+return 1;
+}
+
+#endif /*EXPERIMENTAL_DANE*/
+
/*************************************************
* Information callback *
*/
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;
{
tls_out.ocsp = OCSP_FAILED;
if (log_extra_selector & LX_tls_cipher)
- log_write(0, LOG_MAIN, "Received TLS status response, parse error");
+ log_write(0, LOG_MAIN, "Received TLS cert status response, parse error");
else
DEBUG(D_tls) debug_printf(" parse error\n");
return 0;
{
tls_out.ocsp = OCSP_FAILED;
if (log_extra_selector & LX_tls_cipher)
- log_write(0, LOG_MAIN, "Received TLS status response, error parsing response");
+ log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response");
else
DEBUG(D_tls) debug_printf(" error parsing response\n");
OCSP_RESPONSE_free(rsp);
cbinfo->u_ocsp.client.verify_store, 0)) <= 0)
{
tls_out.ocsp = OCSP_FAILED;
+ if (log_extra_selector & LX_tls_cipher)
+ log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable");
BIO_printf(bp, "OCSP response verify failure\n");
ERR_print_errors(bp);
i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
#endif /*!DISABLE_OCSP*/
-
/*************************************************
* Initialize for TLS *
*************************************************/
long init_options;
int rc;
BOOL okay;
-tls_ext_ctx_cb *cbinfo;
+tls_ext_ctx_cb * cbinfo;
cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
cbinfo->certificate = certificate;
cbinfo->dhparam = dhparam;
cbinfo->server_cipher_list = NULL;
cbinfo->host = host;
+#ifdef EXPERIMENTAL_EVENT
+cbinfo->event_action = NULL;
+#endif
SSL_load_error_strings(); /* basic set up */
OpenSSL_add_ssl_algorithms();
# endif
#endif
-#ifdef EXPERIMENTAL_CERTNAMES
cbinfo->verify_cert_hostnames = NULL;
-#endif
/* Set up the RSA callback */
if (expcerts != NULL && *expcerts != '\0')
{
- struct stat statbuf;
- if (!SSL_CTX_set_default_verify_paths(sctx))
- return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
-
- if (Ustat(expcerts, &statbuf) < 0)
+ if (Ustrcmp(expcerts, "system") == 0)
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "failed to stat %s for certificates", expcerts);
- return DEFER;
+ /* Tell the library to use its compiled-in location for the system default
+ CA bundle, only */
+
+ if (!SSL_CTX_set_default_verify_paths(sctx))
+ return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
}
else
{
- uschar *file, *dir;
- if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- { file = NULL; dir = expcerts; }
- else
- { file = expcerts; dir = NULL; }
+ struct stat statbuf;
- /* If a certificate file is empty, the next function fails with an
- unhelpful error message. If we skip it, we get the correct behaviour (no
- certificates are recognized, but the error message is still misleading (it
- says no certificate was supplied.) But this is better. */
+ /* Tell the library to use its compiled-in location for the system default
+ CA bundle. Those given by the exim config are additional to these */
- if ((file == NULL || statbuf.st_size > 0) &&
- !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
- return tls_error(US"SSL_CTX_load_verify_locations", host, NULL);
+ if (!SSL_CTX_set_default_verify_paths(sctx))
+ return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
- if (file != NULL)
+ if (Ustat(expcerts, &statbuf) < 0)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "failed to stat %s for certificates", expcerts);
+ return DEFER;
+ }
+ else
{
- SSL_CTX_set_client_CA_list(sctx, SSL_load_client_CA_file(CS file));
+ uschar *file, *dir;
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+ { file = NULL; dir = expcerts; }
+ else
+ { file = expcerts; dir = NULL; }
+
+ /* If a certificate file is empty, the next function fails with an
+ unhelpful error message. If we skip it, we get the correct behaviour (no
+ certificates are recognized, but the error message is still misleading (it
+ says no certificate was supplied.) But this is better. */
+
+ if ((file == NULL || statbuf.st_size > 0) &&
+ !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
+ return tls_error(US"SSL_CTX_load_verify_locations", host, NULL);
+
+ /* Load the list of CAs for which we will accept certs, for sending
+ to the client. This is only for the one-file tls_verify_certificates
+ variant.
+ If a list isn't loaded into the server, but
+ some verify locations are set, the server end appears to make
+ a wildcard reqest for client certs.
+ Meanwhile, the client library as deafult behaviour *ignores* the list
+ we send over the wire - see man SSL_CTX_set_client_cert_cb.
+ Because of this, and that the dir variant is likely only used for
+ the public-CA bundle (not for a private CA), not worth fixing.
+ */
+ if (file != NULL)
+ {
+ STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
+ DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
+ sk_X509_NAME_num(names));
+ SSL_CTX_set_client_CA_list(sctx, names);
+ }
}
}
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)
static int
tls_client_basic_ctx_init(SSL_CTX * ctx,
- host_item * host, smtp_transport_options_block * ob
-#ifdef EXPERIMENTAL_CERTNAMES
- , tls_ext_ctx_cb * cbinfo
-#endif
+ host_item * host, smtp_transport_options_block * ob, tls_ext_ctx_cb * cbinfo
)
{
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 || !*ob->tls_try_verify_hosts)
+ )
+ || (verify_check_given_host(&ob->tls_verify_hosts, host) == OK)
+ )
client_verify_optional = FALSE;
+else if (verify_check_given_host(&ob->tls_try_verify_hosts, host) == OK)
+ client_verify_optional = TRUE;
+else
+ return OK;
-#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
+if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
+ ob->tls_crl, host, client_verify_optional, verify_callback_client)) != OK)
+ return rc;
+
+if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK)
+ {
+ cbinfo->verify_cert_hostnames = host->name;
+ DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
+ cbinfo->verify_cert_hostnames);
}
-else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
+return OK;
+}
+
+
+#ifdef EXPERIMENTAL_DANE
+static int
+dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa)
+{
+dns_record * rr;
+dns_scan dnss;
+const char * hostnames[2] = { CS host->name, NULL };
+int found = 0;
+
+if (DANESSL_init(ssl, NULL, hostnames) != 1)
+ return tls_error(US"hostnames load", host, NULL);
+
+for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
+ rr;
+ rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
+ ) if (rr->type == T_TLSA)
{
- if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
- ob->tls_crl, host, TRUE, verify_callback_client)) != OK)
- return rc;
- client_verify_optional = TRUE;
+ uschar * p = rr->data;
+ uint8_t usage, selector, mtype;
+ const char * mdname;
+
+ usage = *p++;
+
+ /* Only DANE-TA(2) and DANE-EE(3) are supported */
+ if (usage != 2 && usage != 3) continue;
+
+ selector = *p++;
+ mtype = *p++;
+
+ switch (mtype)
+ {
+ default: continue; /* Only match-types 0, 1, 2 are supported */
+ case 0: mdname = NULL; break;
+ case 1: mdname = "sha256"; break;
+ case 2: mdname = "sha512"; break;
+ }
+
+ found++;
+ switch (DANESSL_add_tlsa(ssl, usage, selector, mdname, p, rr->size - 3))
+ {
+ default:
+ case 0: /* action not taken */
+ return tls_error(US"tlsa load", host, NULL);
+ case 1: break;
+ }
+
+ tls_out.tlsa_usage |= 1<<usage;
}
-return OK;
+if (found)
+ return OK;
+
+log_write(0, LOG_MAIN, "DANE error: No usable TLSA records");
+return DEFER;
}
+#endif /*EXPERIMENTAL_DANE*/
+
+
/*************************************************
* Start a TLS session in a client *
fd the fd of the connection
host connected host (for messages)
addr the first address
- ob smtp transport options
+ tb transport (always smtp)
+ tlsa_dnsa tlsa lookup, if DANE, else null
Returns: OK on success
FAIL otherwise - note that tls_error() will not give DEFER
int
tls_client_start(int fd, host_item *host, address_item *addr,
- void *v_ob)
+ transport_instance *tb
+#ifdef EXPERIMENTAL_DANE
+ , dns_answer * tlsa_dnsa
+#endif
+ )
{
-smtp_transport_options_block * ob = v_ob;
+smtp_transport_options_block * ob =
+ (smtp_transport_options_block *)tb->options_block;
static uschar txt[256];
uschar * expciphers;
X509 * server_cert;
BOOL request_ocsp = FALSE;
BOOL require_ocsp = FALSE;
#endif
-#ifdef EXPERIMENTAL_DANE
-dns_answer tlsa_dnsa;
-BOOL dane = FALSE;
-BOOL dane_required;
-#endif
#ifdef EXPERIMENTAL_DANE
-dane_required = verify_check_this_host(&ob->hosts_require_dane, NULL,
- host->name, host->address, NULL) == OK;
+tls_out.tlsa_usage = 0;
+#endif
-if (host->dnssec == DS_YES)
+#ifndef DISABLE_OCSP
{
- if( dane_required
- || verify_check_this_host(&ob->hosts_try_dane, NULL,
- host->name, host->address, NULL) == OK
- )
+# ifdef EXPERIMENTAL_DANE
+ if ( tlsa_dnsa
+ && ob->hosts_request_ocsp[0] == '*'
+ && ob->hosts_request_ocsp[1] == '\0'
+ )
{
- /* 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 (rc = dns_lookup(&tlsa_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(&tlsa_dnsa))
- {
- log_write(0, LOG_MAIN, "DANE error: TLSA lookup not DNSSEC");
- return DEFER;
- }
- dane = TRUE;
- break;
- }
+ /* Unchanged from default. Use a safer one under DANE */
+ request_ocsp = TRUE;
+ ob->hosts_request_ocsp = US"${if or { {= {0}{$tls_out_tlsa_usage}} "
+ " {= {4}{$tls_out_tlsa_usage}} } "
+ " {*}{}}";
}
- }
-else if (dane_required)
- {
- /*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
+# endif
-#ifndef DISABLE_OCSP
- {
- require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp,
- NULL, host->name, host->address, NULL) == OK;
- request_ocsp = require_ocsp ? TRUE
- : verify_check_this_host(&ob->hosts_request_ocsp,
- NULL, host->name, host->address, NULL) == OK;
+ if ((require_ocsp =
+ verify_check_given_host(&ob->hosts_require_ocsp, host) == OK))
+ request_ocsp = TRUE;
+ else
+# ifdef EXPERIMENTAL_DANE
+ if (!request_ocsp)
+# endif
+ request_ocsp =
+ verify_check_given_host(&ob->hosts_request_ocsp, host) == OK;
}
#endif
}
#ifdef EXPERIMENTAL_DANE
-if (dane)
+if (tlsa_dnsa)
{
+ 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);
if (DANESSL_CTX_init(client_ctx) <= 0)
#endif
- if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob
-#ifdef EXPERIMENTAL_CERTNAMES
- , client_static_cbinfo
-#endif
- )) != OK)
+ if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob, client_static_cbinfo))
+ != OK)
return rc;
if ((client_ssl = SSL_new(client_ctx)) == NULL)
}
}
+#ifdef EXPERIMENTAL_DANE
+if (tlsa_dnsa)
+ if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa)) != OK)
+ return rc;
+#endif
+
#ifndef DISABLE_OCSP
/* Request certificate status at connection-time. If the server
does OCSP stapling we will get the callback (set in tls_init()) */
+# ifdef EXPERIMENTAL_DANE
+if (request_ocsp)
+ {
+ const uschar * s;
+ if ( ((s = ob->hosts_require_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage"))
+ || ((s = ob->hosts_request_ocsp) && Ustrstr(s, US"tls_out_tlsa_usage"))
+ )
+ { /* Re-eval now $tls_out_tlsa_usage is populated. If
+ this means we avoid the OCSP request, we wasted the setup
+ cost in tls_init(). */
+ require_ocsp = verify_check_given_host(&ob->hosts_require_ocsp, host) == OK;
+ request_ocsp = require_ocsp
+ || verify_check_given_host(&ob->hosts_request_ocsp, host) == OK;
+ }
+ }
+# endif
+
if (request_ocsp)
{
SSL_set_tlsext_status_type(client_ssl, TLSEXT_STATUSTYPE_ocsp);
}
#endif
-#ifdef EXPERIMENTAL_DANE
-if (dane)
- {
- dns_record * rr;
- dns_scan dnss;
- uschar * hostnames[2] = { host->name, NULL };
-
- if (DANESSL_init(client_ssl, NULL, hostnames) != 1)
- return tls_error(US"hostnames load", host, NULL);
-
- for (rr = dns_next_rr(&tlsa_dnsa, &dnss, RESET_ANSWERS);
- rr;
- rr = dns_next_rr(&tlsa_dnsa, &dnss, RESET_NEXT)
- ) if (rr->type == T_TLSA)
- {
- uschar * p = rr->data;
- int usage, selector, mtype;
- const char * mdname;
-
- GETSHORT(usage, p);
- GETSHORT(selector, p);
- GETSHORT(mtype, p);
-
- switch (mtype)
- {
- default: /* log bad */ return FAIL;
- case 0: mdname = NULL; break;
- case 1: mdname = "SHA2-256"; break;
- case 2: mdname = "SHA2-512"; break;
- }
-
- switch (DANESSL_add_tlsa(client_ssl,
- (uint8_t) usage, (uint8_t) selector,
- mdname, p, rr->size - (p - rr->data)))
- {
- default:
- case 0: /* action not taken */
- return tls_error(US"tlsa load", host, NULL);
- case 1: break;
- }
- }
- }
+#ifdef EXPERIMENTAL_EVENT
+client_static_cbinfo->event_action = tb->event_action;
#endif
-
/* There doesn't seem to be a built-in timeout on connection. */
DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
alarm(0);
#ifdef EXPERIMENTAL_DANE
-if (dane)
- DANESSL_cleanup(client_ssl); /*XXX earliest possible callpoint. Too early? */
+if (tlsa_dnsa)
+ DANESSL_cleanup(client_ssl);
#endif
if (rc <= 0)
{
tls_out.peerdn = US X509_NAME_oneline(X509_get_subject_name(server_cert),
CS txt, sizeof(txt));
+ txt[sizeof(txt)-1] = '\0';
tls_out.peerdn = txt; /*XXX a static buffer... */
}
else