extern uschar * tls_cert_version(void *, uschar * mod);
extern int tls_client_start(int, host_item *, address_item *,
- uschar *, uschar *, uschar *, uschar *, uschar *, uschar *,
-# ifdef EXPERIMENTAL_OCSP
- uschar *,
-# endif
- int, int, uschar *, uschar *);
+ void *);
extern void tls_close(BOOL, BOOL);
extern int tls_export_cert(uschar *, size_t, void *);
extern int tls_feof(void);
fd the fd of the connection
host connected host (for messages)
addr the first address (not used)
- certificate certificate file
- privatekey private key file
- sni TLS SNI to send to remote host
- verify_certs file for certificate verify
- verify_crl CRL for verify
- require_ciphers list of allowed ciphers or NULL
- hosts_require_ocsp hosts for which to request certificate-status (OCSP)
- dh_min_bits minimum number of bits acceptable in server's DH prime
- timeout startup timeout
- verify_hosts mandatory client verification
- try_verify_hosts optional client verification
+ ob smtp transport options
Returns: OK/DEFER/FAIL (because using common functions),
but for a client, DEFER and FAIL have the same meaning
int
tls_client_start(int fd, host_item *host,
address_item *addr ARG_UNUSED,
- uschar *certificate, uschar *privatekey, uschar *sni,
- uschar *verify_certs, uschar *verify_crl,
- uschar *require_ciphers,
-#ifdef EXPERIMENTAL_OCSP
- uschar *hosts_require_ocsp,
-#endif
- int dh_min_bits, int timeout,
- uschar *verify_hosts, uschar *try_verify_hosts)
+ void *v_ob)
{
+smtp_transport_options_block *ob = v_ob;
int rc;
const char *error;
exim_gnutls_state_st *state = NULL;
#ifdef EXPERIMENTAL_OCSP
-BOOL require_ocsp = verify_check_this_host(&hosts_require_ocsp,
+BOOL require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp,
NULL, host->name, host->address, NULL) == OK;
#endif
DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd);
-if ((rc = tls_init(host, certificate, privatekey,
- sni, verify_certs, verify_crl, require_ciphers, &state)) != OK)
+if ((rc = tls_init(host, ob->tls_certificate, ob->tls_privatekey,
+ ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
+ ob->tls_require_ciphers, &state)) != OK)
return rc;
-if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS)
{
- DEBUG(D_tls)
- debug_printf("WARNING: tls_dh_min_bits far too low, clamping %d up to %d\n",
- dh_min_bits, EXIM_CLIENT_DH_MIN_MIN_BITS);
- dh_min_bits = EXIM_CLIENT_DH_MIN_MIN_BITS;
- }
+ int dh_min_bits = ob->tls_dh_min_bits;
+ if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS)
+ {
+ DEBUG(D_tls)
+ debug_printf("WARNING: tls_dh_min_bits far too low,"
+ " clamping %d up to %d\n",
+ dh_min_bits, EXIM_CLIENT_DH_MIN_MIN_BITS);
+ dh_min_bits = EXIM_CLIENT_DH_MIN_MIN_BITS;
+ }
-DEBUG(D_tls) debug_printf("Setting D-H prime minimum acceptable bits to %d\n",
- dh_min_bits);
-gnutls_dh_set_prime_bits(state->session, dh_min_bits);
+ DEBUG(D_tls) debug_printf("Setting D-H prime minimum"
+ " acceptable bits to %d\n",
+ dh_min_bits);
+ gnutls_dh_set_prime_bits(state->session, dh_min_bits);
+ }
/* Stick to the old behaviour for compatibility if tls_verify_certificates is
set but both tls_verify_hosts and tls_try_verify_hosts are unset. Check only
the specified host patterns if one of them is defined */
if (( state->exp_tls_verify_certificates
- && !verify_hosts
- && !try_verify_hosts
+ && !ob->tls_verify_hosts
+ && !ob->tls_try_verify_hosts
)
||
- verify_check_host(&verify_hosts) == OK
+ verify_check_host(&ob->tls_verify_hosts) == OK
)
{
DEBUG(D_tls) debug_printf("TLS: server certificate verification required.\n");
state->verify_requirement = VERIFY_REQUIRED;
gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
}
-else if (verify_check_host(&try_verify_hosts) == OK)
+else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
{
DEBUG(D_tls) debug_printf("TLS: server certificate verification optional.\n");
state->verify_requirement = VERIFY_OPTIONAL;
if (require_ocsp)
{
DEBUG(D_tls) debug_printf("TLS: will request OCSP stapling\n");
- rc = gnutls_ocsp_status_request_enable_client(state->session,
- NULL, 0, NULL);
- if (rc != OK)
+ if ((rc = gnutls_ocsp_status_request_enable_client(state->session,
+ NULL, 0, NULL)) != OK)
return tls_error(US"cert-status-req",
gnutls_strerror(rc), state->host);
}
/* There doesn't seem to be a built-in timeout on connection. */
sigalrm_seen = FALSE;
-alarm(timeout);
+alarm(ob->command_timeout);
do
{
rc = gnutls_handshake(state->session);
&& (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
)
{
- fprintf(stderr, "%.4096s", printed.data);
+ debug_printf("%.4096s", printed.data);
gnutls_free(printed.data);
}
else
(void) tls_error(US"ocsp decode", gnutls_strerror(rc), state->host);
}
- fprintf(stderr, "%s: checking ocsp\n", __FUNCTION__);
if (gnutls_ocsp_status_request_is_checked(state->session, 0) == 0)
return tls_error(US"certificate status check failed", NULL, state->host);
DEBUG(D_tls) debug_printf("Passed OCSP checking\n");
fd the fd of the connection
host connected host (for messages)
addr the first address
- certificate certificate file
- privatekey private key file
- sni TLS SNI to send to remote host
- verify_certs file for certificate verify
- crl file containing CRL
- require_ciphers list of allowed ciphers
- dh_min_bits minimum number of bits acceptable in server's DH prime
- (unused in OpenSSL)
- timeout startup timeout
- verify_hosts mandatory client verification
- try_verify_hosts optional client verification
+ ob smtp transport options
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,
- uschar *certificate, uschar *privatekey, uschar *sni,
- uschar *verify_certs, uschar *crl,
- uschar *require_ciphers,
-#ifdef EXPERIMENTAL_OCSP
- uschar *hosts_require_ocsp,
-#endif
- int dh_min_bits ARG_UNUSED, int timeout,
- uschar *verify_hosts, uschar *try_verify_hosts)
+ void *v_ob)
{
+smtp_transport_options_block * ob = v_ob;
static uschar txt[256];
uschar *expciphers;
X509* server_cert;
int rc;
static uschar cipherbuf[256];
#ifdef EXPERIMENTAL_OCSP
-BOOL require_ocsp = verify_check_this_host(&hosts_require_ocsp,
+BOOL require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp,
NULL, host->name, host->address, NULL) == OK;
#endif
-rc = tls_init(&client_ctx, host, NULL, certificate, privatekey,
+rc = tls_init(&client_ctx, host, NULL,
+ ob->tls_certificate, ob->tls_privatekey,
#ifdef EXPERIMENTAL_OCSP
require_ocsp ? US"" : NULL,
#endif
tls_out.certificate_verified = FALSE;
client_verify_callback_called = FALSE;
-if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
+if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
+ &expciphers))
return FAIL;
/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
}
/* stick to the old behaviour for compatibility if tls_verify_certificates is
- set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only
+ 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 (((verify_hosts == NULL) && (try_verify_hosts == NULL)) ||
- (verify_check_host(&verify_hosts) == OK))
+if ((!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) ||
+ (verify_check_host(&ob->tls_verify_hosts) == OK))
{
- rc = setup_certs(client_ctx, verify_certs, crl, host, FALSE, verify_callback_client);
- if (rc != OK) return rc;
+ if ((rc = setup_certs(client_ctx, ob->tls_verify_certificates,
+ ob->tls_crl, host, FALSE, verify_callback_client)) != OK)
+ return rc;
client_verify_optional = FALSE;
}
-else if (verify_check_host(&try_verify_hosts) == OK)
+else if (verify_check_host(&ob->tls_try_verify_hosts) == OK)
{
- rc = setup_certs(client_ctx, verify_certs, crl, host, TRUE, verify_callback_client);
- if (rc != OK) return rc;
+ if ((rc = setup_certs(client_ctx, ob->tls_verify_certificates,
+ ob->tls_crl, host, TRUE, verify_callback_client)) != OK)
+ return rc;
client_verify_optional = TRUE;
}
-if ((client_ssl = SSL_new(client_ctx)) == NULL) return tls_error(US"SSL_new", host, NULL);
+if ((client_ssl = SSL_new(client_ctx)) == NULL)
+ return tls_error(US"SSL_new", host, NULL);
SSL_set_session_id_context(client_ssl, sid_ctx, Ustrlen(sid_ctx));
SSL_set_fd(client_ssl, fd);
SSL_set_connect_state(client_ssl);
-if (sni)
+if (ob->tls_sni)
{
- if (!expand_check(sni, US"tls_sni", &tls_out.sni))
+ if (!expand_check(ob->tls_sni, US"tls_sni", &tls_out.sni))
return FAIL;
if (tls_out.sni == NULL)
{
DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
sigalrm_seen = FALSE;
-alarm(timeout);
+alarm(ob->command_timeout);
rc = SSL_connect(client_ssl);
alarm(0);
#include "exim.h"
+#include "transports/smtp.h"
/* This module is compiled only when it is specifically requested in the
build-time configuration. However, some compilers don't like compiling empty
else
TLS_NEGOTIATE:
{
- int rc = tls_client_start(inblock.sock,
- host,
- addrlist,
- ob->tls_certificate,
- ob->tls_privatekey,
- ob->tls_sni,
- ob->tls_verify_certificates,
- ob->tls_crl,
- ob->tls_require_ciphers,
-#ifdef EXPERIMENTAL_OCSP
- ob->hosts_require_ocsp,
-#endif
- ob->tls_dh_min_bits,
- ob->command_timeout,
- ob->tls_verify_hosts,
- ob->tls_try_verify_hosts);
+ int rc = tls_client_start(inblock.sock, host, addrlist, ob);
/* 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
/* STARTTLS accepted or ssl-on-connect: try to negotiate a TLS session. */
else
{
- int rc = tls_client_start(inblock.sock, host, addr,
- ob->tls_certificate, ob->tls_privatekey,
- ob->tls_sni,
- ob->tls_verify_certificates, ob->tls_crl,
- ob->tls_require_ciphers,
-#ifdef EXPERIMENTAL_OCSP
- ob->hosts_require_ocsp,
-#endif
- ob->tls_dh_min_bits, callout,
- ob->tls_verify_hosts, ob->tls_try_verify_hosts);
+ int oldtimeout = ob->command_timeout;
+ int rc;
+
+ ob->command_timeout = callout;
+ rc = tls_client_start(inblock.sock, host, addr, ob);
+ ob->command_timeout = oldtimeout;
/* TLS negotiation failed; give an error. Try in clear on a new connection,
if the options permit it for this host. */
127.0.0.1 in hosts_verify_avoid_tls? no (end of list)
SMTP>> STARTTLS
SMTP<< 220 TLS go ahead
+127.0.0.1 in hosts_require_ocsp? no (option unset)
SMTP>> EHLO myhost.test.ex
SMTP<< 250-myhost.test.ex Hello the.local.host.name [ip4.ip4.ip4.ip4]
250-SIZE 52428800
127.0.0.1 in hosts_verify_avoid_tls? no (end of list)
SMTP>> STARTTLS
SMTP<< 220 TLS go ahead
+127.0.0.1 in hosts_require_ocsp? no (option unset)
+ in tls_verify_hosts? no (option unset)
+ in tls_try_verify_hosts? no (option unset)
SMTP>> EHLO myhost.test.ex
SMTP<< 250-myhost.test.ex Hello the.local.host.name [ip4.ip4.ip4.ip4]
250-SIZE 52428800