Refactor tls_client_init interface
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 6 May 2014 07:44:59 +0000 (08:44 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 6 May 2014 09:25:19 +0000 (10:25 +0100)
src/src/functions.h
src/src/tls-gnu.c
src/src/tls-openssl.c
src/src/tls.c
src/src/transports/smtp.c
src/src/verify.c
test/stderr/5410
test/stderr/5420

index 566a32bd6af64295825d6699d87b042cb2539b05..8d249b8f25bc16f4c9cdab3bcdb02d538e97125f 100644 (file)
@@ -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);
index 880aaeb14831565a9ae4b752bfe2506f687c2c72..d0e1c35d77af1036112b658096cc25937a9aea08 100644 (file)
@@ -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");
index 2f08e43c66cd887e6d1fb74bf73bfd6168958f2e..66fca7dbbd42c1a8b981e34fa20b8192caf28042 100644 (file)
@@ -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);
 
index ad7fe609c26d06e9bcb47f437e31a73cfe08f3cb..f0ac6030899322ebee9d938334ac8d8dda246817 100644 (file)
@@ -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
index 16c2b601166ff8ceb02e01e342e5bb5bee029e0b..7223f9c89fdec622ceb7518420f3bf268cfec81b 100644 (file)
@@ -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
index c5ffdae4e7d9a4045f594c1453b4f8dd47d23bbb..ea733b60596dae968d61efdd382853cff059ad10 100644 (file)
@@ -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. */
index 334301139792122ee7f4d28224e110f77cbbee7d..b84c2649210c8cf5c54d8bf4e4ab04742b95510d 100644 (file)
@@ -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
index 36d163f2539eba792c38afc4779cf726b0bcd79d..d2fb575b524b0906376c9510233f2a7e6abaf831 100644 (file)
@@ -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