From: Jeremy Harris Date: Tue, 6 May 2014 07:44:59 +0000 (+0100) Subject: Refactor tls_client_init interface X-Git-Tag: exim-4_83_RC1~34 X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=commitdiff_plain;h=65867078f62db450bd8f91100600f6de559e7590 Refactor tls_client_init interface --- diff --git a/src/src/functions.h b/src/src/functions.h index 566a32bd6..8d249b8f2 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -40,11 +40,7 @@ extern uschar * tls_cert_subject_altname(void *, uschar * mod); 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); diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 880aaeb14..d0e1c35d7 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -1610,17 +1610,7 @@ Arguments: 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 @@ -1629,58 +1619,58 @@ Returns: OK/DEFER/FAIL (because using common functions), 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; @@ -1697,9 +1687,8 @@ else 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); } @@ -1713,7 +1702,7 @@ DEBUG(D_tls) debug_printf("about to gnutls_handshake\n"); /* 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); @@ -1747,14 +1736,13 @@ if (require_ocsp) && (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"); diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 2f08e43c6..66fca7dbb 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -1477,17 +1477,7 @@ Argument: 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 @@ -1496,26 +1486,21 @@ Returns: OK on success 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 @@ -1525,7 +1510,8 @@ if (rc != OK) return rc; 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 @@ -1542,30 +1528,33 @@ if (expciphers != NULL) } /* 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) { @@ -1597,7 +1586,7 @@ if (require_ocsp) 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); diff --git a/src/src/tls.c b/src/src/tls.c index ad7fe609c..f0ac60308 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -17,6 +17,7 @@ functions from the OpenSSL or GNU TLS libraries. */ #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 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 16c2b6011..7223f9c89 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1446,22 +1446,7 @@ if (tls_offered && !suppress_tls && 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 diff --git a/src/src/verify.c b/src/src/verify.c index c5ffdae4e..ea733b605 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -636,16 +636,12 @@ else /* 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. */ diff --git a/test/stderr/5410 b/test/stderr/5410 index 334301139..b84c26492 100644 --- a/test/stderr/5410 +++ b/test/stderr/5410 @@ -80,6 +80,7 @@ expanding: ${if eq {$address_data}{userz}{*}{:}} 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 diff --git a/test/stderr/5420 b/test/stderr/5420 index 36d163f25..d2fb575b5 100644 --- a/test/stderr/5420 +++ b/test/stderr/5420 @@ -80,6 +80,9 @@ expanding: ${if eq {$address_data}{userz}{*}{:}} 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