Testcases for dane_require_tls_ciphers
[exim.git] / src / src / tls-gnu.c
index 38e8eab09a3efc451a0579aa56dac61cd326846b..d73188277be2b6171d419023b70f5b56e7814c0b 100644 (file)
@@ -156,8 +156,8 @@ typedef struct exim_gnutls_state {
   uschar *xfer_buffer;
   int xfer_buffer_lwm;
   int xfer_buffer_hwm;
-  int xfer_eof;
-  int xfer_error;
+  BOOL xfer_eof;       /*XXX never gets set! */
+  BOOL xfer_error;
 } exim_gnutls_state_st;
 
 static const exim_gnutls_state_st exim_gnutls_state_init = {
@@ -198,8 +198,8 @@ static const exim_gnutls_state_st exim_gnutls_state_init = {
   .xfer_buffer =       NULL,
   .xfer_buffer_lwm =   0,
   .xfer_buffer_hwm =   0,
-  .xfer_eof =          0,
-  .xfer_error =                0,
+  .xfer_eof =          FALSE,
+  .xfer_error =                FALSE,
 };
 
 /* Not only do we have our own APIs which don't pass around state, assuming
@@ -1621,7 +1621,7 @@ else
     (needed for TA but not EE). */
 
     if (usage == ((1<<DANESSL_USAGE_DANE_TA) | (1<<DANESSL_USAGE_DANE_EE)))
-    {                                          /* a mixed-usage bundle */
+      {                                                /* a mixed-usage bundle */
       int i, j, nrec;
       const char ** dd;
       int * ddl;
@@ -1681,7 +1681,7 @@ else
                        1, 0))
         || (rc = dane_verify_crt_raw(s, certlist, lsize,
                        gnutls_certificate_type_get(state->session),
-                       r, 0, 
+                       r, 0,
 # ifdef GNUTLS_BROKEN_DANE_VALIDATION
                        usage == (1 << DANESSL_USAGE_DANE_EE)
                        ? DANE_VFLAG_ONLY_CHECK_EE_USAGE : 0,
@@ -1920,12 +1920,10 @@ int rc;
 uschar * yield;
 exim_gnutls_state_st * state = gnutls_session_get_ptr(session);
 
-cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
-if (cert_list)
+if ((cert_list = gnutls_certificate_get_peers(session, &cert_list_size)))
   while (cert_list_size--)
   {
-  rc = import_cert(&cert_list[cert_list_size], &crt);
-  if (rc != GNUTLS_E_SUCCESS)
+  if ((rc = import_cert(&cert_list[cert_list_size], &crt)) != GNUTLS_E_SUCCESS)
     {
     DEBUG(D_tls) debug_printf("TLS: peer cert problem: depth %d: %s\n",
       cert_list_size, gnutls_strerror(rc));
@@ -2262,6 +2260,7 @@ smtp_transport_options_block *ob =
   (smtp_transport_options_block *)tb->options_block;
 int rc;
 exim_gnutls_state_st * state = NULL;
+uschar *cipher_list = NULL;
 #ifndef DISABLE_OCSP
 BOOL require_ocsp =
   verify_check_given_host(&ob->hosts_require_ocsp, host) == OK;
@@ -2271,9 +2270,24 @@ BOOL request_ocsp = require_ocsp ? TRUE
 
 DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd);
 
+#ifdef SUPPORT_DANE
+if (tlsa_dnsa && ob->dane_require_tls_ciphers)
+  {
+  /* not using expand_check_tlsvar because not yet in state */
+  if (!expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers",
+      &cipher_list, errstr))
+    return DEFER;
+  cipher_list = cipher_list && *cipher_list
+    ? ob->dane_require_tls_ciphers : ob->tls_require_ciphers;
+  }
+#endif
+
+if (!cipher_list)
+  cipher_list = ob->tls_require_ciphers;
+
 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, errstr)) != OK)
+    cipher_list, &state, errstr)) != OK)
   return rc;
 
   {
@@ -2442,12 +2456,15 @@ return OK;
 daemon, to shut down the TLS library, without actually doing a shutdown (which
 would tamper with the TLS session in the parent process).
 
-Arguments:   TRUE if gnutls_bye is to be called
+Arguments:
+  shutdown     1 if TLS close-alert is to be sent,
+               2 if also response to be waited for
+
 Returns:     nothing
 */
 
 void
-tls_close(BOOL is_server, BOOL shutdown)
+tls_close(BOOL is_server, int shutdown)
 {
 exim_gnutls_state_st *state = is_server ? &state_server : &state_client;
 
@@ -2455,8 +2472,12 @@ if (!state->tlsp || state->tlsp->active < 0) return;  /* TLS was not active */
 
 if (shutdown)
   {
-  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n");
-  gnutls_bye(state->session, GNUTLS_SHUT_WR);
+  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+    shutdown > 1 ? " (with response-wait)" : "");
+
+  alarm(2);
+  gnutls_bye(state->session, shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+  alarm(0);
   }
 
 gnutls_deinit(state->session);
@@ -2500,7 +2521,7 @@ alarm(0);
 if (sigalrm_seen)
   {
   DEBUG(D_tls) debug_printf("Got tls read timeout\n");
-  state->xfer_error = 1;
+  state->xfer_error = TRUE;
   return FALSE;
   }
 
@@ -2536,7 +2557,7 @@ else if (inbytes == 0)
 else if (inbytes < 0)
   {
   record_io_error(state, (int) inbytes, US"recv", NULL);
-  state->xfer_error = 1;
+  state->xfer_error = TRUE;
   return FALSE;
   }
 #ifndef DISABLE_DKIM