apply to all TLS connections. For any host that matches one of these options,
Exim requests a certificate as part of the setup of the TLS session. The
contents of the certificate are verified by comparing it with a list of
-expected certificates.
+expected trust-anchors or certificates.
These may be the system default set (depending on library version),
an explicit file or,
depending on library version, a directory, identified by
.endd
where &_/cert/file_& contains a single certificate.
+There is no checking of names of the client against the certificate
+Subject Name or Subject Alternate Names.
+
The difference between &%tls_verify_hosts%& and &%tls_try_verify_hosts%& is
what happens if the client does not supply a certificate, or if the certificate
does not match any of the certificates in the collection named by
certificate verification to the listed servers. Verification either must
or need not succeed respectively.
+The &%tls_verify_cert_hostnames%& option lists hosts for which additional
+checks are made: that the host name (the one in the DNS A record)
+is valid for the certificate.
+The option defaults to always checking.
+
The &(smtp)& transport has two OCSP-related options:
&%hosts_require_ocsp%&; a host-list for which a Certificate Status
is requested and required for the connection to proceed. The default
DANE-TA usage is effectively declaring a specific CA to be used; this might be a private CA or a public,
well-known one.
A private CA at simplest is just a self-signed certificate (with certain
-attributes) which is used to sign cerver certificates, but running one securely
+attributes) which is used to sign server certificates, but running one securely
does require careful arrangement.
With DANE-TA, as implemented in Exim and commonly in other MTAs,
the server TLS handshake must transmit the entire certificate chain from CA to server-certificate.
BOOL peer_dane_verified;
BOOL trigger_sni_changes;
BOOL have_set_peerdn;
- const struct host_item *host;
+ const struct host_item *host; /* NULL if server */
gnutls_x509_crt_t peercert;
uschar *peerdn;
uschar *ciphersuite;
else
{
- if (state->exp_tls_verify_cert_hostnames)
+ /* Client side, check the server's certificate name versus the name on the
+ A-record for the connection we made. What to do for server side - what name
+ to use for client? We document that there is no such checking for server
+ side. */
+
+ if ( state->exp_tls_verify_cert_hostnames
+ && !gnutls_x509_crt_check_hostname(state->tlsp->peercert,
+ CS state->exp_tls_verify_cert_hostnames)
+ )
{
- int sep = 0;
- const uschar * list = state->exp_tls_verify_cert_hostnames;
- uschar * name;
- while ((name = string_nextinlist(&list, &sep, NULL, 0)))
- if (gnutls_x509_crt_check_hostname(state->tlsp->peercert, CS name))
- break;
- if (!name)
- {
- DEBUG(D_tls)
- debug_printf("TLS certificate verification failed: cert name mismatch\n");
- if (state->verify_requirement >= VERIFY_REQUIRED)
- goto badcert;
- return TRUE;
- }
+ DEBUG(D_tls)
+ debug_printf("TLS certificate verification failed: cert name mismatch\n");
+ if (state->verify_requirement >= VERIFY_REQUIRED)
+ goto badcert;
+ return TRUE;
}
+
state->peer_cert_verified = TRUE;
DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=\"%s\"\n",
state->peerdn ? state->peerdn : US"<unset>");
else if (inbytes < 0)
{
+debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
record_io_error(state, (int) inbytes, US"recv", NULL);
state->xfer_error = TRUE;
return FALSE;
{
DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
}
-else record_io_error(state, (int)inbytes, US"recv", NULL);
+else
+{
+debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+record_io_error(state, (int)inbytes, US"recv", NULL);
+}
return -1;
}
DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes);
if (outbytes < 0)
{
+debug_printf("%s: err from gnutls_record_send(\n", __FUNCTION__);
record_io_error(state, outbytes, US"send", NULL);
return -1;
}