[exim-cvs] TLS: pre-generate and load server selfsigned cert…

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Exim Git Commits Mailing List
Datum:  
To: exim-cvs
Betreff: [exim-cvs] TLS: pre-generate and load server selfsigned cert, when one is to be used
Gitweb: https://git.exim.org/exim.git/commitdiff/48e909900663856b9b1225f5df4cd033302f1bcd
Commit:     48e909900663856b9b1225f5df4cd033302f1bcd
Parent:     6bacc7090a4d219a48899c5b5b08b33f4811dc7f
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Tue Oct 13 17:12:33 2020 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Tue Oct 13 17:12:33 2020 +0100


        TLS: pre-generate and load server selfsigned cert, when one is to be used
---
 src/src/tls-gnu.c              | 33 +++++++++++++++++++++----------
 src/src/tls-openssl.c          | 24 +++++++++++++++++++---
 src/src/tls.c                  | 45 ++++++++++++++++++++++++------------------
 test/confs/2120                |  1 -
 test/log/2020                  |  9 +++++++--
 test/log/2120                  | 10 ++++++++--
 test/scripts/2000-GnuTLS/2020  |  5 ++++-
 test/scripts/2100-OpenSSL/2120 |  5 ++++-
 8 files changed, 93 insertions(+), 39 deletions(-)


diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 9b684e3..b14bca4 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -929,7 +929,7 @@ return OK;



-/* Create and install a selfsigned certificate, for use in server mode */
+/* Create and install a selfsigned certificate, for use in server mode. */

static int
tls_install_selfsign(exim_gnutls_state_st * state, uschar ** errstr)
@@ -946,6 +946,7 @@ rc = GNUTLS_E_NO_CERTIFICATE_FOUND;
if (TRUE) goto err;
#endif

+DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n");
where = US"initialising pkey";
if ((rc = gnutls_x509_privkey_init(&pkey))) goto err;

@@ -970,7 +971,7 @@ now = 1;
 if (  (rc = gnutls_x509_crt_set_version(cert, 3))
    || (rc = gnutls_x509_crt_set_serial(cert, &now, sizeof(now)))
    || (rc = gnutls_x509_crt_set_activation_time(cert, now = time(NULL)))
-   || (rc = gnutls_x509_crt_set_expiration_time(cert, now + 60 * 60)) /* 1 hr */
+   || (rc = gnutls_x509_crt_set_expiration_time(cert, (long)2 * 60 * 60))    /* 2 hour */
    || (rc = gnutls_x509_crt_set_key(cert, pkey))


    || (rc = gnutls_x509_crt_set_dn_by_oid(cert,
@@ -1421,26 +1422,25 @@ return gnutls_priority_init( (gnutls_priority_t *) &state->lib_state.pri_cache,
   CCS p, errpos);
 }


-static void
+static unsigned
tls_server_creds_init(void)
{
uschar * dummy_errstr;
+unsigned lifetime = 0;

 state_server.lib_state = null_tls_preload;
 if (gnutls_certificate_allocate_credentials(
       (gnutls_certificate_credentials_t *) &state_server.lib_state.x509_cred))
   {
   state_server.lib_state.x509_cred = NULL;
-  return;
+  return lifetime;
   }
 creds_basic_init(state_server.lib_state.x509_cred, TRUE);


#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
/* If tls_certificate has any $ indicating expansions, it is not good.
If tls_privatekey is set but has $, not good. Likewise for tls_ocsp_file.
-If all good (and tls_certificate set), load the cert(s). Do not try
-to handle selfsign generation for now (tls_certificate null/empty;
-XXX will want to do that later though) due to the lifetime/expiry issue. */
+If all good (and tls_certificate set), load the cert(s). */

 if (  opt_set_and_noexpand(tls_certificate)
 # ifndef DISABLE_OCSP
@@ -1470,6 +1470,18 @@ if (  opt_set_and_noexpand(tls_certificate)
       state_server.lib_state.conn_certs = TRUE;
     }
   }
+else if (  !tls_certificate && !tls_privatekey
+# ifndef DISABLE_OCSP
+    && !tls_ocsp_file
+# endif
+    )
+  {        /* Generate & preload a selfsigned cert. No files to watch. */
+  if ((tls_install_selfsign(&state_server, &dummy_errstr)) == OK)
+    {
+    state_server.lib_state.conn_certs = TRUE;
+    lifetime = f.running_in_test_harness ? 2 : 60 * 60;        /* 1 hour */
+    }
+  }
 else
   DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");


@@ -1482,7 +1494,7 @@ if (opt_set_and_noexpand(tls_verify_certificates))
     DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
     if (creds_load_cabundle(&state_server, tls_verify_certificates,
                 NULL, &dummy_errstr) != OK)
-      return;
+      return lifetime;
     state_server.lib_state.cabundle = TRUE;


     /* If CAs loaded and tls_crl is non-empty and has no $, load it */
@@ -1493,7 +1505,7 @@ if (opt_set_and_noexpand(tls_verify_certificates))
     {
     DEBUG(D_tls) debug_printf("TLS: preloading CRL for server\n");
     if (creds_load_crl(&state_server, tls_crl, &dummy_errstr) != OK)
-      return;
+      return lifetime;
     state_server.lib_state.crl = TRUE;
     }
       }
@@ -1520,6 +1532,7 @@ if (!tls_require_ciphers || opt_set_and_noexpand(tls_require_ciphers))
   }
 else
   DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n");
+return lifetime;
 }



@@ -1990,7 +2003,7 @@ state->tls_require_ciphers =    require_ciphers;
 state->host = host;


/* This handles the variables that might get re-expanded after TLS SNI;
-that's tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */
+tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */

DEBUG(D_tls)
debug_printf("Expanding various TLS configuration options for session credentials\n");
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 700b01d..0dfd8e0 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -794,6 +794,9 @@ return rsa_key;


/* Create and install a selfsigned certificate, for use in server mode */
+/*XXX we could arrange to call this during prelo for a null tls_certificate option.
+The normal cache inval + relo will suffice.
+Just need a timer for inval. */

static int
tls_install_selfsign(SSL_CTX * sctx, uschar ** errstr)
@@ -804,6 +807,7 @@ RSA * rsa;
X509_NAME * name;
uschar * where;

+DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n");
 where = US"allocating pkey";
 if (!(pkey = EVP_PKEY_new()))
   goto err;
@@ -823,7 +827,7 @@ if (!EVP_PKEY_assign_RSA(pkey, rsa))
 X509_set_version(x509, 2);                /* N+1 - version 3 */
 ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
 X509_gmtime_adj(X509_get_notBefore(x509), 0);
-X509_gmtime_adj(X509_get_notAfter(x509), (long)60 * 60);    /* 1 hour */
+X509_gmtime_adj(X509_get_notAfter(x509), (long)2 * 60 * 60);    /* 2 hour */
 X509_set_pubkey(x509, pkey);


name = X509_get_subject_name(x509);
@@ -1619,18 +1623,19 @@ return OK;
}


-static void
+static unsigned
tls_server_creds_init(void)
{
SSL_CTX * ctx;
uschar * dummy_errstr;
+unsigned lifetime = 0;

tls_openssl_init();

state_server.lib_state = null_tls_preload;

if (lib_ctx_new(&ctx, NULL, &dummy_errstr) != OK)
- return;
+ return 0;
state_server.lib_state.lib_ctx = ctx;

 /* Preload DH params and EC curve */
@@ -1677,6 +1682,18 @@ if (  opt_set_and_noexpand(tls_certificate)
       state_server.lib_state.conn_certs = TRUE;
     }
   }
+else if (  !tls_certificate && !tls_privatekey
+# ifndef DISABLE_OCSP
+    && !tls_ocsp_file
+#endif
+   )
+  {        /* Generate & preload a selfsigned cert. No files to watch. */
+  if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
+    {
+    state_server.lib_state.conn_certs = TRUE;
+    lifetime = f.running_in_test_harness ? 2 : 60 * 60;        /* 1 hour */
+    }
+  }
 else
   DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");


@@ -1717,6 +1734,7 @@ if (opt_set_and_noexpand(tls_require_ciphers))
}
else
DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n");
+return lifetime;
}


diff --git a/src/src/tls.c b/src/src/tls.c
index 38d695d..c088c7d 100644
--- a/src/src/tls.c
+++ b/src/src/tls.c
@@ -38,7 +38,7 @@ functions from the OpenSSL or GNU TLS libraries. */

static void tls_per_lib_daemon_init(void);
static void tls_per_lib_daemon_tick(void);
-static void tls_server_creds_init(void);
+static unsigned tls_server_creds_init(void);
static void tls_server_creds_invalidate(void);
static void tls_client_creds_init(transport_instance *, BOOL);
static void tls_client_creds_invalidate(transport_instance *);
@@ -82,6 +82,8 @@ static struct kevent kev[KEV_SIZE];
static int kev_used = 0;
#endif

+static unsigned tls_creds_expire = 0;
+
 /*************************************************
 *       Expand string; give error on failure     *
 *************************************************/
@@ -291,20 +293,6 @@ struct timespec t = {0};
 (void) kevent(fd, NULL, 0, &kev, 1, &t);
 #endif
 }
-
-/* Called, after a delay for multiple file ops to get done, from
-the daemon when any of the watches added (above) fire.
-
-Dump the set of watches and arrange to reload cached creds (which
-will set up new watches). */
-
-static void
-tls_watch_triggered(void)
-{
-DEBUG(D_tls) debug_printf("watch triggered\n");
-
-tls_daemon_creds_reload();
-}
 #endif    /*EXIM_HAVE_INOTIFY*/



@@ -343,12 +331,15 @@ tls_watch_fd = -1;
static void
tls_daemon_creds_reload(void)
{
+unsigned lifetime;
+
#ifdef EXIM_HAVE_KEVENT
tls_watch_invalidate();
#endif

tls_server_creds_invalidate();
-tls_server_creds_init();
+tls_creds_expire = (lifetime = tls_server_creds_init())
+ ? time(NULL) + lifetime : 0;

tls_client_creds_reload(TRUE);
}
@@ -372,10 +363,26 @@ tls_daemon_tick(void)
{
tls_per_lib_daemon_tick();
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
-if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5)
+if (tls_creds_expire && time(NULL) >= tls_creds_expire)
+ {
+ /* The server cert is a selfsign, with limited lifetime. Dump it and
+ generate a new one. Reload the rest of the creds also as the machinery
+ is all there. */
+
+ DEBUG(D_tls) debug_printf("selfsign cert rotate\n");
+ tls_creds_expire = 0;
+ tls_daemon_creds_reload();
+ }
+else if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5)
{
- tls_watch_trigger_time = 0;
- tls_watch_triggered();
+ /* Called, after a delay for multiple file ops to get done, from
+ the daemon when any of the watches added (above) fire.
+ Dump the set of watches and arrange to reload cached creds (which
+ will set up new watches). */
+
+ DEBUG(D_tls) debug_printf("watch triggered\n");
+ tls_watch_trigger_time = tls_creds_expire = 0;
+ tls_daemon_creds_reload();
}
#endif
}
diff --git a/test/confs/2120 b/test/confs/2120
index 9469cb7..ea9111c 100644
--- a/test/confs/2120
+++ b/test/confs/2120
@@ -13,7 +13,6 @@ acl_smtp_rcpt = accept
log_selector = +tls_peerdn

queue_only
-queue_run_in_order

tls_advertise_hosts = *

diff --git a/test/log/2020 b/test/log/2020
index fbf9039..1d45378 100644
--- a/test/log/2020
+++ b/test/log/2020
@@ -1,11 +1,16 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@??? R=abc T=t1 H=thishost.test.ex [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no DN="C=UK,O=Exim Developers,CN=thishost.test.ex" C="250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userx@??? R=abc T=t1 H=thishost.test.ex [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no DN="C=UK,O=Exim Developers,CN=thishost.test.ex" C="250 OK id=10HmaZ-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp

******** SERVER ********
1999-03-02 09:44:33 Warning: No server certificate defined; will use a selfsigned one.
Suggested action: either install a certificate or change tls_advertise_hosts option
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@??? H=localhost (thishost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@???
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@??? H=localhost (thishost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@???
diff --git a/test/log/2120 b/test/log/2120
index 8057655..d4a754d 100644
--- a/test/log/2120
+++ b/test/log/2120
@@ -1,12 +1,18 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp
1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=Exim Developers/CN=thishost.test.ex
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@??? R=abc T=t1 H=thishost.test.ex [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no DN="/C=UK/O=Exim Developers/CN=thishost.test.ex" C="250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=Exim Developers/CN=thishost.test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userx@??? R=abc T=t1 H=thishost.test.ex [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no DN="/C=UK/O=Exim Developers/CN=thishost.test.ex" C="250 OK id=10HmaZ-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp

******** SERVER ********
1999-03-02 09:44:33 Warning: No server certificate defined; will use a selfsigned one.
Suggested action: either install a certificate or change tls_advertise_hosts option
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@??? H=localhost (thishost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@???
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@??? H=localhost (thishost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@???
diff --git a/test/scripts/2000-GnuTLS/2020 b/test/scripts/2000-GnuTLS/2020
index 3203ab4..28835a5 100644
--- a/test/scripts/2000-GnuTLS/2020
+++ b/test/scripts/2000-GnuTLS/2020
@@ -5,7 +5,10 @@ exim -DSERVER=server -bd -oX PORT_D
exim userx
Test
****
-exim -qf
+exim -q
+****
+sleep 4
+exim -q
****
killdaemon
no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2120 b/test/scripts/2100-OpenSSL/2120
index 53cd813..e4f2c82 100644
--- a/test/scripts/2100-OpenSSL/2120
+++ b/test/scripts/2100-OpenSSL/2120
@@ -4,7 +4,10 @@ exim -DSERVER=server -bd -oX PORT_D
exim userx
Test
****
-exim -qf
+exim -q
+****
+sleep 4
+exim -q
****
killdaemon
no_msglog_check