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 *,
 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);
 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)
   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
 
 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,
 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
 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);
 
   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;
 
   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
 
 /* 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);
   }
    )
   {
   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;
   {
   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");
 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);
   }
     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;
 /* 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);
 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
        )
       {
        && (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);
     }
 
       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");
   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
   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
 
 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,
 
 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
 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
 
   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
 #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;
 
 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
   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 
   }
 
 /* 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 */
    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;
   }
   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;
   }
 
   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);
 
 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)
     {
     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;
 
 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);
 
 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 "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
 
 /* 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:
     {
   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
 
     /* 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
         {
        /* 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. */
 
         /* 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_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
   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_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
   SMTP>> EHLO myhost.test.ex
   SMTP<< 250-myhost.test.ex Hello the.local.host.name [ip4.ip4.ip4.ip4]
          250-SIZE 52428800