WIP
[exim.git] / src / src / tls-openssl.c
index 7a3ca81c269dae57a7bf6065ab9fbc4b1623493b..4dfeac06d35f12586174fe042ca2af6d5a641f0d 100644 (file)
@@ -28,7 +28,7 @@ functions from the OpenSSL library. */
 #ifndef DISABLE_OCSP
 # include <openssl/ocsp.h>
 #endif
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 # include "danessl.h"
 #endif
 
@@ -152,6 +152,7 @@ typedef struct tls_ext_ctx_cb {
   uschar *certificate;
   uschar *privatekey;
   BOOL is_server;
+  STACK_OF(X509_NAME) * acceptable_certnames;
 #ifndef DISABLE_OCSP
   STACK_OF(X509) *verify_stack;                /* chain for verifying the proof */
   union {
@@ -512,7 +513,7 @@ return verify_callback(preverify_ok, x509ctx, &tls_in,
 }
 
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 
 /* This gets called *by* the dane library verify callback, which interposes
 itself.
@@ -566,7 +567,7 @@ else
 return preverify_ok;
 }
 
-#endif /*EXPERIMENTAL_DANE*/
+#endif /*SUPPORT_DANE*/
 
 
 /*************************************************
@@ -1510,6 +1511,7 @@ cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
 cbinfo->certificate = certificate;
 cbinfo->privatekey = privatekey;
 cbinfo->is_server = host==NULL;
+cbinfo->acceptable_certnames = NULL;
 #ifndef DISABLE_OCSP
 cbinfo->verify_stack = NULL;
 if (!host)
@@ -1754,6 +1756,9 @@ chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack)
 BIO * bp;
 X509 * x;
 
+while (sk_X509_num(verify_stack) > 0)
+  X509_free(sk_X509_pop(verify_stack));
+
 if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
 while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)))
   sk_X509_push(verify_stack, x);
@@ -1763,7 +1768,8 @@ return TRUE;
 
 
 
-/* Called by both client and server startup
+/* Called by both client and server startup; on the server possibly
+repeated after a Server Name Indication.
 
 Arguments:
   sctx          SSL_CTX* to initialise
@@ -1853,11 +1859,21 @@ if (expcerts && *expcerts)
       */
       if (file)
        {
-       STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
+       tls_ext_ctx_cb * cbinfo = host
+         ? client_static_cbinfo : server_static_cbinfo;
+       STACK_OF(X509_NAME) * names;
 
+       if ((names = cbinfo->acceptable_certnames))
+         {
+         sk_X509_NAME_pop_free(names, X509_NAME_free);
+         cbinfo->acceptable_certnames = NULL;
+         }
+       names = SSL_load_client_CA_file(CS file);
+
+       SSL_CTX_set_client_CA_list(sctx, names);
        DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
                                    sk_X509_NAME_num(names));
-       SSL_CTX_set_client_CA_list(sctx, names);
+       cbinfo->acceptable_certnames = names;
        }
       }
     }
@@ -1996,7 +2012,7 @@ if (expciphers)
 optional, set up appropriately. */
 
 tls_in.certificate_verified = FALSE;
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 tls_in.dane_verified = FALSE;
 #endif
 server_verify_callback_called = FALSE;
@@ -2095,7 +2111,7 @@ DEBUG(D_tls)
    smtp_read_response()/ip_recv().
    Hence no need to duplicate for _in and _out.
  */
-ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
+if (!ssl_xfer_buffer) ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
 ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
 ssl_xfer_eof = ssl_xfer_error = 0;
 
@@ -2155,7 +2171,7 @@ return OK;
 }
 
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 static int
 dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa, uschar ** errstr)
 {
@@ -2210,7 +2226,7 @@ if (found)
 log_write(0, LOG_MAIN, "DANE error: No usable TLSA records");
 return DEFER;
 }
-#endif /*EXPERIMENTAL_DANE*/
+#endif /*SUPPORT_DANE*/
 
 
 
@@ -2236,7 +2252,7 @@ Returns:           OK on success
 int
 tls_client_start(int fd, host_item *host, address_item *addr,
   transport_instance * tb,
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
   dns_answer * tlsa_dnsa,
 #endif
   uschar ** errstr)
@@ -2253,13 +2269,13 @@ BOOL request_ocsp = FALSE;
 BOOL require_ocsp = FALSE;
 #endif
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 tls_out.tlsa_usage = 0;
 #endif
 
 #ifndef DISABLE_OCSP
   {
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
   if (  tlsa_dnsa
      && ob->hosts_request_ocsp[0] == '*'
      && ob->hosts_request_ocsp[1] == '\0'
@@ -2277,7 +2293,7 @@ tls_out.tlsa_usage = 0;
        verify_check_given_host(&ob->hosts_require_ocsp, host) == OK))
     request_ocsp = TRUE;
   else
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
     if (!request_ocsp)
 # endif
       request_ocsp =
@@ -2313,7 +2329,7 @@ if (expciphers)
     return tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr);
   }
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
   {
   SSL_CTX_set_verify(client_ctx,
@@ -2361,7 +2377,7 @@ if (ob->tls_sni)
     }
   }
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
   if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa, errstr)) != OK)
     return rc;
@@ -2370,7 +2386,7 @@ if (tlsa_dnsa)
 #ifndef DISABLE_OCSP
 /* Request certificate status at connection-time.  If the server
 does OCSP stapling we will get the callback (set in tls_init()) */
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
 if (request_ocsp)
   {
   const uschar * s;
@@ -2407,7 +2423,7 @@ alarm(ob->command_timeout);
 rc = SSL_connect(client_ssl);
 alarm(0);
 
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
 if (tlsa_dnsa)
   DANESSL_cleanup(client_ssl);
 #endif
@@ -2468,7 +2484,16 @@ if (error == SSL_ERROR_ZERO_RETURN)
   receive_ferror = smtp_ferror;
   receive_smtp_buffered = smtp_buffered;
 
+  if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
+       SSL_shutdown(server_ssl);
+
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  sk_X509_NAME_pop_free(server_static_cbinfo->acceptable_certnames, X509_NAME_free);
   SSL_free(server_ssl);
+  SSL_CTX_free(server_ctx);
+  server_static_cbinfo->verify_stack = NULL;
+  server_static_cbinfo->acceptable_certnames = NULL;
+  server_ctx = NULL;
   server_ssl = NULL;
   tls_in.active = -1;
   tls_in.bits = 0;
@@ -2702,15 +2727,19 @@ return len;
 daemon, to shut down the TLS library, without actually doing a shutdown (which
 would tamper with the SSL session in the parent process).
 
-Arguments:   TRUE if SSL_shutdown 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
 
 Used by both server-side and client-side TLS.
 */
 
 void
-tls_close(BOOL is_server, BOOL shutdown)
+tls_close(BOOL is_server, int shutdown)
 {
+SSL_CTX **ctxp = is_server ? &server_ctx : &client_ctx;
 SSL **sslp = is_server ? &server_ssl : &client_ssl;
 int *fdp = is_server ? &tls_in.active : &tls_out.active;
 
@@ -2718,13 +2747,38 @@ if (*fdp < 0) return;  /* TLS was not active */
 
 if (shutdown)
   {
-  DEBUG(D_tls) debug_printf("tls_close(): shutting down SSL\n");
-  SSL_shutdown(*sslp);
+  int rc;
+  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+    shutdown > 1 ? " (with response-wait)" : "");
+
+  if (  (rc = SSL_shutdown(*sslp)) == 0        /* send "close notify" alert */
+     && shutdown > 1)
+    {
+    alarm(2);
+    rc = SSL_shutdown(*sslp);          /* wait for response */
+    alarm(0);
+    }
+
+  if (rc < 0) DEBUG(D_tls)
+    {
+    ERR_error_string(ERR_get_error(), ssl_errstring);
+    debug_printf("SSL_shutdown: %s\n", ssl_errstring);
+    }
+  }
+
+if (is_server)
+  {
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  sk_X509_NAME_pop_free(server_static_cbinfo->acceptable_certnames,
+    X509_NAME_free);
+  server_static_cbinfo->verify_stack = NULL;
+  server_static_cbinfo->acceptable_certnames = NULL;
   }
 
+SSL_CTX_free(*ctxp);
 SSL_free(*sslp);
+*ctxp = NULL;
 *sslp = NULL;
-
 *fdp = -1;
 }