TLS: Session resumption, under the EXPERIMENTAL_TLS_RESUME build option.
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 2 May 2019 16:16:05 +0000 (17:16 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 2 May 2019 16:23:05 +0000 (17:23 +0100)
53 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
doc/doc-txt/experimental-spec.txt
src/OS/Makefile-Base
src/src/acl.c
src/src/config.h.defaults
src/src/daemon.c
src/src/dbfn.c
src/src/dbfunctions.h
src/src/dbstuff.h
src/src/deliver.c
src/src/enq.c
src/src/exim.c
src/src/exim_dbutil.c
src/src/expand.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/macro_predef.c
src/src/macro_predef.h
src/src/macros.h
src/src/readconf.c
src/src/receive.c
src/src/retry.c
src/src/smtp_in.c
src/src/spool_in.c
src/src/spool_out.c
src/src/structs.h
src/src/tls-gnu.c
src/src/tls-openssl.c
src/src/tls.c
src/src/transport.c
src/src/transports/smtp.c
src/src/transports/smtp.h
src/src/verify.c
test/aux-var-src/tls_conf_prefix
test/confs/5890 [new file with mode: 0644]
test/confs/5891 [new file with mode: 0644]
test/log/2102
test/log/5890 [new file with mode: 0644]
test/log/5891 [new file with mode: 0644]
test/runtest
test/scripts/5890-Resume-GnuTLS/5890 [new file with mode: 0644]
test/scripts/5890-Resume-GnuTLS/REQUIRES [new file with mode: 0644]
test/scripts/5891-Resume-OpenSSL/5891 [new file with mode: 0644]
test/scripts/5891-Resume-OpenSSL/REQUIRES [new file with mode: 0644]
test/stderr/5890 [new file with mode: 0644]
test/stderr/5891 [new file with mode: 0644]
test/stdout/0572
test/stdout/0577
test/stdout/5890 [new file with mode: 0644]
test/stdout/5891 [new file with mode: 0644]

index 7a7608bd6153b766b98c4c2efacc28dd5e822099..783aeb429d70406a5c2d394fd83d396b9573558e 100644 (file)
@@ -16169,7 +16169,7 @@ harm. This option overrides the &%pipe_as_creator%& option of the &(pipe)&
 transport driver.
 
 
 transport driver.
 
 
-.option openssl_options main "string list" "+no_sslv2 +single_dh_use +no_ticket"
+.option openssl_options main "string list" "+no_sslv2 +no_sslv3 +single_dh_use +no_ticket"
 .cindex "OpenSSL "compatibility options"
 This option allows an administrator to adjust the SSL options applied
 by OpenSSL to connections.  It is given as a space-separated list of items,
 .cindex "OpenSSL "compatibility options"
 This option allows an administrator to adjust the SSL options applied
 by OpenSSL to connections.  It is given as a space-separated list of items,
@@ -28319,7 +28319,7 @@ There is no current way to staple a proof for a client certificate.
 
 
 
 
 
 
-.section "Configuring an Exim client to use TLS" "SECID185"
+.section "Configuring an Exim client to use TLS" "SECTclientTLS"
 .cindex "cipher" "logging"
 .cindex "log" "TLS cipher"
 .cindex "log" "distinguished name"
 .cindex "cipher" "logging"
 .cindex "log" "TLS cipher"
 .cindex "log" "distinguished name"
index a85841af63f60f462d5a49611a0396814abd94a8..59a025b2a916437600bf0c45917b8a5c5e19d703 100644 (file)
@@ -89,6 +89,8 @@ JH/16 GnuTLS: rework ciphersuite strings under recent library versions.  Thanks
       This affects log line X= elements, the $tls_{in,out}_cipher variables,
       and the use of specific cipher names in the encrypted= ACL condition.
 
       This affects log line X= elements, the $tls_{in,out}_cipher variables,
       and the use of specific cipher names in the encrypted= ACL condition.
 
+JH/17 OpenSSL: the default openssl_options now disables ssl_v3.
+
 
 Exim version 4.92
 -----------------
 
 Exim version 4.92
 -----------------
index e776a4f953f1fbca9066baf6bfee6957957dc0a5..352833c4b68b4780724fbb4f5174932eae9a7425 100644 (file)
@@ -20,6 +20,9 @@ Version 4.93
 
  5. A case_insensitive option for verify=not_blind.
 
 
  5. A case_insensitive option for verify=not_blind.
 
+ 6. EXPERIMENTAL_TLS_RESUME optional build feature.  See the experimental.spec
+    file.
+
 
 Version 4.92
 --------------
 
 Version 4.92
 --------------
index 2f1e5c59194a897481784465d4ac9a0184350478..a2861c4a968b94f07d7e7f4ff1ad0b246b6279a1 100644 (file)
@@ -951,6 +951,50 @@ Transport configurations should be checked for this.  An example avoidance:
 
 
 
 
 
 
+TLS Session Resumption
+----------------------
+TLS Session Resumption for TLS 1.2 and TLS1.3 connections can be used (defined
+in RFC 5077 for 1.2).  The support for this can be included by building with
+EXPERIMENTAL_TLS_RESUME defined.
+
+Session resumption (this is the "stateless" variant) involves the server sending
+a "session ticket" to the client on one connection, which can be stored by the
+client and used for a later session.  The ticket contains sufficient state for
+the server to reconstruct the TLS session, avoiding some expensive crypto
+calculation and one full packet roundtrip time.
+
+Operational cost/benefit:
+ The extra data being transmitted costs a minor amount, and the client has
+extra costs in storing and retrieving the data.
+
+In the Exim/Gnutls implementation the extra cost on an initial connection
+which is TLS1.2 over a loopback path is about 6ms on 2017-laptop class hardware.
+The saved cost on a subsequent connection is about 4ms; three or more
+connections become a net win.  On longer network paths, two or more
+connections will have an average lower startup time thanks to the one
+saved packet roundtrip.  TLS1.3 will save the crypto cpu costs but not any
+packet roundtrips.
+
+Security aspects:
+ The session ticket is encrypted, but is obviously an additional security
+vulnarability surface.  An attacker able to decrypt it would have access
+all connections using the resumed session.
+The session ticket encryption key is not committed to storage by the server
+and is rotated regularly.  Tickets have limited lifetime.
+
+There is a question-mark over the security of the Diffie-Helman parameters
+used for session negotiation. TBD.  q-value; cf bug 1895
+
+Observability:
+ New log_selector "tls_resumption", appends an asterisk to the tls_cipher "X="
+element.
+
+Variables $tls_{in,out}_resumption have bit 0-4 indicating respectively
+support built, client requested ticket, client offered session,
+server issued ticket, resume used.  A suitable decode list is provided
+in the builtin macro _RESUME_DECODE for ${listextract {}{}}.
+
+
 --------------------------------------------------------------
 End of file
 --------------------------------------------------------------
 --------------------------------------------------------------
 End of file
 --------------------------------------------------------------
index 0fbee9d0379c3286abec23befd3e542ffc93d57b..8ca9a485c8e92d36280f79969c37edd6a75416c8 100644 (file)
@@ -123,7 +123,7 @@ config.h: Makefile buildconfig ../src/config.h.defaults $(EDITME)
 
 # Build the builtin-macros data struct
 
 
 # Build the builtin-macros data struct
 
-MACRO_HSRC = macro_predef.h os.h globals.h config.h \
+MACRO_HSRC = macro_predef.h os.h globals.h config.h macros.h \
        routers/accept.h routers/dnslookup.h routers/ipliteral.h \
        routers/iplookup.h routers/manualroute.h routers/queryprogram.h \
        routers/redirect.h
        routers/accept.h routers/dnslookup.h routers/ipliteral.h \
        routers/iplookup.h routers/manualroute.h routers/queryprogram.h \
        routers/redirect.h
@@ -158,7 +158,7 @@ macro-transport.o:  transport.c
 macro-drtables.o :     drtables.c
        @echo "$(CC) -DMACRO_PREDEF drtables.c"
        $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ drtables.c
 macro-drtables.o :     drtables.c
        @echo "$(CC) -DMACRO_PREDEF drtables.c"
        $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ drtables.c
-macro-tls.o:   tls.c
+macro-tls.o:   tls.c tls-gnu.c tls-openssl.c
        @echo "$(CC) -DMACRO_PREDEF tls.c"
        $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ tls.c
 macro-appendfile.o :   transports/appendfile.c
        @echo "$(CC) -DMACRO_PREDEF tls.c"
        $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ tls.c
 macro-appendfile.o :   transports/appendfile.c
index fdd32b8e715ed7f93665a085183b0bb22c30157a..19938affac44b7a948012950b2cdd4d31545b2bc 100644 (file)
@@ -2406,7 +2406,7 @@ if ((t = tree_search(*anchor, key)))
 /* We aren't using a pre-computed rate, so get a previously recorded rate
 from the database, which will be updated and written back if required. */
 
 /* We aren't using a pre-computed rate, so get a previously recorded rate
 from the database, which will be updated and written back if required. */
 
-if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE)))
+if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE, TRUE)))
   {
   store_pool = old_pool;
   sender_rate = NULL;
   {
   store_pool = old_pool;
   sender_rate = NULL;
index a27ad3fd24fe82b5ff79596b18c820543d5f2f23..c5d5389baf9fbabd15d2fab53efd260953727119 100644 (file)
@@ -203,6 +203,7 @@ Do not put spaces between # and the 'define'.
 #define EXPERIMENTAL_PIPE_CONNECT
 #define EXPERIMENTAL_QUEUEFILE
 #define EXPERIMENTAL_SRS
 #define EXPERIMENTAL_PIPE_CONNECT
 #define EXPERIMENTAL_QUEUEFILE
 #define EXPERIMENTAL_SRS
+#define EXPERIMENTAL_TLS_RESUME
 
 
 /* For developers */
 
 
 /* For developers */
index 4addf0ac7d1ced24eb40ce90666d35f0deab6f4e..cf5e09201fb8223e514b4d542d0fdc4fb4b879fe 100644 (file)
@@ -1985,6 +1985,11 @@ for (;;)
     handle_ending_processes();
     errno = select_errno;
 
     handle_ending_processes();
     errno = select_errno;
 
+#ifdef SUPPORT_TLS
+    /* Create or rotate any required keys */
+    tls_daemon_init();
+#endif
+
     /* Loop for all the sockets that are currently ready to go. If select
     actually failed, we have set the count to 1 and select_failed=TRUE, so as
     to use the common error code for select/accept below. */
     /* Loop for all the sockets that are currently ready to go. If select
     actually failed, we have set the count to 1 and select_failed=TRUE, so as
     to use the common error code for select/accept below. */
index 5555c710b86fbb5e1b0e2cfa23547f495df93f1f..a607756819313cd69c5f1db34cce06a056cc7a37 100644 (file)
@@ -72,6 +72,7 @@ Arguments:
   dbblock  Points to an open_db block to be filled in.
   lof      If TRUE, write to the log for actual open failures (locking failures
            are always logged).
   dbblock  Points to an open_db block to be filled in.
   lof      If TRUE, write to the log for actual open failures (locking failures
            are always logged).
+  panic           If TRUE, panic on failure to create the db directory
 
 Returns:   NULL if the open failed, or the locking failed. After locking
            failures, errno is zero.
 
 Returns:   NULL if the open failed, or the locking failed. After locking
            failures, errno is zero.
@@ -85,7 +86,7 @@ moment I haven't changed them.
 */
 
 open_db *
 */
 
 open_db *
-dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof)
+dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof, BOOL panic)
 {
 int rc, save_errno;
 BOOL read_only = flags == O_RDONLY;
 {
 int rc, save_errno;
 BOOL read_only = flags == O_RDONLY;
@@ -114,7 +115,7 @@ snprintf(CS filename, sizeof(filename), "%s/%s.lockfile", dirname, name);
 if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
   {
   created = TRUE;
 if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
   {
   created = TRUE;
-  (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, TRUE);
+  (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, panic);
   dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
   }
 
   dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
   }
 
@@ -536,7 +537,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
       }
 
     start = clock();
       }
 
     start = clock();
-    odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE);
+    odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE, TRUE);
     stop = clock();
 
     if (odb)
     stop = clock();
 
     if (odb)
index 93d12efc31529987e8121a21c878677735946b62..2e18e0effe2c4d122bbfe556b57b59f2232c6022 100644 (file)
@@ -10,7 +10,7 @@
 
 void     dbfn_close(open_db *);
 int      dbfn_delete(open_db *, const uschar *);
 
 void     dbfn_close(open_db *);
 int      dbfn_delete(open_db *, const uschar *);
-open_db *dbfn_open(uschar *, int, open_db *, BOOL);
+open_db *dbfn_open(uschar *, int, open_db *, BOOL, BOOL);
 void    *dbfn_read_with_length(open_db *, const uschar *, int *);
 uschar  *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
 int      dbfn_write(open_db *, const uschar *, void *, int);
 void    *dbfn_read_with_length(open_db *, const uschar *, int *);
 uschar  *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
 int      dbfn_write(open_db *, const uschar *, void *, int);
index 02cfa1446f8d2d00b8548d6315c8840c40cc92bb..6b1ae0ebb8484564a942cd3957321048691b13e3 100644 (file)
@@ -804,5 +804,11 @@ typedef struct {
 } dbdata_ehlo_resp;
 #endif
 
 } dbdata_ehlo_resp;
 #endif
 
+typedef struct {
+  time_t time_stamp;
+  /*************/
+  uschar session[1];
+} dbdata_tls_session;
+
 
 /* End of dbstuff.h */
 
 /* End of dbstuff.h */
index 696effdeedfea0a6c21d6ca756b25fe76f5858f4..f79522d8e8a948c82f81529b5111b6f949694b63 100644 (file)
@@ -803,12 +803,18 @@ return g;
 
 #ifdef SUPPORT_TLS
 static gstring *
 
 #ifdef SUPPORT_TLS
 static gstring *
-d_tlslog(gstring * s, address_item * addr)
+d_tlslog(gstring * g, address_item * addr)
 {
 if (LOGGING(tls_cipher) && addr->cipher)
 {
 if (LOGGING(tls_cipher) && addr->cipher)
-  s = string_append(s, 2, US" X=", addr->cipher);
+  {
+  g = string_append(g, 2, US" X=", addr->cipher);
+#ifdef EXPERIMENTAL_TLS_RESUME
+  if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume))
+    g = string_catn(g, US"*", 1);
+#endif
+  }
 if (LOGGING(tls_certificate_verified) && addr->cipher)
 if (LOGGING(tls_certificate_verified) && addr->cipher)
-  s = string_append(s, 2, US" CV=",
+  g = string_append(g, 2, US" CV=",
     testflag(addr, af_cert_verified)
     ?
 #ifdef SUPPORT_DANE
     testflag(addr, af_cert_verified)
     ?
 #ifdef SUPPORT_DANE
@@ -819,8 +825,8 @@ if (LOGGING(tls_certificate_verified) && addr->cipher)
       "yes"
     : "no");
 if (LOGGING(tls_peerdn) && addr->peerdn)
       "yes"
     : "no");
 if (LOGGING(tls_peerdn) && addr->peerdn)
-  s = string_append(s, 3, US" DN=\"", string_printing(addr->peerdn), US"\"");
-return s;
+  g = string_append(g, 3, US" DN=\"", string_printing(addr->peerdn), US"\"");
+return g;
 }
 #endif
 
 }
 #endif
 
@@ -2900,7 +2906,7 @@ while (addr_local)
   of these checks, rather than for all local deliveries, because some local
   deliveries (e.g. to pipes) can take a substantial time. */
 
   of these checks, rather than for all local deliveries, because some local
   deliveries (e.g. to pipes) can take a substantial time. */
 
-  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
     {
     DEBUG(D_deliver|D_retry|D_hints_lookup)
       debug_printf("no retry data available\n");
     {
     DEBUG(D_deliver|D_retry|D_hints_lookup)
       debug_printf("no retry data available\n");
@@ -4794,6 +4800,9 @@ all pipes, so I do not see a reason to use non-blocking IO here
 #ifdef SUPPORT_DANE
       if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
 #endif
 #ifdef SUPPORT_DANE
       if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
 #endif
+# ifdef EXPERIMENTAL_TLS_RESUME
+      if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume);
+# endif
 
       /* Use an X item only if there's something to send */
 #ifdef SUPPORT_TLS
 
       /* Use an X item only if there's something to send */
 #ifdef SUPPORT_TLS
@@ -6321,7 +6330,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
   /* Failure to open the retry database is treated the same as if it does
   not exist. In both cases, dbm_file is NULL. */
 
   /* Failure to open the retry database is treated the same as if it does
   not exist. In both cases, dbm_file is NULL. */
 
-  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
     DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
       debug_printf("no retry data available\n");
 
     DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
       debug_printf("no retry data available\n");
 
index 573fc00ca4833cca78c0d20d44d6f6a0a1d54b07..7feba55319efc2982796d07a72086dc24afff07c 100644 (file)
@@ -47,7 +47,7 @@ deliberate; the dbfn_open() function - which is an Exim function - always tries
 to create if it can't open a read/write file. It expects only O_RDWR or
 O_RDONLY as its argument. */
 
 to create if it can't open a read/write file. It expects only O_RDWR or
 O_RDONLY as its argument. */
 
-if (!(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE)))
+if (!(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
   return FALSE;
 
 /* See if there is a record for this host or queue run; if there is, we cannot
   return FALSE;
 
 /* See if there is a record for this host or queue run; if there is, we cannot
@@ -101,7 +101,7 @@ dbdata_serialize *serial_record;
 
 DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
 
 
 DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
 
-if (  !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE))
+if (  !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))
    || !(serial_record = dbfn_read(dbm_file, key))
    )
   return;
    || !(serial_record = dbfn_read(dbm_file, key))
    )
   return;
index df76de15e02020a5087c33069330e4576e07cd96..1952d91a46fb4a1965c67cc117d36a31c4c67564 100644 (file)
@@ -934,6 +934,9 @@ fprintf(fp, "Support for:");
 #ifdef EXPERIMENTAL_PIPE_CONNECT
   fprintf(fp, " Experimental_PIPE_CONNECT");
 #endif
 #ifdef EXPERIMENTAL_PIPE_CONNECT
   fprintf(fp, " Experimental_PIPE_CONNECT");
 #endif
+#ifdef EXPERIMENTAL_TLS_RESUME
+  fprintf(fp, " Experimental_TLS_resume");
+#endif
 fprintf(fp, "\n");
 
 fprintf(fp, "Lookups (built-in):");
 fprintf(fp, "\n");
 
 fprintf(fp, "Lookups (built-in):");
index a0514f009d922a7056168b64dc2668ea11e9cbf0..2c7aad63b40ac42260b3b099674f49ca526a3c7a 100644 (file)
@@ -20,6 +20,7 @@ argument is the name of the database file. The available names are:
   misc:       miscellaneous hints data
   wait-<t>:   message waiting information; <t> is a transport name
   callout:    callout verification cache
   misc:       miscellaneous hints data
   wait-<t>:   message waiting information; <t> is a transport name
   callout:    callout verification cache
+  tls:       TLS session resumption cache
 
 There are a number of common subroutines, followed by three main programs,
 whose inclusion is controlled by -D on the compilation command. */
 
 There are a number of common subroutines, followed by three main programs,
 whose inclusion is controlled by -D on the compilation command. */
@@ -35,6 +36,7 @@ whose inclusion is controlled by -D on the compilation command. */
 #define type_misc      3
 #define type_callout   4
 #define type_ratelimit 5
 #define type_misc      3
 #define type_callout   4
 #define type_ratelimit 5
+#define type_tls       6
 
 
 /* This is used by our cut-down dbfn_open(). */
 
 
 /* This is used by our cut-down dbfn_open(). */
@@ -91,7 +93,7 @@ static void
 usage(uschar *name, uschar *options)
 {
 printf("Usage: exim_%s%s  <spool-directory> <database-name>\n", name, options);
 usage(uschar *name, uschar *options)
 {
 printf("Usage: exim_%s%s  <spool-directory> <database-name>\n", name, options);
-printf("  <database-name> = retry | misc | wait-<transport-name> | callout | ratelimit\n");
+printf("  <database-name> = retry | misc | wait-<transport-name> | callout | ratelimit | tls\n");
 exit(1);
 }
 
 exit(1);
 }
 
@@ -114,6 +116,7 @@ if (argc == 3)
   if (Ustrncmp(argv[2], "wait-", 5) == 0) return type_wait;
   if (Ustrcmp(argv[2], "callout") == 0) return type_callout;
   if (Ustrcmp(argv[2], "ratelimit") == 0) return type_ratelimit;
   if (Ustrncmp(argv[2], "wait-", 5) == 0) return type_wait;
   if (Ustrcmp(argv[2], "callout") == 0) return type_callout;
   if (Ustrcmp(argv[2], "ratelimit") == 0) return type_ratelimit;
+  if (Ustrcmp(argv[2], "tls") == 0) return type_tls;
   }
 usage(name, options);
 return -1;              /* Never obeyed */
   }
 usage(name, options);
 return -1;              /* Never obeyed */
@@ -240,6 +243,7 @@ Arguments:
   flags    O_RDONLY or O_RDWR
   dbblock  Points to an open_db block to be filled in.
   lof      Unused.
   flags    O_RDONLY or O_RDWR
   dbblock  Points to an open_db block to be filled in.
   lof      Unused.
+  panic           Unused
 
 Returns:   NULL if the open failed, or the locking failed.
            On success, dbblock is returned. This contains the dbm pointer and
 
 Returns:   NULL if the open failed, or the locking failed.
            On success, dbblock is returned. This contains the dbm pointer and
@@ -247,7 +251,7 @@ Returns:   NULL if the open failed, or the locking failed.
 */
 
 open_db *
 */
 
 open_db *
-dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof)
+dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof, BOOL panic)
 {
 int rc;
 struct flock lock_data;
 {
 int rc;
 struct flock lock_data;
@@ -525,7 +529,7 @@ uschar keybuffer[1024];
 
 dbdata_type = check_args(argc, argv, US"dumpdb", US"");
 spool_directory = argv[1];
 
 dbdata_type = check_args(argc, argv, US"dumpdb", US"");
 spool_directory = argv[1];
-if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE)))
+if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE)))
   exit(1);
 
 /* Scan the file, formatting the information for each entry. Note
   exit(1);
 
 /* Scan the file, formatting the information for each entry. Note
@@ -541,6 +545,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor);
   dbdata_callout_cache *callout;
   dbdata_ratelimit *ratelimit;
   dbdata_ratelimit_unique *rate_unique;
   dbdata_callout_cache *callout;
   dbdata_ratelimit *ratelimit;
   dbdata_ratelimit_unique *rate_unique;
+  dbdata_tls_session *session;
   int count_bad = 0;
   int length;
   uschar *t;
   int count_bad = 0;
   int length;
   uschar *t;
@@ -673,6 +678,11 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor);
            keybuffer);
          }
        break;
            keybuffer);
          }
        break;
+
+      case type_tls:
+       session = (dbdata_tls_session *)value;
+       printf("  %s %.*s\n", keybuffer, length, session->session);
+       break;
       }
     store_reset(value);
     }
       }
     store_reset(value);
     }
@@ -745,6 +755,7 @@ for(;;)
   dbdata_callout_cache *callout;
   dbdata_ratelimit *ratelimit;
   dbdata_ratelimit_unique *rate_unique;
   dbdata_callout_cache *callout;
   dbdata_ratelimit *ratelimit;
   dbdata_ratelimit_unique *rate_unique;
+  dbdata_tls_session *session;
   int oldlength;
   uschar *t;
   uschar field[256], value[256];
   int oldlength;
   uschar *t;
   uschar field[256], value[256];
@@ -783,7 +794,7 @@ for(;;)
     int verify = 1;
     spool_directory = argv[1];
 
     int verify = 1;
     spool_directory = argv[1];
 
-    if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE)))
+    if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE, TRUE)))
       continue;
 
     if (Ustrcmp(field, "d") == 0)
       continue;
 
     if (Ustrcmp(field, "d") == 0)
@@ -925,6 +936,10 @@ for(;;)
                         break;
                }
              break;
                         break;
                }
              break;
+
+            case type_tls:
+             printf("Can't change contents of tls database record\n");
+             break;
             }
 
           dbfn_write(dbm, name, record, oldlength);
             }
 
           dbfn_write(dbm, name, record, oldlength);
@@ -949,7 +964,7 @@ for(;;)
   /* Handle a read request, or verify after an update. */
 
   spool_directory = argv[1];
   /* Handle a read request, or verify after an update. */
 
   spool_directory = argv[1];
-  if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE)))
+  if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE)))
     continue;
 
   if (!(record = dbfn_read_with_length(dbm, name, &oldlength)))
     continue;
 
   if (!(record = dbfn_read_with_length(dbm, name, &oldlength)))
@@ -1036,6 +1051,12 @@ for(;;)
         printf("5 add element to filter\n");
         }
        break;
         printf("5 add element to filter\n");
         }
        break;
+
+      case type_tls:
+       session = (dbdata_tls_session *)value;
+       printf("0 time stamp:  %s\n", print_time(session->time_stamp));
+       printf("1 session: .%s\n", session->session);
+       break;
       }
     }
 
       }
     }
 
@@ -1134,7 +1155,7 @@ oldest = time(NULL) - maxkeep;
 printf("Tidying Exim hints database %s/db/%s\n", argv[1], argv[2]);
 
 spool_directory = argv[1];
 printf("Tidying Exim hints database %s/db/%s\n", argv[1], argv[2]);
 
 spool_directory = argv[1];
-if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE)))
+if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE, TRUE)))
   exit(1);
 
 /* Prepare for building file names */
   exit(1);
 
 /* Prepare for building file names */
index ff1b72615150da75033ab136f2812d6377644436..d8ea87dee165e5401f849950780d093acbe599bd 100644 (file)
@@ -751,6 +751,9 @@ static var_entry var_table[] = {
   { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
   { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
   { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
   { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
   { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
   { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
+#ifdef EXPERIMENTAL_TLS_RESUME
+  { "tls_in_resumption",   vtype_int,         &tls_in.resumption },
+#endif
 #if defined(SUPPORT_TLS)
   { "tls_in_sni",          vtype_stringptr,   &tls_in.sni },
 #endif
 #if defined(SUPPORT_TLS)
   { "tls_in_sni",          vtype_stringptr,   &tls_in.sni },
 #endif
@@ -765,6 +768,9 @@ static var_entry var_table[] = {
   { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
   { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
   { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
   { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
   { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
   { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
+#ifdef EXPERIMENTAL_TLS_RESUME
+  { "tls_out_resumption",  vtype_int,         &tls_out.resumption },
+#endif
 #if defined(SUPPORT_TLS)
   { "tls_out_sni",         vtype_stringptr,   &tls_out.sni },
 #endif
 #if defined(SUPPORT_TLS)
   { "tls_out_sni",         vtype_stringptr,   &tls_out.sni },
 #endif
@@ -5039,7 +5045,7 @@ while (*s != 0)
             port = ntohs(service_info->s_port);
             }
 
             port = ntohs(service_info->s_port);
             }
 
-         /*XXX we trust that the request is idempotent.  Hmm. */
+         /*XXX we trust that the request is idempotent for TFO.  Hmm. */
          cctx.sock = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
                  timeout, &host, &expand_string_message,
                  do_tls ? NULL : &reqstr);
          cctx.sock = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
                  timeout, &host, &expand_string_message,
                  do_tls ? NULL : &reqstr);
index 2eb74579fd88eb70bd62b1d238cfc6792118bb75..87953c413bee518a0f7fd5f117b04bc8c528a4a6 100644 (file)
@@ -51,6 +51,7 @@ extern BOOL    tls_client_start(client_conn_ctx *, smtp_connect_args *,
 
 extern void    tls_close(void *, int);
 extern BOOL    tls_could_read(void);
 
 extern void    tls_close(void *, int);
 extern BOOL    tls_could_read(void);
+extern void    tls_daemon_init(void);
 extern int     tls_export_cert(uschar *, size_t, void *);
 extern int     tls_feof(void);
 extern int     tls_ferror(void);
 extern int     tls_export_cert(uschar *, size_t, void *);
 extern int     tls_feof(void);
 extern int     tls_ferror(void);
index acabeb8c3d6867ad1266c90ce91c0827ce8c44d2..a2fa032bc55904c4f4d6df62f2754c2518629911 100644 (file)
@@ -102,38 +102,12 @@ them. Also, the tls_ variables are now always visible.  Note that these are
 only used for smtp connections, not for service-daemon access. */
 
 tls_support tls_in = {
 only used for smtp connections, not for service-daemon access. */
 
 tls_support tls_in = {
- .active =             {.sock = -1},
- .bits =               0,
- .certificate_verified = FALSE,
-#ifdef SUPPORT_DANE
- .dane_verified =      FALSE,
- .tlsa_usage =         0,
-#endif
- .cipher =             NULL,
- .on_connect =         FALSE,
- .on_connect_ports =   NULL,
- .ourcert =            NULL,
- .peercert =           NULL,
- .peerdn =             NULL,
- .sni =                        NULL,
- .ocsp =               OCSP_NOT_REQ
+ .active =             {.sock = -1}
+ /* all other elements zero */
 };
 tls_support tls_out = {
  .active =             {.sock = -1},
 };
 tls_support tls_out = {
  .active =             {.sock = -1},
- .bits =               0,
- .certificate_verified = FALSE,
-#ifdef SUPPORT_DANE
- .dane_verified =      FALSE,
- .tlsa_usage =         0,
-#endif
- .cipher =             NULL,
- .on_connect =         FALSE,
- .on_connect_ports =   NULL,
- .ourcert =            NULL,
- .peercert =           NULL,
- .peerdn =             NULL,
- .sni =                        NULL,
- .ocsp =               OCSP_NOT_REQ
+ /* all other elements zero */
 };
 
 uschar *dsn_envid              = NULL;
 };
 
 uschar *dsn_envid              = NULL;
@@ -161,6 +135,9 @@ uschar *tls_ocsp_file          = NULL;
 uschar *tls_privatekey         = NULL;
 BOOL    tls_remember_esmtp     = FALSE;
 uschar *tls_require_ciphers    = NULL;
 uschar *tls_privatekey         = NULL;
 BOOL    tls_remember_esmtp     = FALSE;
 uschar *tls_require_ciphers    = NULL;
+# ifdef EXPERIMENTAL_TLS_RESUME
+uschar *tls_resumption_hosts   = NULL;
+# endif
 uschar *tls_try_verify_hosts   = NULL;
 uschar *tls_verify_certificates= US"system";
 uschar *tls_verify_hosts       = NULL;
 uschar *tls_try_verify_hosts   = NULL;
 uschar *tls_verify_certificates= US"system";
 uschar *tls_verify_hosts       = NULL;
@@ -1047,7 +1024,8 @@ uschar *log_file_path          = US LOG_FILE_PATH
 int     log_notall[]           = {
   -1
 };
 int     log_notall[]           = {
   -1
 };
-bit_table log_options[]        = { /* must be in alphabetical order */
+bit_table log_options[]        = { /* must be in alphabetical order,
+                               with definitions from enum logbit. */
   BIT_TABLE(L, 8bitmime),
   BIT_TABLE(L, acl_warn_skipped),
   BIT_TABLE(L, address_rewrite),
   BIT_TABLE(L, 8bitmime),
   BIT_TABLE(L, acl_warn_skipped),
   BIT_TABLE(L, address_rewrite),
@@ -1105,6 +1083,7 @@ bit_table log_options[]        = { /* must be in alphabetical order */
   BIT_TABLE(L, tls_certificate_verified),
   BIT_TABLE(L, tls_cipher),
   BIT_TABLE(L, tls_peerdn),
   BIT_TABLE(L, tls_certificate_verified),
   BIT_TABLE(L, tls_cipher),
   BIT_TABLE(L, tls_peerdn),
+  BIT_TABLE(L, tls_resumption),
   BIT_TABLE(L, tls_sni),
   BIT_TABLE(L, unknown_in_list),
 };
   BIT_TABLE(L, tls_sni),
   BIT_TABLE(L, unknown_in_list),
 };
index a0c1977a2bdec9500fab9433b60b45e7943e9326..1aacaf7e64aed97ca9f4f37b1db999bcfaf8c5e0 100644 (file)
@@ -103,6 +103,11 @@ typedef struct {
     OCSP_FAILED,               /* verify failed */
     OCSP_VFIED                 /* verified */
     }     ocsp;                      /* Stapled OCSP status */
     OCSP_FAILED,               /* verify failed */
     OCSP_VFIED                 /* verified */
     }     ocsp;                      /* Stapled OCSP status */
+#ifdef EXPERIMENTAL_TLS_RESUME
+  unsigned resumption;         /* Session resumption */
+  BOOL   host_resumable:1;
+  BOOL   ticket_received:1;
+#endif
 } tls_support;
 extern tls_support tls_in;
 extern tls_support tls_out;
 } tls_support;
 extern tls_support tls_in;
 extern tls_support tls_out;
@@ -124,6 +129,9 @@ extern uschar *tls_ocsp_file;          /* OCSP stapling proof file */
 extern uschar *tls_privatekey;         /* Private key file */
 extern BOOL    tls_remember_esmtp;     /* For YAEB */
 extern uschar *tls_require_ciphers;    /* So some can be avoided */
 extern uschar *tls_privatekey;         /* Private key file */
 extern BOOL    tls_remember_esmtp;     /* For YAEB */
 extern uschar *tls_require_ciphers;    /* So some can be avoided */
+# ifdef EXPERIMENTAL_TLS_RESUME
+extern uschar *tls_resumption_hosts;   /* TLS session resumption */
+# endif
 extern uschar *tls_try_verify_hosts;   /* Optional client verification */
 extern uschar *tls_verify_certificates;/* Path for certificates to check */
 extern uschar *tls_verify_hosts;       /* Mandatory client verification */
 extern uschar *tls_try_verify_hosts;   /* Optional client verification */
 extern uschar *tls_verify_certificates;/* Path for certificates to check */
 extern uschar *tls_verify_hosts;       /* Mandatory client verification */
index 86be52f542c0f2ee1fda557c6cacf2ace36d26f0..33249133ace87ef2270ca79a37b865ef1a1b6e23 100644 (file)
@@ -200,6 +200,9 @@ due to conflicts with other common macros. */
 #ifdef EXPERIMENTAL_PIPE_CONNECT
   builtin_macro_create(US"_HAVE_PIPE_CONNECT");
 #endif
 #ifdef EXPERIMENTAL_PIPE_CONNECT
   builtin_macro_create(US"_HAVE_PIPE_CONNECT");
 #endif
+#ifdef EXPERIMENTAL_TLS_RESUME
+  builtin_macro_create(US"_HAVE_TLS_RESUME");
+#endif
 
 #ifdef LOOKUP_LSEARCH
   builtin_macro_create(US"_HAVE_LOOKUP_LSEARCH");
 
 #ifdef LOOKUP_LSEARCH
   builtin_macro_create(US"_HAVE_LOOKUP_LSEARCH");
@@ -287,7 +290,7 @@ options_routers();
 options_transports();
 options_auths();
 options_logging();
 options_transports();
 options_auths();
 options_logging();
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
 options_tls();
 #endif
 }
 options_tls();
 #endif
 }
index f265750ca9b0c7af74aa16511f1a38f9f71c4d19..79a8d6f15bf13421cc33804bb153baef5980556f 100644 (file)
@@ -20,7 +20,7 @@ extern void options_transports(void);
 extern void options_auths(void);
 extern void options_logging(void);
 extern void params_dkim(void);
 extern void options_auths(void);
 extern void options_logging(void);
 extern void params_dkim(void);
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
 extern void options_tls(void);
 #endif
 
 extern void options_tls(void);
 #endif
 
index f98d5e6bdf8b7e14854ab813b7f6809c0b988de4..e3f1f4c281b77e086ab18fd4db79e1b8adc308e8 100644 (file)
@@ -435,11 +435,12 @@ enum {
 /* Options bits for logging. Those that have values < BITWORDSIZE can be used
 in calls to log_write(). The others are put into later words in log_selector
 and are only ever tested independently, so they do not need bit mask
 /* Options bits for logging. Those that have values < BITWORDSIZE can be used
 in calls to log_write(). The others are put into later words in log_selector
 and are only ever tested independently, so they do not need bit mask
-declarations. The Li_all value is recognized specially by decode_bits(). */
+declarations. The Li_all value is recognized specially by decode_bits().
+Add also to log_options[] when creating new ones. */
 
 #define LOG_BIT(name) Li_##name = IOTA(Li_iota), L_##name = BIT(Li_##name)
 
 
 #define LOG_BIT(name) Li_##name = IOTA(Li_iota), L_##name = BIT(Li_##name)
 
-enum {
+enum logbit {
   Li_all = -1,
 
   Li_iota = IOTA_INIT(0),
   Li_all = -1,
 
   Li_iota = IOTA_INIT(0),
@@ -495,6 +496,7 @@ enum {
   Li_tls_certificate_verified,
   Li_tls_cipher,
   Li_tls_peerdn,
   Li_tls_certificate_verified,
   Li_tls_cipher,
   Li_tls_peerdn,
+  Li_tls_resumption,
   Li_tls_sni,
   Li_unknown_in_list,
 
   Li_tls_sni,
   Li_unknown_in_list,
 
@@ -1077,5 +1079,21 @@ should not be one active. */
 #define AUTH_ITEM_IGN64        BIT(2)
 
 
 #define AUTH_ITEM_IGN64        BIT(2)
 
 
+/* Flags for tls_{in,out}_resumption */
+#define RESUME_SUPPORTED       BIT(0)
+#define RESUME_CLIENT_REQUESTED        BIT(1)
+#define RESUME_CLIENT_SUGGESTED        BIT(2)
+#define RESUME_SERVER_TICKET   BIT(3)
+#define RESUME_USED            BIT(4)
+
+#define RESUME_DECODE_STRING \
+         US"not requested or offered : 0x02 :client requested, no server ticket" \
+    ": 0x04 : 0x05 : 0x06 :client offered session, no server action" \
+    ": 0x08 :no client request: 0x0A :client requested new ticket, server provided" \
+    ": 0x0C :client offered session, not used: 0x0E :client offered session, server only provided new ticket" \
+    ": 0x10 :session resumed unasked: 0x12 :session resumed unasked" \
+    ": 0x14 : 0x15 : 0x16 :session resumed" \
+    ": 0x18 :session resumed unasked: 0x1A :session resumed unasked" \
+    ": 0x1C :session resumed: 0x1E :session resumed, also new ticket"
 
 /* End of macros.h */
 
 /* End of macros.h */
index 150d7973d3ffd706374093e6d86041e8af1f6fb1..cac8fe5c2e81a475663d2a30d50b2e412927716d 100644 (file)
@@ -367,6 +367,9 @@ static optionlist optionlist_config[] = {
   { "tls_privatekey",           opt_stringptr,   &tls_privatekey },
   { "tls_remember_esmtp",       opt_bool,        &tls_remember_esmtp },
   { "tls_require_ciphers",      opt_stringptr,   &tls_require_ciphers },
   { "tls_privatekey",           opt_stringptr,   &tls_privatekey },
   { "tls_remember_esmtp",       opt_bool,        &tls_remember_esmtp },
   { "tls_require_ciphers",      opt_stringptr,   &tls_require_ciphers },
+# ifdef EXPERIMENTAL_TLS_RESUME
+  { "tls_resumption_hosts",     opt_stringptr,   &tls_resumption_hosts },
+# endif
   { "tls_try_verify_hosts",     opt_stringptr,   &tls_try_verify_hosts },
   { "tls_verify_certificates",  opt_stringptr,   &tls_verify_certificates },
   { "tls_verify_hosts",         opt_stringptr,   &tls_verify_hosts },
   { "tls_try_verify_hosts",     opt_stringptr,   &tls_try_verify_hosts },
   { "tls_verify_certificates",  opt_stringptr,   &tls_verify_certificates },
   { "tls_verify_hosts",         opt_stringptr,   &tls_verify_hosts },
index 701d540b09121d66e542550bde6bd68cb315c06f..fbd32c8fa4e049b000135dc386079e74b84c4d58 100644 (file)
@@ -3980,7 +3980,13 @@ g = add_host_info_for_log(g);
 
 #ifdef SUPPORT_TLS
 if (LOGGING(tls_cipher) && tls_in.cipher)
 
 #ifdef SUPPORT_TLS
 if (LOGGING(tls_cipher) && tls_in.cipher)
+  {
   g = string_append(g, 2, US" X=", tls_in.cipher);
   g = string_append(g, 2, US" X=", tls_in.cipher);
+# ifdef EXPERIMENTAL_TLS_RESUME
+  if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
+    g = string_catn(g, US"*", 1);
+# endif
+  }
 if (LOGGING(tls_certificate_verified) && tls_in.cipher)
   g = string_append(g, 2, US" CV=", tls_in.certificate_verified ? "yes":"no");
 if (LOGGING(tls_peerdn) && tls_in.peerdn)
 if (LOGGING(tls_certificate_verified) && tls_in.cipher)
   g = string_append(g, 2, US" CV=", tls_in.certificate_verified ? "yes":"no");
 if (LOGGING(tls_peerdn) && tls_in.peerdn)
index dc39813fba731687cfc301e7b62ae8fbf577d213..509de123c6a799bd31990a2ea6561b53acc244a5 100644 (file)
@@ -170,7 +170,7 @@ if ((node = tree_search(tree_unusable, host_key)))
 /* Open the retry database, giving up if there isn't one. Otherwise, search for
 the retry records, and then close the database again. */
 
 /* Open the retry database, giving up if there isn't one. Otherwise, search for
 the retry records, and then close the database again. */
 
-if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
   {
   DEBUG(D_deliver|D_retry|D_hints_lookup)
     debug_printf("no retry data available\n");
   {
   DEBUG(D_deliver|D_retry|D_hints_lookup)
     debug_printf("no retry data available\n");
@@ -580,7 +580,7 @@ for (int i = 0; i < 3; i++)
         reached their retry next try time. */
 
         if (!dbm_file)
         reached their retry next try time. */
 
         if (!dbm_file)
-          dbm_file = dbfn_open(US"retry", O_RDWR, &dbblock, TRUE);
+          dbm_file = dbfn_open(US"retry", O_RDWR, &dbblock, TRUE, TRUE);
 
         if (!dbm_file)
           {
 
         if (!dbm_file)
           {
index b46f3e876a9141844ba40e17db60a611f135fe1d..40fd3083b550cc137e519df140078eb322bace00 100644 (file)
@@ -1786,7 +1786,13 @@ static gstring *
 s_tlslog(gstring * g)
 {
 if (LOGGING(tls_cipher) && tls_in.cipher)
 s_tlslog(gstring * g)
 {
 if (LOGGING(tls_cipher) && tls_in.cipher)
+  {
   g = string_append(g, 2, US" X=", tls_in.cipher);
   g = string_append(g, 2, US" X=", tls_in.cipher);
+#ifdef EXPERIMENTAL_TLS_RESUME
+  if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
+    g = string_catn(g, US"*", 1);
+#endif
+  }
 if (LOGGING(tls_certificate_verified) && tls_in.cipher)
   g = string_append(g, 2, US" CV=", tls_in.certificate_verified? "yes":"no");
 if (LOGGING(tls_peerdn) && tls_in.peerdn)
 if (LOGGING(tls_certificate_verified) && tls_in.cipher)
   g = string_append(g, 2, US" CV=", tls_in.certificate_verified? "yes":"no");
 if (LOGGING(tls_peerdn) && tls_in.peerdn)
index 786eb514e9dc245b3a427a6fb1ef30eaeef75285..95004c1030961b3ca9ffb30bf25485ac8a8af1a4 100644 (file)
@@ -667,6 +667,11 @@ for (;;)
        tls_in.sni = string_unprinting(string_copy(big_buffer + 9));
       else if (Ustrncmp(q, "ocsp", 4) == 0)
        tls_in.ocsp = big_buffer[10] - '0';
        tls_in.sni = string_unprinting(string_copy(big_buffer + 9));
       else if (Ustrncmp(q, "ocsp", 4) == 0)
        tls_in.ocsp = big_buffer[10] - '0';
+# ifdef EXPERIMENTAL_TLS_RESUME
+      else if (Ustrncmp(q, "resumption", 10) == 0)
+       tls_in.resumption = big_buffer[16] - 'A';
+# endif
+
       }
     break;
 #endif
       }
     break;
 #endif
index 46a490a9324266ead100f2adf3e1d05643192eda..d14914f94c2a39f093e79a4db5d284c5c593c00f 100644 (file)
@@ -249,6 +249,9 @@ if (tls_in.ourcert)
   fprintf(fp, "-tls_ourcert %s\n", CS big_buffer);
   }
 if (tls_in.ocsp)        fprintf(fp, "-tls_ocsp %d\n",   tls_in.ocsp);
   fprintf(fp, "-tls_ourcert %s\n", CS big_buffer);
   }
 if (tls_in.ocsp)        fprintf(fp, "-tls_ocsp %d\n",   tls_in.ocsp);
+# ifdef EXPERIMENTAL_TLS_RESUME
+fprintf(fp, "-tls_resumption %c\n", 'A' + tls_in.resumption);
+# endif
 #endif
 
 #ifdef SUPPORT_I18N
 #endif
 
 #ifdef SUPPORT_I18N
index 7fb32777c0d0d27da96a13eb50e317da6cbb008a..349aa38e85062bf3de63abffa14da9d0cfd2d32c 100644 (file)
@@ -636,6 +636,9 @@ typedef struct address_item {
 #endif
 #ifdef SUPPORT_I18N
     BOOL af_utf8_downcvt:1;            /* downconvert was done for delivery */
 #endif
 #ifdef SUPPORT_I18N
     BOOL af_utf8_downcvt:1;            /* downconvert was done for delivery */
+#endif
+#ifdef EXPERIMENTAL_TLS_RESUME
+    BOOL af_tls_resume:1;              /* TLS used a resumed session */
 #endif
   } flags;
 
 #endif
   } flags;
 
index 91ddc579b8eabd64c324a45346c1694359e1bd68..32625d6d8d98dca868b63aee6a7d5569a2b4d233 100644 (file)
@@ -99,6 +99,17 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
 #include "tls-cipher-stdname.c"
 
 
 #include "tls-cipher-stdname.c"
 
 
+#ifdef MACRO_PREDEF
+void
+options_tls(void)
+{
+# ifdef EXPERIMENTAL_TLS_RESUME
+builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
+# endif
+}
+#else
+
+
 /* GnuTLS 2 vs 3
 
 GnuTLS 3 only:
 /* GnuTLS 2 vs 3
 
 GnuTLS 3 only:
@@ -174,45 +185,9 @@ typedef struct exim_gnutls_state {
 } exim_gnutls_state_st;
 
 static const exim_gnutls_state_st exim_gnutls_state_init = {
 } exim_gnutls_state_st;
 
 static const exim_gnutls_state_st exim_gnutls_state_init = {
-  .session =           NULL,
-  .x509_cred =         NULL,
-  .priority_cache =    NULL,
-  .verify_requirement =        VERIFY_NONE,
+  /* all elements not explicitly intialised here get 0/NULL/FALSE */
   .fd_in =             -1,
   .fd_out =            -1,
   .fd_in =             -1,
   .fd_out =            -1,
-  .peer_cert_verified =        FALSE,
-  .peer_dane_verified =        FALSE,
-  .trigger_sni_changes =FALSE,
-  .have_set_peerdn =   FALSE,
-  .host =              NULL,
-  .peercert =          NULL,
-  .peerdn =            NULL,
-  .ciphersuite =       NULL,
-  .received_sni =      NULL,
-
-  .tls_certificate =   NULL,
-  .tls_privatekey =    NULL,
-  .tls_sni =           NULL,
-  .tls_verify_certificates = NULL,
-  .tls_crl =           NULL,
-  .tls_require_ciphers =NULL,
-
-  .exp_tls_certificate = NULL,
-  .exp_tls_privatekey =        NULL,
-  .exp_tls_verify_certificates = NULL,
-  .exp_tls_crl =       NULL,
-  .exp_tls_require_ciphers = NULL,
-  .exp_tls_verify_cert_hostnames = NULL,
-#ifndef DISABLE_EVENT
-  .event_action =      NULL,
-#endif
-  .tlsp =              NULL,
-
-  .xfer_buffer =       NULL,
-  .xfer_buffer_lwm =   0,
-  .xfer_buffer_hwm =   0,
-  .xfer_eof =          FALSE,
-  .xfer_error =                FALSE,
 };
 
 /* Not only do we have our own APIs which don't pass around state, assuming
 };
 
 /* Not only do we have our own APIs which don't pass around state, assuming
@@ -234,9 +209,7 @@ don't want to repeat this. */
 
 static gnutls_dh_params_t dh_server_params = NULL;
 
 
 static gnutls_dh_params_t dh_server_params = NULL;
 
-/* No idea how this value was chosen; preserving it.  Default is 3600. */
-
-static const int ssl_session_timeout = 200;
+static int ssl_session_timeout = 3600; /* One hour */
 
 static const uschar * const exim_default_gnutls_priority = US"NORMAL";
 
 
 static const uschar * const exim_default_gnutls_priority = US"NORMAL";
 
@@ -248,6 +221,9 @@ static BOOL exim_gnutls_base_init_done = FALSE;
 static BOOL gnutls_buggy_ocsp = FALSE;
 #endif
 
 static BOOL gnutls_buggy_ocsp = FALSE;
 #endif
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+static gnutls_datum_t server_sessticket_key;
+#endif
 
 /* ------------------------------------------------------------------------ */
 /* macros */
 
 /* ------------------------------------------------------------------------ */
 /* macros */
@@ -261,7 +237,7 @@ setuid binaries, making it useless - "GNUTLS_DEBUG_LEVEL".
 Allegedly the testscript line "GNUTLS_DEBUG_LEVEL=9 sudo exim ..." would work,
 but the env var must be added to /etc/sudoers too. */
 #ifndef EXIM_GNUTLS_LIBRARY_LOG_LEVEL
 Allegedly the testscript line "GNUTLS_DEBUG_LEVEL=9 sudo exim ..." would work,
 but the env var must be added to /etc/sudoers too. */
 #ifndef EXIM_GNUTLS_LIBRARY_LOG_LEVEL
-# define EXIM_GNUTLS_LIBRARY_LOG_LEVEL -1
+# define EXIM_GNUTLS_LIBRARY_LOG_LEVEL 9
 #endif
 
 #ifndef EXIM_CLIENT_DH_MIN_BITS
 #endif
 
 #ifndef EXIM_CLIENT_DH_MIN_BITS
@@ -312,6 +288,24 @@ static int server_ocsp_stapling_cb(gnutls_session_t session, void * ptr,
 
 
 
 
 
 
+/* Daemon one-time initialisation */
+void
+tls_daemon_init(void)
+{
+#ifdef EXPERIMENTAL_TLS_RESUME
+/* We are dependent on the GnuTLS implementation of the Session Ticket
+encryption; both the strength and the key rotation period.  We hope that
+the strength at least matches that of the ciphersuite (but GnuTLS does not
+document this). */
+
+static BOOL once = FALSE;
+if (once) return;
+once = TRUE;
+gnutls_session_ticket_key_generate(&server_sessticket_key);    /* >= 2.10.0 */
+if (f.running_in_test_harness) ssl_session_timeout = 6;
+#endif
+}
+
 /* ------------------------------------------------------------------------ */
 /* Static functions */
 
 /* ------------------------------------------------------------------------ */
 /* Static functions */
 
@@ -463,7 +457,6 @@ Argument:
 static void
 extract_exim_vars_from_tls_state(exim_gnutls_state_st * state)
 {
 static void
 extract_exim_vars_from_tls_state(exim_gnutls_state_st * state)
 {
-gnutls_cipher_algorithm_t cipher;
 #ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
 int old_pool;
 int rc;
 #ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
 int old_pool;
 int rc;
@@ -474,12 +467,6 @@ tls_support * tlsp = state->tlsp;
 tlsp->active.sock = state->fd_out;
 tlsp->active.tls_ctx = state;
 
 tlsp->active.sock = state->fd_out;
 tlsp->active.tls_ctx = state;
 
-cipher = gnutls_cipher_get(state->session);
-/* returns size in "bytes" */
-tlsp->bits = gnutls_cipher_get_key_size(cipher) * 8;
-
-tlsp->cipher = state->ciphersuite;
-
 DEBUG(D_tls) debug_printf("cipher: %s\n", state->ciphersuite);
 
 tlsp->certificate_verified = state->peer_cert_verified;
 DEBUG(D_tls) debug_printf("cipher: %s\n", state->ciphersuite);
 
 tlsp->certificate_verified = state->peer_cert_verified;
@@ -1423,6 +1410,9 @@ if ((rc = gnutls_priority_init(&state->priority_cache, CCS p, &errpos)))
 if ((rc = gnutls_priority_set(state->session, state->priority_cache)))
   return tls_error_gnu(US"gnutls_priority_set", rc, host, errstr);
 
 if ((rc = gnutls_priority_set(state->session, state->priority_cache)))
   return tls_error_gnu(US"gnutls_priority_set", rc, host, errstr);
 
+/* This also sets the server ticket expiration time to the same, and
+the STEK rotation time to 3x. */
+
 gnutls_db_set_cache_expiration(state->session, ssl_session_timeout);
 
 /* Reduce security in favour of increased compatibility, if the admin
 gnutls_db_set_cache_expiration(state->session, ssl_session_timeout);
 
 /* Reduce security in favour of increased compatibility, if the admin
@@ -1492,9 +1482,10 @@ Returns:          OK/DEFER/FAIL
 */
 
 static int
 */
 
 static int
-peer_status(exim_gnutls_state_st *state, uschar ** errstr)
+peer_status(exim_gnutls_state_st * state, uschar ** errstr)
 {
 {
-const gnutls_datum_t *cert_list;
+gnutls_session_t session = state->session;
+const gnutls_datum_t * cert_list;
 int old_pool, rc;
 unsigned int cert_list_size = 0;
 gnutls_protocol_t protocol;
 int old_pool, rc;
 unsigned int cert_list_size = 0;
 gnutls_protocol_t protocol;
@@ -1503,7 +1494,7 @@ gnutls_kx_algorithm_t kx;
 gnutls_mac_algorithm_t mac;
 gnutls_certificate_type_t ct;
 gnutls_x509_crt_t crt;
 gnutls_mac_algorithm_t mac;
 gnutls_certificate_type_t ct;
 gnutls_x509_crt_t crt;
-uschar *dn_buf;
+uschar * dn_buf;
 size_t sz;
 
 if (state->have_set_peerdn)
 size_t sz;
 
 if (state->have_set_peerdn)
@@ -1513,23 +1504,24 @@ state->have_set_peerdn = TRUE;
 state->peerdn = NULL;
 
 /* tls_cipher */
 state->peerdn = NULL;
 
 /* tls_cipher */
-cipher = gnutls_cipher_get(state->session);
-protocol = gnutls_protocol_get_version(state->session);
-mac = gnutls_mac_get(state->session);
+cipher = gnutls_cipher_get(session);
+protocol = gnutls_protocol_get_version(session);
+mac = gnutls_mac_get(session);
 kx =
 #ifdef GNUTLS_TLS1_3
     protocol >= GNUTLS_TLS1_3 ? 0 :
 #endif
 kx =
 #ifdef GNUTLS_TLS1_3
     protocol >= GNUTLS_TLS1_3 ? 0 :
 #endif
-  gnutls_kx_get(state->session);
+  gnutls_kx_get(session);
 
 old_pool = store_pool;
   {
 
 old_pool = store_pool;
   {
+  tls_support * tlsp = state->tlsp;
   store_pool = POOL_PERM;
 
 #ifdef SUPPORT_GNUTLS_SESS_DESC
     {
     gstring * g = NULL;
   store_pool = POOL_PERM;
 
 #ifdef SUPPORT_GNUTLS_SESS_DESC
     {
     gstring * g = NULL;
-    uschar * s = US gnutls_session_get_desc(state->session), c;
+    uschar * s = US gnutls_session_get_desc(session), c;
 
     /* Nikos M suggests we use this by preference.  It returns like:
     (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
 
     /* Nikos M suggests we use this by preference.  It returns like:
     (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
@@ -1568,15 +1560,15 @@ old_pool = store_pool;
 
 /* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */
 
 
 /* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */
 
-  state->tlsp->cipher = state->ciphersuite;
-  state->tlsp->bits = gnutls_cipher_get_key_size(cipher) * 8;
+  tlsp->cipher = state->ciphersuite;
+  tlsp->bits = gnutls_cipher_get_key_size(cipher) * 8;
 
 
-  state->tlsp->cipher_stdname = cipher_stdname_kcm(kx, cipher, mac);
+  tlsp->cipher_stdname = cipher_stdname_kcm(kx, cipher, mac);
   }
 store_pool = old_pool;
 
 /* tls_peerdn */
   }
 store_pool = old_pool;
 
 /* tls_peerdn */
-cert_list = gnutls_certificate_get_peers(state->session, &cert_list_size);
+cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
 
 if (!cert_list || cert_list_size == 0)
   {
 
 if (!cert_list || cert_list_size == 0)
   {
@@ -1588,7 +1580,7 @@ if (!cert_list || cert_list_size == 0)
   return OK;
   }
 
   return OK;
   }
 
-if ((ct = gnutls_certificate_type_get(state->session)) != GNUTLS_CRT_X509)
+if ((ct = gnutls_certificate_type_get(session)) != GNUTLS_CRT_X509)
   {
   const uschar * ctn = US gnutls_certificate_type_get_name(ct);
   DEBUG(D_tls)
   {
   const uschar * ctn = US gnutls_certificate_type_get_name(ct);
   DEBUG(D_tls)
@@ -1660,13 +1652,14 @@ verify_certificate(exim_gnutls_state_st * state, uschar ** errstr)
 int rc;
 uint verify;
 
 int rc;
 uint verify;
 
-if (state->verify_requirement == VERIFY_NONE)
-  return TRUE;
-
 DEBUG(D_tls) debug_printf("TLS: checking peer certificate\n");
 *errstr = NULL;
 DEBUG(D_tls) debug_printf("TLS: checking peer certificate\n");
 *errstr = NULL;
+rc = peer_status(state, errstr);
 
 
-if ((rc = peer_status(state, errstr)) != OK || !state->peerdn)
+if (state->verify_requirement == VERIFY_NONE)
+  return TRUE;
+
+if (rc != OK || !state->peerdn)
   {
   verify = GNUTLS_CERT_INVALID;
   *errstr = US"certificate not supplied";
   {
   verify = GNUTLS_CERT_INVALID;
   *errstr = US"certificate not supplied";
@@ -2065,7 +2058,6 @@ return g;
 static void
 post_handshake_debug(exim_gnutls_state_st * state)
 {
 static void
 post_handshake_debug(exim_gnutls_state_st * state)
 {
-debug_printf("gnutls_handshake was successful\n");
 #ifdef SUPPORT_GNUTLS_SESS_DESC
 debug_printf("%s\n", gnutls_session_get_desc(state->session));
 #endif
 #ifdef SUPPORT_GNUTLS_SESS_DESC
 debug_printf("%s\n", gnutls_session_get_desc(state->session));
 #endif
@@ -2094,6 +2086,63 @@ else
 #endif
 }
 
 #endif
 }
 
+
+#ifdef EXPERIMENTAL_TLS_RESUME
+static int
+tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
+  unsigned incoming, const gnutls_datum_t * msg)
+{
+DEBUG(D_tls) debug_printf("newticket cb\n");
+tls_in.resumption |= RESUME_CLIENT_REQUESTED;
+return 0;
+}
+
+static void
+tls_server_resume_prehandshake(exim_gnutls_state_st * state)
+{
+/* Should the server offer session resumption? */
+tls_in.resumption = RESUME_SUPPORTED;
+if (verify_check_host(&tls_resumption_hosts) == OK)
+  {
+  int rc;
+  /* GnuTLS appears to not do ticket overlap, but does emit a fresh ticket when
+  an offered resumption is unacceptable.  We lose one resumption per ticket
+  lifetime, and sessions cannot be indefinitely re-used.  There seems to be no
+  way (3.6.7) of changing the default number of 2 TLS1.3 tickets issued, but at
+  least they go out in a single packet. */
+
+  if (!(rc = gnutls_session_ticket_enable_server(state->session,
+             &server_sessticket_key)))
+    tls_in.resumption |= RESUME_SERVER_TICKET;
+  else
+    DEBUG(D_tls)
+      debug_printf("enabling session tickets: %s\n", US gnutls_strerror(rc));
+
+  /* Try to tell if we see a ticket request */
+  gnutls_handshake_set_hook_function(state->session,
+    GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, GNUTLS_HOOK_POST, tls_server_ticket_cb);
+  }
+}
+
+static void
+tls_server_resume_posthandshake(exim_gnutls_state_st * state)
+{
+if (gnutls_session_resumption_requested(state->session))
+  {
+  /* This tells us the client sent a full ticket.  We use a
+  callback on session-ticket request, elsewhere, to tell
+  if a client asked for a ticket. */
+
+  tls_in.resumption |= RESUME_CLIENT_SUGGESTED;
+  DEBUG(D_tls) debug_printf("client requested resumption\n");
+  }
+if (gnutls_session_is_resumed(state->session))
+  {
+  tls_in.resumption |= RESUME_USED;
+  DEBUG(D_tls) debug_printf("Session resumed\n");
+  }
+}
+#endif
 /* ------------------------------------------------------------------------ */
 /* Exported functions */
 
 /* ------------------------------------------------------------------------ */
 /* Exported functions */
 
@@ -2141,6 +2190,10 @@ if ((rc = tls_init(NULL, tls_certificate, tls_privatekey,
     NULL, tls_verify_certificates, tls_crl,
     require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
 
     NULL, tls_verify_certificates, tls_crl,
     require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_server_resume_prehandshake(state);
+#endif
+
 /* If this is a host for which certificate verification is mandatory or
 optional, set up appropriately. */
 
 /* If this is a host for which certificate verification is mandatory or
 optional, set up appropriately. */
 
@@ -2240,6 +2293,10 @@ if (rc != GNUTLS_E_SUCCESS)
   return FAIL;
   }
 
   return FAIL;
   }
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_server_resume_posthandshake(state);
+#endif
+
 DEBUG(D_tls) post_handshake_debug(state);
 
 /* Verify after the fact */
 DEBUG(D_tls) post_handshake_debug(state);
 
 /* Verify after the fact */
@@ -2256,10 +2313,6 @@ if (!verify_certificate(state, errstr))
        *errstr);
   }
 
        *errstr);
   }
 
-/* Figure out peer DN, and if authenticated, etc. */
-
-if ((rc = peer_status(state, NULL)) != OK) return rc;
-
 /* Sets various Exim expansion variables; always safe within server */
 
 extract_exim_vars_from_tls_state(state);
 /* Sets various Exim expansion variables; always safe within server */
 
 extract_exim_vars_from_tls_state(state);
@@ -2372,6 +2425,140 @@ return TRUE;
 
 
 
 
 
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+/* On the client, get any stashed session for the given IP from hints db
+and apply it to the ssl-connection for attempted resumption.  Although
+there is a gnutls_session_ticket_enable_client() interface it is
+documented as unnecessary (as of 3.6.7) as "session tickets are emabled
+by deafult".  There seems to be no way to disable them, so even hosts not
+enabled by the transport option will be sent a ticket request.  We will
+however avoid storing and retrieving session information. */
+
+static void
+tls_retrieve_session(tls_support * tlsp, gnutls_session_t session,
+  host_item * host, smtp_transport_options_block * ob)
+{
+tlsp->resumption = RESUME_SUPPORTED;
+if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
+  {
+  dbdata_tls_session * dt;
+  int len, rc;
+  open_db dbblock, * dbm_file;
+
+  DEBUG(D_tls)
+    debug_printf("check for resumable session for %s\n", host->address);
+  tlsp->host_resumable = TRUE;
+  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
+  if ((dbm_file = dbfn_open(US"tls", O_RDONLY, &dbblock, FALSE, FALSE)))
+    {
+    /* key for the db is the IP */
+    if ((dt = dbfn_read_with_length(dbm_file, host->address, &len)))
+      if (!(rc = gnutls_session_set_data(session,
+                   CUS dt->session, (size_t)len - sizeof(dbdata_tls_session))))
+       {
+       DEBUG(D_tls) debug_printf("good session\n");
+       tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
+       }
+      else DEBUG(D_tls) debug_printf("setting session resumption data: %s\n",
+           US gnutls_strerror(rc));
+    dbfn_close(dbm_file);
+    }
+  }
+}
+
+
+static void
+tls_save_session(tls_support * tlsp, gnutls_session_t session, const host_item * host)
+{
+/* TLS 1.2 - we get both the callback and the direct posthandshake call,
+but this flag is not set until the second.  TLS 1.3 it's the other way about.
+Keep both calls as the session data cannot be extracted before handshake
+completes. */
+
+if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET)
+  {
+  gnutls_datum_t tkt;
+  int rc;
+
+  DEBUG(D_tls) debug_printf("server offered session ticket\n");
+  tlsp->ticket_received = TRUE;
+  tlsp->resumption |= RESUME_SERVER_TICKET;
+
+  if (tlsp->host_resumable)
+    if (!(rc = gnutls_session_get_data2(session, &tkt)))
+      {
+      open_db dbblock, * dbm_file;
+      int dlen = sizeof(dbdata_tls_session) + tkt.size;
+      dbdata_tls_session * dt = store_get(dlen);
+
+      DEBUG(D_tls) debug_printf("session data size %u\n", (unsigned)tkt.size);
+      memcpy(dt->session, tkt.data, tkt.size);
+      gnutls_free(tkt.data);
+
+      if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
+       {
+       /* key for the db is the IP */
+       dbfn_delete(dbm_file, host->address);
+       dbfn_write(dbm_file, host->address, dt, dlen);
+       dbfn_close(dbm_file);
+
+       DEBUG(D_tls)
+         debug_printf("wrote session db (len %u)\n", (unsigned)dlen);
+       }
+      }
+    else DEBUG(D_tls)
+      debug_printf("extract session data: %s\n", US gnutls_strerror(rc));
+  }
+}
+
+
+/* With a TLS1.3 session, the ticket(s) are not seen until
+the first data read is attempted.  And there's often two of them.
+Pick them up with this callback.  We are also called for 1.2
+but we do nothing.
+*/
+static int
+tls_client_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
+  unsigned incoming, const gnutls_datum_t * msg)
+{
+exim_gnutls_state_st * state = gnutls_session_get_ptr(sess);
+tls_support * tlsp = state->tlsp;
+
+DEBUG(D_tls) debug_printf("newticket cb\n");
+
+if (!tlsp->ticket_received)
+  tls_save_session(tlsp, sess, state->host);
+return 0;
+}
+
+
+static void
+tls_client_resume_prehandshake(exim_gnutls_state_st * state,
+  tls_support * tlsp, host_item * host,
+  smtp_transport_options_block * ob)
+{
+gnutls_session_set_ptr(state->session, state);
+gnutls_handshake_set_hook_function(state->session,
+  GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, GNUTLS_HOOK_POST, tls_client_ticket_cb);
+
+tls_retrieve_session(tlsp, state->session, host, ob);
+}
+
+static void
+tls_client_resume_posthandshake(exim_gnutls_state_st * state,
+  tls_support * tlsp, host_item * host)
+{
+if (gnutls_session_is_resumed(state->session))
+  {
+  DEBUG(D_tls) debug_printf("Session resumed\n");
+  tlsp->resumption |= RESUME_USED;
+  }
+
+tls_save_session(tlsp, state->session, host);
+}
+#endif /* EXPERIMENTAL_TLS_RESUME */
+
+
 /*************************************************
 *    Start a TLS session in a client             *
 *************************************************/
 /*************************************************
 *    Start a TLS session in a client             *
 *************************************************/
@@ -2512,6 +2699,10 @@ if (request_ocsp)
   }
 #endif
 
   }
 #endif
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_client_resume_prehandshake(state, tlsp, host, ob);
+#endif
+
 #ifndef DISABLE_EVENT
 if (tb && tb->event_action)
   {
 #ifndef DISABLE_EVENT
 if (tb && tb->event_action)
   {
@@ -2589,10 +2780,9 @@ if (require_ocsp)
   }
 #endif
 
   }
 #endif
 
-/* Figure out peer DN, and if authenticated, etc. */
-
-if (peer_status(state, errstr) != OK)
-  return FALSE;
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_client_resume_posthandshake(state, tlsp, host);
+#endif
 
 /* Sets various Exim expansion variables; may need to adjust for ACL callouts */
 
 
 /* Sets various Exim expansion variables; may need to adjust for ACL callouts */
 
@@ -3090,6 +3280,7 @@ fprintf(f, "Library version: GnuTLS: Compile: %s\n"
            gnutls_check_version(NULL));
 }
 
            gnutls_check_version(NULL));
 }
 
+#endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
 /* End of tls-gnu.c */
 /* vi: aw ai sw=2
 */
 /* End of tls-gnu.c */
index c7b22a0db3e490a92ded847f197e470c428518b3..06008deccceb03aa48583b7227fba4c89582ed05 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) University of Cambridge 1995 - 2019 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Portions Copyright (c) The OpenSSL Project 1999 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Portions Copyright (c) The OpenSSL Project 1999 */
@@ -72,6 +72,7 @@ change this guard and punt the issue for a while longer. */
 #  define EXIM_HAVE_OPENSSL_TLS_METHOD
 #  define EXIM_HAVE_OPENSSL_KEYLOG
 #  define EXIM_HAVE_OPENSSL_CIPHER_GET_ID
 #  define EXIM_HAVE_OPENSSL_TLS_METHOD
 #  define EXIM_HAVE_OPENSSL_KEYLOG
 #  define EXIM_HAVE_OPENSSL_CIPHER_GET_ID
+#  define EXIM_HAVE_SESSION_TICKET
 # else
 #  define EXIM_NEED_OPENSSL_INIT
 # endif
 # else
 #  define EXIM_NEED_OPENSSL_INIT
 # endif
@@ -249,6 +250,10 @@ for (struct exim_openssl_option * o = exim_openssl_options;
   spf(buf, sizeof(buf), US"_OPT_OPENSSL_%T_X", o->name);
   builtin_macro_create(buf);
   }
   spf(buf, sizeof(buf), US"_OPT_OPENSSL_%T_X", o->name);
   builtin_macro_create(buf);
   }
+
+# ifdef EXPERIMENTAL_TLS_RESUME
+builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
+# endif
 }
 #else
 
 }
 #else
 
@@ -303,7 +308,7 @@ static SSL_CTX *server_sni = NULL;
 
 static char ssl_errstring[256];
 
 
 static char ssl_errstring[256];
 
-static int  ssl_session_timeout = 200;
+static int  ssl_session_timeout = 3600;
 static BOOL client_verify_optional = FALSE;
 static BOOL server_verify_optional = FALSE;
 
 static BOOL client_verify_optional = FALSE;
 static BOOL server_verify_optional = FALSE;
 
@@ -311,6 +316,7 @@ static BOOL reexpand_tls_files_for_sni = FALSE;
 
 
 typedef struct tls_ext_ctx_cb {
 
 
 typedef struct tls_ext_ctx_cb {
+  tls_support * tlsp;
   uschar *certificate;
   uschar *privatekey;
   BOOL is_server;
   uschar *certificate;
   uschar *privatekey;
   BOOL is_server;
@@ -342,7 +348,7 @@ typedef struct tls_ext_ctx_cb {
 /* should figure out a cleanup of API to handle state preserved per
 implementation, for various reasons, which can be void * in the APIs.
 For now, we hack around it. */
 /* should figure out a cleanup of API to handle state preserved per
 implementation, for various reasons, which can be void * in the APIs.
 For now, we hack around it. */
-tls_ext_ctx_cb *client_static_cbinfo = NULL;
+tls_ext_ctx_cb *client_static_cbinfo = NULL;   /*XXX should not use static; multiple concurrent clients! */
 tls_ext_ctx_cb *server_static_cbinfo = NULL;
 
 static int
 tls_ext_ctx_cb *server_static_cbinfo = NULL;
 
 static int
@@ -358,6 +364,23 @@ static int tls_server_stapling_cb(SSL *s, void *arg);
 #endif
 
 
 #endif
 
 
+
+/* Daemon-called key create/rotate */
+#ifdef EXPERIMENTAL_TLS_RESUME
+static void tk_init(void);
+static int tls_exdata_idx = -1;
+#endif
+
+void
+tls_daemon_init(void)
+{
+#ifdef EXPERIMENTAL_TLS_RESUME
+tk_init();
+#endif
+return;
+}
+
+
 /*************************************************
 *               Handle TLS error                 *
 *************************************************/
 /*************************************************
 *               Handle TLS error                 *
 *************************************************/
@@ -803,6 +826,121 @@ DEBUG(D_tls) debug_printf("%.200s\n", line);
 #endif
 
 
 #endif
 
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+/* Manage the keysets used for encrypting the session tickets, on the server. */
+
+typedef struct {                       /* Session ticket encryption key */
+  uschar       name[16];
+
+  const EVP_CIPHER *   aes_cipher;
+  uschar               aes_key[16];    /* size needed depends on cipher. aes_128 implies 128/8 = 16? */
+  const EVP_MD *       hmac_hash;
+  uschar               hmac_key[16];
+  time_t               renew;
+  time_t               expire;
+} exim_stek;
+
+/*XXX for now just always create/find the one key.
+Worry about rotation and overlap later. */
+
+static exim_stek exim_tk;
+static exim_stek exim_tk_old;
+
+static void
+tk_init(void)
+{
+if (exim_tk.name[0])
+  {
+  if (exim_tk.renew >= time(NULL)) return;
+  exim_tk_old = exim_tk;
+  }
+
+if (f.running_in_test_harness) ssl_session_timeout = 6;
+
+DEBUG(D_tls) debug_printf("OpenSSL: %s STEK\n", exim_tk.name[0] ? "rotating" : "creating");
+if (RAND_bytes(exim_tk.aes_key, sizeof(exim_tk.aes_key)) <= 0) return;
+if (RAND_bytes(exim_tk.hmac_key, sizeof(exim_tk.hmac_key)) <= 0) return;
+if (RAND_bytes(exim_tk.name+1, sizeof(exim_tk.name)-1) <= 0) return;
+
+exim_tk.name[0] = 'E';
+exim_tk.aes_cipher = EVP_aes_128_cbc();
+exim_tk.hmac_hash = EVP_sha256();
+exim_tk.expire = time(NULL) + ssl_session_timeout;
+exim_tk.renew = exim_tk.expire - ssl_session_timeout/2;
+}
+
+static exim_stek *
+tk_current(void)
+{
+if (!exim_tk.name[0]) return NULL;
+return &exim_tk;
+}
+
+static exim_stek *
+tk_find(const uschar * name)
+{
+return memcmp(name, exim_tk.name, sizeof(exim_tk.name)) == 0 ? &exim_tk
+  : memcmp(name, exim_tk_old.name, sizeof(exim_tk_old.name)) == 0 ? &exim_tk_old
+  : NULL;
+}
+
+/* Callback for session tickets, on server */
+static int
+ticket_key_callback(SSL * ssl, uschar key_name[16],
+  uschar * iv, EVP_CIPHER_CTX * ctx, HMAC_CTX * hctx, int enc)
+{
+tls_support * tlsp = server_static_cbinfo->tlsp;
+exim_stek * key;
+
+if (enc)
+  {
+  DEBUG(D_tls) debug_printf("ticket_key_callback: create new session\n");
+  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
+
+  if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0)
+    return -1; /* insufficient random */
+
+  if (!(key = tk_current()))   /* current key doesn't exist or isn't valid */
+     return 0;                 /* key couldn't be created */
+  memcpy(key_name, key->name, 16);
+  DEBUG(D_tls) debug_printf("STEK expire %ld\n", key->expire - time(NULL));
+
+  /*XXX will want these dependent on the ssl session strength */
+  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
+               key->hmac_hash, NULL);
+  EVP_EncryptInit_ex(ctx, key->aes_cipher, NULL, key->aes_key, iv);
+
+  DEBUG(D_tls) debug_printf("ticket created\n");
+  return 1;
+  }
+else
+  {
+  time_t now = time(NULL);
+
+  DEBUG(D_tls) debug_printf("ticket_key_callback: retrieve session\n");
+  tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
+
+  if (!(key = tk_find(key_name)) || key->expire < now)
+    {
+    DEBUG(D_tls)
+      {
+      debug_printf("ticket not usable (%s)\n", key ? "expired" : "not found");
+      if (key) debug_printf("STEK expire %ld\n", key->expire - now);
+      }
+    return 0;
+    }
+
+  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
+               key->hmac_hash, NULL);
+  EVP_DecryptInit_ex(ctx, key->aes_cipher, NULL, key->aes_key, iv);
+
+  DEBUG(D_tls) debug_printf("ticket usable, STEK expire %ld\n", key->expire - now);
+  return key->renew < now ? 2 : 1;
+  }
+}
+#endif
+
+
 
 /*************************************************
 *                Initialize for DH               *
 
 /*************************************************
 *                Initialize for DH               *
@@ -1394,6 +1532,9 @@ Arguments:
   arg             Callback of "our" registered data
 
 Returns:          SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK}
   arg             Callback of "our" registered data
 
 Returns:          SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK}
+
+XXX might need to change to using ClientHello callback,
+per https://www.openssl.org/docs/manmaster/man3/SSL_client_hello_cb_fn.html
 */
 
 #ifdef EXIM_HAVE_OPENSSL_TLSEXT
 */
 
 #ifdef EXIM_HAVE_OPENSSL_TLSEXT
@@ -1714,7 +1855,9 @@ tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
 #ifndef DISABLE_OCSP
   uschar *ocsp_file,   /*XXX stack, in server*/
 #endif
 #ifndef DISABLE_OCSP
   uschar *ocsp_file,   /*XXX stack, in server*/
 #endif
-  address_item *addr, tls_ext_ctx_cb ** cbp, uschar ** errstr)
+  address_item *addr, tls_ext_ctx_cb ** cbp,
+  tls_support * tlsp,
+  uschar ** errstr)
 {
 SSL_CTX * ctx;
 long init_options;
 {
 SSL_CTX * ctx;
 long init_options;
@@ -1722,6 +1865,7 @@ int rc;
 tls_ext_ctx_cb * cbinfo;
 
 cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
 tls_ext_ctx_cb * cbinfo;
 
 cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
+cbinfo->tlsp = tlsp;
 cbinfo->certificate = certificate;
 cbinfo->privatekey = privatekey;
 cbinfo->is_server = host==NULL;
 cbinfo->certificate = certificate;
 cbinfo->privatekey = privatekey;
 cbinfo->is_server = host==NULL;
@@ -1795,10 +1939,16 @@ if (!RAND_status())
 /* Set up the information callback, which outputs if debugging is at a suitable
 level. */
 
 /* Set up the information callback, which outputs if debugging is at a suitable
 level. */
 
-DEBUG(D_tls) SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
+DEBUG(D_tls)
+  {
+  SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
+#ifndef OPENSSL_NO_SSL_TRACE   /* this needs a debug build of OpenSSL */
+  SSL_CTX_set_msg_callback(ctx, (void (*)())SSL_trace);
+#endif
 #ifdef OPENSSL_HAVE_KEYLOG_CB
 #ifdef OPENSSL_HAVE_KEYLOG_CB
-DEBUG(D_tls) SSL_CTX_set_keylog_callback(ctx, (void (*)())keylog_callback);
+  SSL_CTX_set_keylog_callback(ctx, (void (*)())keylog_callback);
 #endif
 #endif
+  }
 
 /* Automatically re-try reads/writes after renegotiation. */
 (void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
 
 /* Automatically re-try reads/writes after renegotiation. */
 (void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
@@ -1815,8 +1965,22 @@ availability of the option value macros from OpenSSL.  */
 if (!tls_openssl_options_parse(openssl_options, &init_options))
   return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
 
 if (!tls_openssl_options_parse(openssl_options, &init_options))
   return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+tlsp->resumption = RESUME_SUPPORTED;
+#endif
 if (init_options)
   {
 if (init_options)
   {
+#ifdef EXPERIMENTAL_TLS_RESUME
+  /* Should the server offer session resumption? */
+  if (!host && verify_check_host(&tls_resumption_hosts) == OK)
+    {
+    DEBUG(D_tls) debug_printf("tls_resumption_hosts overrides openssl_options\n");
+    init_options &= ~SSL_OP_NO_TICKET;
+    tlsp->resumption |= RESUME_SERVER_TICKET; /* server will give ticket on request */
+    tlsp->host_resumable = TRUE;
+    }
+#endif
+
   DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
   if (!(SSL_CTX_set_options(ctx, init_options)))
     return tls_error(string_sprintf(
   DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
   if (!(SSL_CTX_set_options(ctx, init_options)))
     return tls_error(string_sprintf(
@@ -1825,10 +1989,6 @@ if (init_options)
 else
   DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
 
 else
   DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
 
-#ifdef OPENSSL_HAVE_NUM_TICKETS
-SSL_CTX_set_num_tickets(ctx, 0);       /* send no TLS1.3 stateful-tickets */
-#endif
-
 /* We'd like to disable session cache unconditionally, but foolish Outlook
 Express clients then give up the first TLS connection and make a second one
 (which works).  Only when there is an IMAP service on the same machine.
 /* We'd like to disable session cache unconditionally, but foolish Outlook
 Express clients then give up the first TLS connection and make a second one
 (which works).  Only when there is an IMAP service on the same machine.
@@ -1903,7 +2063,8 @@ cbinfo->verify_cert_hostnames = NULL;
 SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
 #endif
 
 SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
 #endif
 
-/* Finally, set the timeout, and we are done */
+/* Finally, set the session cache timeout, and we are done.
+The period appears to be also used for (server-generated) session tickets */
 
 SSL_CTX_set_timeout(ctx, ssl_session_timeout);
 DEBUG(D_tls) debug_printf("Initialized TLS\n");
 
 SSL_CTX_set_timeout(ctx, ssl_session_timeout);
 DEBUG(D_tls) debug_printf("Initialized TLS\n");
@@ -2226,7 +2387,7 @@ rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey,
 #ifndef DISABLE_OCSP
     tls_ocsp_file,     /*XXX stack*/
 #endif
 #ifndef DISABLE_OCSP
     tls_ocsp_file,     /*XXX stack*/
 #endif
-    NULL, &server_static_cbinfo, errstr);
+    NULL, &server_static_cbinfo, &tls_in, errstr);
 if (rc != OK) return rc;
 cbinfo = server_static_cbinfo;
 
 if (rc != OK) return rc;
 cbinfo = server_static_cbinfo;
 
@@ -2244,8 +2405,7 @@ TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
 
 if (expciphers)
   {
 
 if (expciphers)
   {
-  uschar * s = expciphers;
-  while (*s != 0) { if (*s == '_') *s = '-'; s++; }
+  for (uschar * s = expciphers; *s; s++ ) if (*s == '_') *s = '-';
   DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
   if (!SSL_CTX_set_cipher_list(server_ctx, CS expciphers))
     return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
   DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
   if (!SSL_CTX_set_cipher_list(server_ctx, CS expciphers))
     return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
@@ -2276,6 +2436,19 @@ else if (verify_check_host(&tls_try_verify_hosts) == OK)
   server_verify_optional = TRUE;
   }
 
   server_verify_optional = TRUE;
   }
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_key_callback);
+/* despite working, appears to always return failure, so ignoring */
+#endif
+#ifdef OPENSSL_HAVE_NUM_TICKETS
+# ifdef EXPERIMENTAL_TLS_RESUME
+SSL_CTX_set_num_tickets(server_ctx, tls_in.host_resumable ? 1 : 0);
+# else
+SSL_CTX_set_num_tickets(server_ctx, 0);        /* send no TLS1.3 stateful-tickets */
+# endif
+#endif
+
+
 /* Prepare for new connection */
 
 if (!(server_ssl = SSL_new(server_ctx)))
 /* Prepare for new connection */
 
 if (!(server_ssl = SSL_new(server_ctx)))
@@ -2329,7 +2502,15 @@ if (rc <= 0)
 
 DEBUG(D_tls) debug_printf("SSL_accept was successful\n");
 ERR_clear_error();     /* Even success can leave errors in the stack. Seen with
 
 DEBUG(D_tls) debug_printf("SSL_accept was successful\n");
 ERR_clear_error();     /* Even success can leave errors in the stack. Seen with
-                       anon-authentication ciphersuite negociated. */
+                       anon-authentication ciphersuite negotiated. */
+
+#ifdef EXPERIMENTAL_TLS_RESUME
+if (SSL_session_reused(server_ssl))
+  {
+  tls_in.resumption |= RESUME_USED;
+  DEBUG(D_tls) debug_printf("Session reused\n");
+  }
+#endif
 
 /* TLS has been set up. Adjust the input functions to read via TLS,
 and initialize things. */
 
 /* TLS has been set up. Adjust the input functions to read via TLS,
 and initialize things. */
@@ -2352,6 +2533,15 @@ DEBUG(D_tls)
   BIO_free(bp);
   }
 #endif
   BIO_free(bp);
   }
 #endif
+
+#ifdef EXIM_HAVE_SESSION_TICKET
+  {
+  SSL_SESSION * ss = SSL_get_session(server_ssl);
+  if (SSL_SESSION_has_ticket(ss))
+    debug_printf("The session has a ticket, life %lu seconds\n",
+      SSL_SESSION_get_ticket_lifetime_hint(ss));
+  }
+#endif
   }
 
 /* Record the certificate we presented */
   }
 
 /* Record the certificate we presented */
@@ -2483,6 +2673,160 @@ return DEFER;
 
 
 
 
 
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+/* On the client, get any stashed session for the given IP from hints db
+and apply it to the ssl-connection for attempted resumption. */
+
+static void
+tls_retrieve_session(tls_support * tlsp, SSL * ssl, const uschar * key)
+{
+tlsp->resumption |= RESUME_SUPPORTED;
+if (tlsp->host_resumable)
+  {
+  dbdata_tls_session * dt;
+  int len;
+  open_db dbblock, * dbm_file;
+
+  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
+  DEBUG(D_tls) debug_printf("checking for resumable session for %s\n", key);
+  if ((dbm_file = dbfn_open(US"tls", O_RDONLY, &dbblock, FALSE, FALSE)))
+    {
+    /* key for the db is the IP */
+    if ((dt = dbfn_read_with_length(dbm_file, key, &len)))
+      {
+      SSL_SESSION * ss = NULL;
+      const uschar * sess_asn1 = dt->session;
+
+      len -= sizeof(dbdata_tls_session);
+      if (!(d2i_SSL_SESSION(&ss, &sess_asn1, (long)len)))
+       {
+       DEBUG(D_tls)
+         {
+         ERR_error_string_n(ERR_get_error(),
+           ssl_errstring, sizeof(ssl_errstring));
+         debug_printf("decoding session: %s\n", ssl_errstring);
+         }
+       }
+      else if (!SSL_set_session(ssl, ss))
+       {
+       DEBUG(D_tls)
+         {
+         ERR_error_string_n(ERR_get_error(),
+           ssl_errstring, sizeof(ssl_errstring));
+         debug_printf("applying session to ssl: %s\n", ssl_errstring);
+         }
+       }
+      else
+       {
+       DEBUG(D_tls) debug_printf("good session\n");
+       tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
+       }
+      }
+    else
+      DEBUG(D_tls) debug_printf("no session record\n");
+    dbfn_close(dbm_file);
+    }
+  }
+}
+
+
+/* On the client, save the session for later resumption */
+
+static int
+tls_save_session_cb(SSL * ssl, SSL_SESSION * ss)
+{
+tls_ext_ctx_cb * cbinfo = SSL_get_ex_data(ssl, tls_exdata_idx);
+tls_support * tlsp;
+
+DEBUG(D_tls) debug_printf("tls_save_session_cb\n");
+
+if (!cbinfo || !(tlsp = cbinfo->tlsp)->host_resumable) return 0;
+
+# ifdef EXIM_HAVE_SESSION_TICKET
+
+if (SSL_SESSION_is_resumable(ss)) 
+  {
+  int len = i2d_SSL_SESSION(ss, NULL);
+  int dlen = sizeof(dbdata_tls_session) + len;
+  dbdata_tls_session * dt = store_get(dlen);
+  uschar * s = dt->session;
+  open_db dbblock, * dbm_file;
+
+  DEBUG(D_tls) debug_printf("session is resumable\n");
+  tlsp->resumption |= RESUME_SERVER_TICKET;    /* server gave us a ticket */
+
+  len = i2d_SSL_SESSION(ss, &s);       /* s gets bumped to end */
+
+  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
+    {
+    const uschar * key = cbinfo->host->address;
+    dbfn_delete(dbm_file, key);
+    dbfn_write(dbm_file, key, dt, dlen);
+    dbfn_close(dbm_file);
+    DEBUG(D_tls) debug_printf("wrote session (len %u) to db\n",
+                 (unsigned)dlen);
+    }
+  }
+# endif
+return 1;
+}
+
+
+static void
+tls_client_ctx_resume_prehandshake(
+  exim_openssl_client_tls_ctx * exim_client_ctx, tls_support * tlsp,
+  smtp_transport_options_block * ob, host_item * host)
+{
+/* Should the client request a session resumption ticket? */
+if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
+  {
+  tlsp->host_resumable = TRUE;
+
+  SSL_CTX_set_session_cache_mode(exim_client_ctx->ctx,
+       SSL_SESS_CACHE_CLIENT
+       | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
+  SSL_CTX_sess_set_new_cb(exim_client_ctx->ctx, tls_save_session_cb);
+  }
+}
+
+static BOOL
+tls_client_ssl_resume_prehandshake(SSL * ssl, tls_support * tlsp,
+  host_item * host, uschar ** errstr)
+{
+if (tlsp->host_resumable)
+  {
+  DEBUG(D_tls)
+    debug_printf("tls_resumption_hosts overrides openssl_options, enabling tickets\n");
+  SSL_clear_options(ssl, SSL_OP_NO_TICKET);
+
+  tls_exdata_idx = SSL_get_ex_new_index(0, 0, 0, 0, 0);
+  if (!SSL_set_ex_data(ssl, tls_exdata_idx, client_static_cbinfo))
+    {
+    tls_error(US"set ex_data", host, NULL, errstr);
+    return FALSE;
+    }
+  debug_printf("tls_exdata_idx %d cbinfo %p\n", tls_exdata_idx, client_static_cbinfo);
+  }
+
+tlsp->resumption = RESUME_SUPPORTED;
+/* Pick up a previous session, saved on an old ticket */
+tls_retrieve_session(tlsp, ssl, host->address);
+return TRUE;
+}
+
+static void
+tls_client_resume_posthandshake(exim_openssl_client_tls_ctx * exim_client_ctx,
+  tls_support * tlsp)
+{
+if (SSL_session_reused(exim_client_ctx->ssl))
+  {
+  DEBUG(D_tls) debug_printf("The session was reused\n");
+  tlsp->resumption |= RESUME_USED;
+  }
+}
+#endif /* EXPERIMENTAL_TLS_RESUME */
+
+
 /*************************************************
 *    Start a TLS session in a client             *
 *************************************************/
 /*************************************************
 *    Start a TLS session in a client             *
 *************************************************/
@@ -2562,7 +2906,7 @@ rc = tls_init(&exim_client_ctx->ctx, host, NULL,
 #ifndef DISABLE_OCSP
     (void *)(long)request_ocsp,
 #endif
 #ifndef DISABLE_OCSP
     (void *)(long)request_ocsp,
 #endif
-    cookie, &client_static_cbinfo, errstr);
+    cookie, &client_static_cbinfo, tlsp, errstr);
 if (rc != OK) return FALSE;
 
 tlsp->certificate_verified = FALSE;
 if (rc != OK) return FALSE;
 
 tlsp->certificate_verified = FALSE;
@@ -2629,12 +2973,24 @@ else
        client_static_cbinfo, errstr) != OK)
     return FALSE;
 
        client_static_cbinfo, errstr) != OK)
     return FALSE;
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
+#endif
+
+
 if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
   {
   tls_error(US"SSL_new", host, NULL, errstr);
   return FALSE;
   }
 SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
 if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
   {
   tls_error(US"SSL_new", host, NULL, errstr);
   return FALSE;
   }
 SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
+
+#ifdef EXPERIMENTAL_TLS_RESUME
+if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
+      errstr))
+  return FALSE;
+#endif
+
 SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
 SSL_set_connect_state(exim_client_ctx->ssl);
 
 SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
 SSL_set_connect_state(exim_client_ctx->ssl);
 
@@ -2729,6 +3085,10 @@ DEBUG(D_tls)
 #endif
   }
 
 #endif
   }
 
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_client_resume_posthandshake(exim_client_ctx, tlsp);
+#endif
+
 peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
 
 tlsp->cipher = construct_cipher_name(exim_client_ctx->ssl, &tlsp->bits);
 peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
 
 tlsp->cipher = construct_cipher_name(exim_client_ctx->ssl, &tlsp->bits);
@@ -3377,12 +3737,17 @@ uschar *end;
 uschar keep_c;
 BOOL adding, item_parsed;
 
 uschar keep_c;
 BOOL adding, item_parsed;
 
+/* Server: send no (<= TLS1.2) session tickets */
 result = SSL_OP_NO_TICKET;
 result = SSL_OP_NO_TICKET;
+
 /* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
  * from default because it increases BEAST susceptibility. */
 #ifdef SSL_OP_NO_SSLv2
 result |= SSL_OP_NO_SSLv2;
 #endif
 /* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
  * from default because it increases BEAST susceptibility. */
 #ifdef SSL_OP_NO_SSLv2
 result |= SSL_OP_NO_SSLv2;
 #endif
+#ifdef SSL_OP_NO_SSLv3
+result |= SSL_OP_NO_SSLv3;
+#endif
 #ifdef SSL_OP_SINGLE_DH_USE
 result |= SSL_OP_SINGLE_DH_USE;
 #endif
 #ifdef SSL_OP_SINGLE_DH_USE
 result |= SSL_OP_SINGLE_DH_USE;
 #endif
@@ -3393,7 +3758,7 @@ if (!option_spec)
   return TRUE;
   }
 
   return TRUE;
   }
 
-for (uschar * s = option_spec; *s != '\0'; /**/)
+for (uschar * s = option_spec; *s; /**/)
   {
   while (isspace(*s)) ++s;
   if (*s == '\0')
   {
   while (isspace(*s)) ++s;
   if (*s == '\0')
index 23e9d41113f695f08090e96aba49aa914496e650..7b8d7a2a3aae1504bb19942280ce544aad198250 100644 (file)
@@ -20,8 +20,10 @@ functions from the OpenSSL or GNU TLS libraries. */
 #include "transports/smtp.h"
 
 #if defined(MACRO_PREDEF) && defined(SUPPORT_TLS)
 #include "transports/smtp.h"
 
 #if defined(MACRO_PREDEF) && defined(SUPPORT_TLS)
-# ifndef USE_GNUTLS
-#  include "macro_predef.h"
+# include "macro_predef.h"
+# ifdef USE_GNUTLS
+#  include "tls-gnu.c"
+# else
 #  include "tls-openssl.c"
 # endif
 #endif
 #  include "tls-openssl.c"
 # endif
 #endif
index f34db091458a8248922fc3db50e8650bad34bcc3..fb74dfdcde44919d4b99c736f025186dda4de57e 100644 (file)
@@ -1475,7 +1475,7 @@ DEBUG(D_transport) debug_printf("updating wait-%s database\n", tpname);
 /* Open the database for this transport */
 
 if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", tpname),
 /* Open the database for this transport */
 
 if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", tpname),
-                     O_RDWR, &dbblock, TRUE)))
+                     O_RDWR, &dbblock, TRUE, TRUE)))
   return;
 
 /* Scan the list of hosts for which this message is waiting, and ensure
   return;
 
 /* Scan the list of hosts for which this message is waiting, and ensure
@@ -1648,7 +1648,7 @@ if (local_message_max > 0 && continue_sequence >= local_message_max)
 /* Open the waiting information database. */
 
 if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", transport_name),
 /* Open the waiting information database. */
 
 if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", transport_name),
-                         O_RDWR, &dbblock, TRUE)))
+                         O_RDWR, &dbblock, TRUE, TRUE)))
   return FALSE;
 
 /* See if there is a record for this host; if not, there's nothing to do. */
   return FALSE;
 
 /* See if there is a record for this host; if not, there's nothing to do. */
index 806c41fed3ed20268b18175c45dd961b58a2d48c..f76b4f730cd0ba5de83cdd529880cd83ea3f4557 100644 (file)
@@ -183,6 +183,10 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, tls_privatekey) },
   { "tls_require_ciphers",  opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_require_ciphers) },
       (void *)offsetof(smtp_transport_options_block, tls_privatekey) },
   { "tls_require_ciphers",  opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_require_ciphers) },
+# ifdef EXPERIMENTAL_TLS_RESUME
+  { "tls_resumption_hosts", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, tls_resumption_hosts) },
+# endif
   { "tls_sni",              opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_sni) },
   { "tls_tempfail_tryclear", opt_bool,
   { "tls_sni",              opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_sni) },
   { "tls_tempfail_tryclear", opt_bool,
@@ -293,6 +297,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   .tls_verify_certificates =   US"system",
   .tls_dh_min_bits =           EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
   .tls_tempfail_tryclear =     TRUE,
   .tls_verify_certificates =   US"system",
   .tls_dh_min_bits =           EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
   .tls_tempfail_tryclear =     TRUE,
+# ifdef EXPERIMENTAL_TLS_RESUME
+  .tls_resumption_hosts =      NULL,
+# endif
   .tls_verify_hosts =          NULL,
   .tls_try_verify_hosts =      US"*",
   .tls_verify_cert_hostnames = US"*",
   .tls_verify_hosts =          NULL,
   .tls_try_verify_hosts =      US"*",
   .tls_verify_cert_hostnames = US"*",
@@ -825,7 +832,7 @@ write_ehlo_cache_entry(const smtp_context * sx)
 {
 open_db dbblock, * dbm_file;
 
 {
 open_db dbblock, * dbm_file;
 
-if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE)))
+if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
   {
   uschar * ehlo_resp_key = ehlo_cache_key(sx);
   dbdata_ehlo_resp er = { .data = sx->ehlo_resp };
   {
   uschar * ehlo_resp_key = ehlo_cache_key(sx);
   dbdata_ehlo_resp er = { .data = sx->ehlo_resp };
@@ -845,7 +852,7 @@ invalidate_ehlo_cache_entry(smtp_context * sx)
 open_db dbblock, * dbm_file;
 
 if (  sx->early_pipe_active
 open_db dbblock, * dbm_file;
 
 if (  sx->early_pipe_active
-   && (dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE)))
+   && (dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
   {
   uschar * ehlo_resp_key = ehlo_cache_key(sx);
   dbfn_delete(dbm_file, ehlo_resp_key);
   {
   uschar * ehlo_resp_key = ehlo_cache_key(sx);
   dbfn_delete(dbm_file, ehlo_resp_key);
@@ -859,7 +866,7 @@ read_ehlo_cache_entry(smtp_context * sx)
 open_db dbblock;
 open_db * dbm_file;
 
 open_db dbblock;
 open_db * dbm_file;
 
-if (!(dbm_file = dbfn_open(US"misc", O_RDONLY, &dbblock, FALSE)))
+if (!(dbm_file = dbfn_open(US"misc", O_RDONLY, &dbblock, FALSE, TRUE)))
   { DEBUG(D_transport) debug_printf("ehlo-cache: no misc DB\n"); }
 else
   {
   { DEBUG(D_transport) debug_printf("ehlo-cache: no misc DB\n"); }
 else
   {
@@ -872,7 +879,7 @@ else
     {
     DEBUG(D_transport) debug_printf("ehlo-resp record too old\n");
     dbfn_close(dbm_file);
     {
     DEBUG(D_transport) debug_printf("ehlo-resp record too old\n");
     dbfn_close(dbm_file);
-    if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE)))
+    if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
       dbfn_delete(dbm_file, ehlo_resp_key);
     }
   else
       dbfn_delete(dbm_file, ehlo_resp_key);
     }
   else
@@ -2016,6 +2023,9 @@ tls_out.peerdn = NULL;
 tls_out.sni = NULL;
 #endif
 tls_out.ocsp = OCSP_NOT_REQ;
 tls_out.sni = NULL;
 #endif
 tls_out.ocsp = OCSP_NOT_REQ;
+#ifdef EXPERIMENTAL_TLS_RESUME
+tls_out.resumption = 0;
+#endif
 
 /* Flip the legacy TLS-related variables over to the outbound set in case
 they're used in the context of the transport.  Don't bother resetting
 
 /* Flip the legacy TLS-related variables over to the outbound set in case
 they're used in the context of the transport.  Don't bother resetting
index 056efbcf7cf084c41d41cdc1aeecb2b9eeaca75d..ab0e93ff8a278b6698e6603c6fdcec4bddb2479b 100644 (file)
@@ -83,6 +83,9 @@ typedef struct {
   uschar *tls_crl;
   uschar *tls_privatekey;
   uschar *tls_require_ciphers;
   uschar *tls_crl;
   uschar *tls_privatekey;
   uschar *tls_require_ciphers;
+# ifdef EXPERIMENTAL_TLS_RESUME
+  uschar *tls_resumption_hosts;
+# endif
   uschar *tls_sni;
   uschar *tls_verify_certificates;
   int     tls_dh_min_bits;
   uschar *tls_sni;
   uschar *tls_verify_certificates;
   int     tls_dh_min_bits;
index 528a668b81be3f1dfda0b1730db424c893f3ecd4..720f85d8ce7f537539bde311acdd7ab6bb60937c 100644 (file)
@@ -140,7 +140,7 @@ if (options & vopt_callout_no_cache)
   {
   HDEBUG(D_verify) debug_printf("callout cache: disabled by no_cache\n");
   }
   {
   HDEBUG(D_verify) debug_printf("callout cache: disabled by no_cache\n");
   }
-else if (!(dbm_file = dbfn_open(US"callout", O_RDWR, &dbblock, FALSE)))
+else if (!(dbm_file = dbfn_open(US"callout", O_RDWR, &dbblock, FALSE, TRUE)))
   {
   HDEBUG(D_verify) debug_printf("callout cache: not available\n");
   }
   {
   HDEBUG(D_verify) debug_printf("callout cache: not available\n");
   }
@@ -313,7 +313,7 @@ implying some kind of I/O error. We don't want to write the cache in that case.
 Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */
 
 if (dom_rec->result != ccache_unknown)
 Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */
 
 if (dom_rec->result != ccache_unknown)
-  if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE)))
+  if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE)))
     {
     HDEBUG(D_verify) debug_printf("callout cache: not available\n");
     }
     {
     HDEBUG(D_verify) debug_printf("callout cache: not available\n");
     }
@@ -335,7 +335,7 @@ is disabled. */
 if (done  &&  addr_rec->result != ccache_unknown)
   {
   if (!dbm_file)
 if (done  &&  addr_rec->result != ccache_unknown)
   {
   if (!dbm_file)
-    dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE);
+    dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE);
   if (!dbm_file)
     {
     HDEBUG(D_verify) debug_printf("no callout cache available\n");
   if (!dbm_file)
     {
     HDEBUG(D_verify) debug_printf("no callout cache available\n");
@@ -3245,7 +3245,7 @@ int
 verify_check_host(uschar **listptr)
 {
 return verify_check_this_host(CUSS listptr, sender_host_cache, NULL,
 verify_check_host(uschar **listptr)
 {
 return verify_check_this_host(CUSS listptr, sender_host_cache, NULL,
-  (sender_host_address == NULL)? US"" : sender_host_address, NULL);
+  sender_host_address ? sender_host_address : US"", NULL);
 }
 
 
 }
 
 
index 965bc8b247195d7ab108f530de2e243afa810a2e..1c464f63e6d8ebc4c99c50c63b0e1b5803c99401 100644 (file)
@@ -1,4 +1,4 @@
-keep_environment = PATH
+keep_environment = PATH:SSLKEYLOGFILE
 exim_path = EXIM_PATH
 host_lookup_order = bydns
 spool_directory = DIR/spool
 exim_path = EXIM_PATH
 host_lookup_order = bydns
 spool_directory = DIR/spool
diff --git a/test/confs/5890 b/test/confs/5890
new file mode 100644 (file)
index 0000000..6daf596
--- /dev/null
@@ -0,0 +1,94 @@
+# Exim test configuration 5890
+
+SERVER =
+OPTION = NORMAL
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : *.test.ex
+
+acl_smtp_helo = check_helo
+acl_smtp_rcpt = check_recipient
+log_selector = +received_recipients +tls_resumption
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+tls_require_ciphers = OPTION
+tls_resumption_hosts = 127.0.0.1
+
+
+# ------ ACL ------
+
+begin acl
+
+check_helo:
+  accept  condition =  ${if def:tls_in_cipher}
+         logwrite =    tls_in_resumption ${listextract {$tls_in_resumption} {_RESUME_DECODE}}
+  accept
+
+check_recipient:
+  accept  domains =    +local_domains
+  deny    message =    relay not permitted
+
+log_resumption:
+  accept condition =   ${if def:tls_out_cipher}
+        condition =    ${if eq {$event_name}{tcp:close}}
+        logwrite =     tls_out_resumption ${listextract {$tls_out_resumption} {_RESUME_DECODE}}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+  driver = accept
+  condition = ${if eq {SERVER}{server}{no}{yes}}
+  retry_use_local_part
+  transport = send_to_server${if eq{$local_part}{abcd}{2}{1}}
+
+server:
+  driver = redirect
+  data = :blackhole:
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server1:
+  driver = smtp
+  allow_localhost
+  hosts = 127.0.0.1
+  port = PORT_D
+  helo_data = helo.data.changed
+.ifdef VALUE
+  tls_resumption_hosts = *
+.else
+  tls_resumption_hosts = :
+.endif
+  event_action =       ${acl {log_resumption}}
+
+send_to_server2:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  event_action =       ${acl {log_resumption}}
+
+
+# ----- Retry -----
+
+
+begin retry
+
+* * F,5d,10s
+
+
+# End
diff --git a/test/confs/5891 b/test/confs/5891
new file mode 100644 (file)
index 0000000..78d22f7
--- /dev/null
@@ -0,0 +1,94 @@
+# Exim test configuration 5891
+
+SERVER =
+OPTION =
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : *.test.ex
+
+acl_smtp_helo = check_helo
+acl_smtp_rcpt = check_recipient
+log_selector = +received_recipients +tls_resumption
+
+openssl_options = +no_sslv2 +no_sslv3 +single_dh_use OPTION
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+tls_resumption_hosts = 127.0.0.1
+
+
+# ------ ACL ------
+
+begin acl
+
+check_helo:
+  accept  condition =  ${if def:tls_in_cipher}
+         logwrite =    tls_in_resumption ${listextract {$tls_in_resumption} {_RESUME_DECODE}}
+  accept
+
+check_recipient:
+  accept  domains =    +local_domains
+  deny    message =    relay not permitted
+
+log_resumption:
+  accept condition =   ${if def:tls_out_cipher}
+        condition =    ${if eq {$event_name}{tcp:close}}
+        logwrite =     tls_out_resumption ${listextract {$tls_out_resumption} {_RESUME_DECODE}}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+  driver = accept
+  condition = ${if eq {SERVER}{server}{no}{yes}}
+  retry_use_local_part
+  transport = send_to_server${if eq{$local_part}{abcd}{2}{1}}
+
+server:
+  driver = redirect
+  data = :blackhole:
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server1:
+  driver = smtp
+  allow_localhost
+  hosts = 127.0.0.1
+  port = PORT_D
+  helo_data = helo.data.changed
+.ifdef VALUE
+  tls_resumption_hosts = *
+.else
+  tls_resumption_hosts = :
+.endif
+  event_action =       ${acl {log_resumption}}
+
+send_to_server2:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+  event_action =       ${acl {log_resumption}}
+
+
+# ----- Retry -----
+
+
+begin retry
+
+* * F,5d,10s
+
+
+# End
index 5ec2c1cb9c89ea183b437dc21b28e226bf9c4b52..215bbe243f56f2b96aa60e6be2603d54516807f2 100644 (file)
@@ -40,7 +40,7 @@
 1999-03-02 09:44:33 sha256 fingerprint E251FA7D0372CB784294CF92B243DCE53FDDABD9F58A1B89226586C07C82CAC6
 1999-03-02 09:44:33 der_b64 MIIDuDCCAqCgAwIBAgICAMkwDQYJKoZIhvcNAQELBQAwNzEUMBIGA1UEChMLZXhhbXBsZS5jb20xHzAdBgNVBAMTFmNsaWNhIFNpZ25pbmcgQ2VydCByc2EwHhcNMTIxMTAxMTI0MDA0WhcNMzcxMjAxMTI0MDA0WjAeMRwwGgYDVQQDExNzZXJ2ZXIyLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA52Rfiv2Igy0NiaKN5gc0VPLbEoHngkdJWv3wEORp+iFl6skQRbsCylT8djJ2pvHstFpnzSodF3Wwjj2/EDuj3iKBzN9HeXJOvJz8j9Si1xkgCxJeUjPGgYcvKdxybaZAOpi9l3xwPCCEXN4JBq/WaQQ9+eP1PczeMNfvFtXma+VcHXG743ttPOv7eSMr0JxQl3zjQvYGOhFP/KAw6jh/N6YPqii9kV0cC/ubeVzpqJ5/+hndx5YrmAu39N5qzwWujhDPkFNSgCJUhfkEiMaQiPxFxDTbUzWnQ5jpAQ5El4WJVkGWkqxose1bOjSSNzFPJt59YtxxJC3IWN3UtGODTwIDAQABo4HmMIHjMA4GA1UdDwEB/wQEAwIE8DAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTgYDVR0jBEcwRYANQUFidHdDeGNYZ2IwUaExpC8wLTEUMBIGA1UEChMLZXhhbXBsZS5jb20xFTATBgNVBAMTDGNsaWNhIENBIHJzYYIBQjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vc2NwLmV4YW1wbGUuY29tLzApBgNVHREEIjAgghNzZXJ2ZXIyLmV4YW1wbGUuY29tggkqLnRlc3QuZXgwDQYJKoZIhvcNAQELBQADggEBALHOkZkvHLpNm0QSof09vmmdNFE6/+0TCIoPExeqqSOsy4NsF+Ha46WttjJRSVtbhRxF8jxEU7btPiFgQUaOcJZTwQPDhmQSOPNO8GS46oJ57aQ7U7O+X3M1sVS5Pa2IzE6vrJSh349/CNbTA8WPQdWLlxVJhJXAcZNtaEu6lCsZuDSMTpAsW5I4+snyrm3yvP5t0eD28K5LgCKePX962drkAOP6XGQ51VnbMQ7b1TSdQedtYKIpR3VKUvG5Ky/+0c+Rmwfi2aQ8oXXwekzJyS5jvovdVVsdhO68It+Rz/zursN5Pn+Gj1YuQNUs2nDrGHN+VIIFpgWUjLZO4bcJctY=
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="/CN=server2.example.com" S=sss
 1999-03-02 09:44:33 sha256 fingerprint E251FA7D0372CB784294CF92B243DCE53FDDABD9F58A1B89226586C07C82CAC6
 1999-03-02 09:44:33 der_b64 MIIDuDCCAqCgAwIBAgICAMkwDQYJKoZIhvcNAQELBQAwNzEUMBIGA1UEChMLZXhhbXBsZS5jb20xHzAdBgNVBAMTFmNsaWNhIFNpZ25pbmcgQ2VydCByc2EwHhcNMTIxMTAxMTI0MDA0WhcNMzcxMjAxMTI0MDA0WjAeMRwwGgYDVQQDExNzZXJ2ZXIyLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA52Rfiv2Igy0NiaKN5gc0VPLbEoHngkdJWv3wEORp+iFl6skQRbsCylT8djJ2pvHstFpnzSodF3Wwjj2/EDuj3iKBzN9HeXJOvJz8j9Si1xkgCxJeUjPGgYcvKdxybaZAOpi9l3xwPCCEXN4JBq/WaQQ9+eP1PczeMNfvFtXma+VcHXG743ttPOv7eSMr0JxQl3zjQvYGOhFP/KAw6jh/N6YPqii9kV0cC/ubeVzpqJ5/+hndx5YrmAu39N5qzwWujhDPkFNSgCJUhfkEiMaQiPxFxDTbUzWnQ5jpAQ5El4WJVkGWkqxose1bOjSSNzFPJt59YtxxJC3IWN3UtGODTwIDAQABo4HmMIHjMA4GA1UdDwEB/wQEAwIE8DAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTgYDVR0jBEcwRYANQUFidHdDeGNYZ2IwUaExpC8wLTEUMBIGA1UEChMLZXhhbXBsZS5jb20xFTATBgNVBAMTDGNsaWNhIENBIHJzYYIBQjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vc2NwLmV4YW1wbGUuY29tLzApBgNVHREEIjAgghNzZXJ2ZXIyLmV4YW1wbGUuY29tggkqLnRlc3QuZXgwDQYJKoZIhvcNAQELBQADggEBALHOkZkvHLpNm0QSof09vmmdNFE6/+0TCIoPExeqqSOsy4NsF+Ha46WttjJRSVtbhRxF8jxEU7btPiFgQUaOcJZTwQPDhmQSOPNO8GS46oJ57aQ7U7O+X3M1sVS5Pa2IzE6vrJSh349/CNbTA8WPQdWLlxVJhJXAcZNtaEu6lCsZuDSMTpAsW5I4+snyrm3yvP5t0eD28K5LgCKePX962drkAOP6XGQ51VnbMQ7b1TSdQedtYKIpR3VKUvG5Ky/+0c+Rmwfi2aQ8oXXwekzJyS5jvovdVVsdhO68It+Rz/zursN5Pn+Gj1YuQNUs2nDrGHN+VIIFpgWUjLZO4bcJctY=
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="/CN=server2.example.com" S=sss
-1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+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 Our cert SN: <CN=server1.example_ec.com>
 1999-03-02 09:44:33 Peer did not present a cert
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@test.ex H=[127.0.0.1] P=smtps X=TLS1.x:ke-ECDSA-AES256-SHAnnn:xxx CV=no S=sss
 1999-03-02 09:44:33 Our cert SN: <CN=server1.example_ec.com>
 1999-03-02 09:44:33 Peer did not present a cert
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@test.ex H=[127.0.0.1] P=smtps X=TLS1.x:ke-ECDSA-AES256-SHAnnn:xxx CV=no S=sss
diff --git a/test/log/5890 b/test/log/5890
new file mode 100644 (file)
index 0000000..9d098e5
--- /dev/null
@@ -0,0 +1,116 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for getticket@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 tls_out_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmaX-0005vi-00 => getticket@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for resume@test.ex abcd@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 tls_out_resumption not requested or offered
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => resume@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 -> xyz@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => abcd@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for renewal@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmbC-0005vi-00 => renewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbD-0005vi-00"
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => postrenewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbF-0005vi-00"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for timeout@test.ex
+1999-03-02 09:44:33 10HmbG-0005vi-00 tls_out_resumption client offered session, server only provided new ticket
+1999-03-02 09:44:33 10HmbG-0005vi-00 => timeout@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbH-0005vi-00"
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for notreq@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 tls_out_resumption no client request
+1999-03-02 09:44:33 10HmbI-0005vi-00 => notreq@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbJ-0005vi-00"
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for getticket@test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 tls_out_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbK-0005vi-00 => getticket@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbL-0005vi-00"
+1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for resume@test.ex abcd@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 tls_out_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbM-0005vi-00 tls_out_resumption not requested or offered
+1999-03-02 09:44:33 10HmbM-0005vi-00 => resume@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbN-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 -> xyz@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbN-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 => abcd@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbO-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbP-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for renewal@test.ex
+1999-03-02 09:44:33 10HmbP-0005vi-00 tls_out_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbP-0005vi-00 => renewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbQ-0005vi-00"
+1999-03-02 09:44:33 10HmbP-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbR-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbR-0005vi-00 tls_out_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbR-0005vi-00 => postrenewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbS-0005vi-00"
+1999-03-02 09:44:33 10HmbR-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbT-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for timeout@test.ex
+1999-03-02 09:44:33 10HmbT-0005vi-00 tls_out_resumption client offered session, server only provided new ticket
+1999-03-02 09:44:33 10HmbT-0005vi-00 => timeout@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbU-0005vi-00"
+1999-03-02 09:44:33 10HmbT-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbV-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for notreq@test.ex
+1999-03-02 09:44:33 10HmbV-0005vi-00 tls_out_resumption no client request
+1999-03-02 09:44:33 10HmbV-0005vi-00 => notreq@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbW-0005vi-00"
+1999-03-02 09:44:33 10HmbV-0005vi-00 Completed
+
+******** SERVER ********
+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 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for getticket@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <getticket@test.ex> R=server
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for resume@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <xyz@test.ex> R=server
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <resume@test.ex> R=server
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption not requested or offered
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for abcd@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 => :blackhole: <abcd@test.ex> R=server
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbC-0005vi-00@myhost.test.ex for renewal@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 => :blackhole: <renewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke--AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbE-0005vi-00@myhost.test.ex for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 => :blackhole: <postrenewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption client offered session, server only provided new ticket
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbG-0005vi-00@myhost.test.ex for timeout@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 => :blackhole: <timeout@test.ex> R=server
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbJ-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbI-0005vi-00@myhost.test.ex for notreq@test.ex
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => :blackhole: <notreq@test.ex> R=server
+1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+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 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbK-0005vi-00@myhost.test.ex for getticket@test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 => :blackhole: <getticket@test.ex> R=server
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbN-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbM-0005vi-00@myhost.test.ex for resume@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmbN-0005vi-00 => :blackhole: <xyz@test.ex> R=server
+1999-03-02 09:44:33 10HmbN-0005vi-00 => :blackhole: <resume@test.ex> R=server
+1999-03-02 09:44:33 10HmbN-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption not requested or offered
+1999-03-02 09:44:33 10HmbO-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbM-0005vi-00@myhost.test.ex for abcd@test.ex
+1999-03-02 09:44:33 10HmbO-0005vi-00 => :blackhole: <abcd@test.ex> R=server
+1999-03-02 09:44:33 10HmbO-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbQ-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbP-0005vi-00@myhost.test.ex for renewal@test.ex
+1999-03-02 09:44:33 10HmbQ-0005vi-00 => :blackhole: <renewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbQ-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbS-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-PSK-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbR-0005vi-00@myhost.test.ex for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbS-0005vi-00 => :blackhole: <postrenewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbS-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbU-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbT-0005vi-00@myhost.test.ex for timeout@test.ex
+1999-03-02 09:44:33 10HmbU-0005vi-00 => :blackhole: <timeout@test.ex> R=server
+1999-03-02 09:44:33 10HmbU-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbW-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbV-0005vi-00@myhost.test.ex for notreq@test.ex
+1999-03-02 09:44:33 10HmbW-0005vi-00 => :blackhole: <notreq@test.ex> R=server
+1999-03-02 09:44:33 10HmbW-0005vi-00 Completed
diff --git a/test/log/5891 b/test/log/5891
new file mode 100644 (file)
index 0000000..8131404
--- /dev/null
@@ -0,0 +1,130 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for getticket@test.ex
+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=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
+1999-03-02 09:44:33 10HmaX-0005vi-00 tls_out_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmaX-0005vi-00 => getticket@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for resume@test.ex abcd@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 [ip4.ip4.ip4.ip4] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmaZ-0005vi-00 [ip4.ip4.ip4.ip4] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="ip4.ip4.ip4.ip4"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 tls_out_resumption not requested or offered
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => resume@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 -> xyz@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => abcd@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for renewal@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmbC-0005vi-00 => renewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbD-0005vi-00"
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => postrenewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbF-0005vi-00"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for timeout@test.ex
+1999-03-02 09:44:33 10HmbG-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbG-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
+1999-03-02 09:44:33 10HmbG-0005vi-00 tls_out_resumption client offered session, server only provided new ticket
+1999-03-02 09:44:33 10HmbG-0005vi-00 => timeout@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbH-0005vi-00"
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for notreq@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbI-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
+1999-03-02 09:44:33 10HmbI-0005vi-00 tls_out_resumption not requested or offered
+1999-03-02 09:44:33 10HmbI-0005vi-00 => notreq@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbJ-0005vi-00"
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for getticket@test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbK-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
+1999-03-02 09:44:33 10HmbK-0005vi-00 tls_out_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbK-0005vi-00 => getticket@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbL-0005vi-00"
+1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for resume@test.ex abcd@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmbM-0005vi-00 [ip4.ip4.ip4.ip4] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbM-0005vi-00 [ip4.ip4.ip4.ip4] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="ip4.ip4.ip4.ip4"
+1999-03-02 09:44:33 10HmbM-0005vi-00 tls_out_resumption not requested or offered
+1999-03-02 09:44:33 10HmbM-0005vi-00 => resume@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbN-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 -> xyz@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbN-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 => abcd@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbO-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbP-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for renewal@test.ex
+1999-03-02 09:44:33 10HmbP-0005vi-00 tls_out_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbP-0005vi-00 => renewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbQ-0005vi-00"
+1999-03-02 09:44:33 10HmbP-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbR-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbR-0005vi-00 tls_out_resumption session resumed
+1999-03-02 09:44:33 10HmbR-0005vi-00 => postrenewal@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbS-0005vi-00"
+1999-03-02 09:44:33 10HmbR-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbT-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for timeout@test.ex
+1999-03-02 09:44:33 10HmbT-0005vi-00 tls_out_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbT-0005vi-00 => timeout@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no C="250 OK id=10HmbU-0005vi-00"
+1999-03-02 09:44:33 10HmbT-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbV-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for notreq@test.ex
+1999-03-02 09:44:33 10HmbV-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbV-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
+1999-03-02 09:44:33 10HmbV-0005vi-00 tls_out_resumption not requested or offered
+1999-03-02 09:44:33 10HmbV-0005vi-00 => notreq@test.ex R=client T=send_to_server1 H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmbW-0005vi-00"
+1999-03-02 09:44:33 10HmbV-0005vi-00 Completed
+
+******** SERVER ********
+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 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for getticket@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <getticket@test.ex> R=server
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for resume@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <xyz@test.ex> R=server
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <resume@test.ex> R=server
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption not requested or offered
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for abcd@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 => :blackhole: <abcd@test.ex> R=server
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbC-0005vi-00@myhost.test.ex for renewal@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 => :blackhole: <renewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbE-0005vi-00@myhost.test.ex for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 => :blackhole: <postrenewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption client offered session, server only provided new ticket
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbG-0005vi-00@myhost.test.ex for timeout@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 => :blackhole: <timeout@test.ex> R=server
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption no client request
+1999-03-02 09:44:33 10HmbJ-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbI-0005vi-00@myhost.test.ex for notreq@test.ex
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => :blackhole: <notreq@test.ex> R=server
+1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+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 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbK-0005vi-00@myhost.test.ex for getticket@test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 => :blackhole: <getticket@test.ex> R=server
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed
+1999-03-02 09:44:33 10HmbN-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbM-0005vi-00@myhost.test.ex for resume@test.ex xyz@test.ex
+1999-03-02 09:44:33 10HmbN-0005vi-00 => :blackhole: <xyz@test.ex> R=server
+1999-03-02 09:44:33 10HmbN-0005vi-00 => :blackhole: <resume@test.ex> R=server
+1999-03-02 09:44:33 10HmbN-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption not requested or offered
+1999-03-02 09:44:33 10HmbO-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbM-0005vi-00@myhost.test.ex for abcd@test.ex
+1999-03-02 09:44:33 10HmbO-0005vi-00 => :blackhole: <abcd@test.ex> R=server
+1999-03-02 09:44:33 10HmbO-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbQ-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbP-0005vi-00@myhost.test.ex for renewal@test.ex
+1999-03-02 09:44:33 10HmbQ-0005vi-00 => :blackhole: <renewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbQ-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed
+1999-03-02 09:44:33 10HmbS-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbR-0005vi-00@myhost.test.ex for postrenewal@test.ex
+1999-03-02 09:44:33 10HmbS-0005vi-00 => :blackhole: <postrenewal@test.ex> R=server
+1999-03-02 09:44:33 10HmbS-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption session resumed, also new ticket
+1999-03-02 09:44:33 10HmbU-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx* CV=no S=sss id=E10HmbT-0005vi-00@myhost.test.ex for timeout@test.ex
+1999-03-02 09:44:33 10HmbU-0005vi-00 => :blackhole: <timeout@test.ex> R=server
+1999-03-02 09:44:33 10HmbU-0005vi-00 Completed
+1999-03-02 09:44:33 tls_in_resumption client requested new ticket, server provided
+1999-03-02 09:44:33 10HmbW-0005vi-00 <= CALLER@myhost.test.ex H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no S=sss id=E10HmbV-0005vi-00@myhost.test.ex for notreq@test.ex
+1999-03-02 09:44:33 10HmbW-0005vi-00 => :blackhole: <notreq@test.ex> R=server
+1999-03-02 09:44:33 10HmbW-0005vi-00 Completed
index 6566579efacbcbfec3224e79df7fd9f1bec47bd7..a9927475e06dfdba8630a91ef9c7ea7618d05faf 100755 (executable)
@@ -615,9 +615,10 @@ RESET_AFTER_EXTRA_LINE_READ:
   #   TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_256_GCM:256
   #   TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_128_CBC__SHA256:128
   #   TLS1.2:ECDHE_SECP256R1__ECDSA_SHA512__AES_256_GCM:256
   #   TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_256_GCM:256
   #   TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_128_CBC__SHA256:128
   #   TLS1.2:ECDHE_SECP256R1__ECDSA_SHA512__AES_256_GCM:256
-  #   TLS1.2:ECDHE_RSA_SECP256R1__AES_256_GCM:256 (! 3.5.18 !)
-  #   TLS1.2:RSA__CAMELLIA_256_GCM:256 (leave the cipher name)
-  #   TLS1.2-PKIX:RSA__AES_128_GCM__AEAD:128 (the -PKIX seems to be a 3.1.20 thing)
+  #   TLS1.2:ECDHE_SECP256R1__AES_256_GCM:256          (3.6.7 resumption)
+  #   TLS1.2:ECDHE_RSA_SECP256R1__AES_256_GCM:256      (! 3.5.18 !)
+  #   TLS1.2:RSA__CAMELLIA_256_GCM:256                 (leave the cipher name)
+  #   TLS1.2-PKIX:RSA__AES_128_GCM__AEAD:128           (the -PKIX seems to be a 3.1.20 thing)
   #   TLS1.2-PKIX:ECDHE_RSA_SECP521R1__AES_256_GCM__AEAD:256
   #
   #   X=TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256
   #   TLS1.2-PKIX:ECDHE_RSA_SECP521R1__AES_256_GCM__AEAD:256
   #
   #   X=TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256
@@ -1000,6 +1001,10 @@ RESET_AFTER_EXTRA_LINE_READ:
 
     # ARC is not always supported by the build
     next if /^arc_sign =/;
 
     # ARC is not always supported by the build
     next if /^arc_sign =/;
+
+    # TLS resumption is not always supported by the build
+    next if /^tls_resumption_hosts =/;
+    next if /^-tls_resumption/;
     }
 
   # ======== stderr ========
     }
 
   # ======== stderr ========
@@ -1225,6 +1230,9 @@ RESET_AFTER_EXTRA_LINE_READ:
     # Not all builds include DMARC
     next if /^DMARC: no (dmarc_tld_file|sender_host_address)$/ ;
 
     # Not all builds include DMARC
     next if /^DMARC: no (dmarc_tld_file|sender_host_address)$/ ;
 
+    # TLS resumption is not always supported by the build
+    next if /in tls_resumption_hosts\?/;
+
     # When Exim is checking the size of directories for maildir, it uses
     # the check_dir_size() function to scan directories. Of course, the order
     # of the files that are obtained using readdir() varies from system to
     # When Exim is checking the size of directories for maildir, it uses
     # the check_dir_size() function to scan directories. Of course, the order
     # of the files that are obtained using readdir() varies from system to
diff --git a/test/scripts/5890-Resume-GnuTLS/5890 b/test/scripts/5890-Resume-GnuTLS/5890
new file mode 100644 (file)
index 0000000..9db5403
--- /dev/null
@@ -0,0 +1,62 @@
+# TLS session resumption
+gnutls
+#
+# For keying info:
+# (requires SSLKEYLOGFILE added to /etc/sudoers)
+# SSLKEYLOGFILE=/home/jgh/git/exim/test/foo sudo exim -DSERVER=server -bd -oX PORT_D
+#
+### TLS1.2
+exim -DSERVER=server -DOPTION=NORMAL:!VERS-TLS1.3 -bd -oX PORT_D
+****
+exim -DVALUE=resume -odf getticket@test.ex
+Test message. Contains FF: ÿ
+****
+exim -DVALUE=resume -odf resume@test.ex abcd@test.ex xyz@test.ex
+Test message to two different hosts, one does not support resume
+****
+# allow time for ticket to hit renewal time
+sleep 3
+exim -DVALUE=resume -odf renewal@test.ex
+Test message.
+****
+exim -DVALUE=resume -odf postrenewal@test.ex
+Test message.
+****
+sleep 3
+exim -DVALUE=resume -odf timeout@test.ex
+Test message.
+****
+exim -odf notreq@test.ex
+Test message, not requesting resumption.
+****
+killdaemon
+sleep 1
+sudo rm DIR/spool/db/tls
+#
+#
+### TLS1.3
+exim -DSERVER=server -DOPTION=NORMAL -bd -oX PORT_D
+****
+exim -DVALUE=resume -odf getticket@test.ex
+Test message. Contains FF: ÿ
+****
+exim -DVALUE=resume -odf resume@test.ex abcd@test.ex xyz@test.ex
+Test message to two different hosts, one does not support resume
+****
+# allow time for ticket to hit renewal time
+sleep 3
+exim -DVALUE=resume -odf renewal@test.ex
+Test message.
+****
+exim -DVALUE=resume -odf postrenewal@test.ex
+Test message.
+****
+sleep 3
+exim -DVALUE=resume -odf timeout@test.ex
+Test message.
+****
+exim -odf notreq@test.ex
+Test message, not requesting resumption.
+****
+killdaemon
+no_msglog_check
diff --git a/test/scripts/5890-Resume-GnuTLS/REQUIRES b/test/scripts/5890-Resume-GnuTLS/REQUIRES
new file mode 100644 (file)
index 0000000..2f12f27
--- /dev/null
@@ -0,0 +1,3 @@
+support GnuTLS
+running IPv4
+support Experimental_TLS_resume
diff --git a/test/scripts/5891-Resume-OpenSSL/5891 b/test/scripts/5891-Resume-OpenSSL/5891
new file mode 100644 (file)
index 0000000..116f5cf
--- /dev/null
@@ -0,0 +1,57 @@
+# TLS session resumption
+#
+### TLS1.2
+exim -DSERVER=server -DOPTION=+no_tlsv1_3 -bd -oX PORT_D
+****
+exim -DVALUE=resume -odf getticket@test.ex
+Test message. Contains FF: ÿ
+****
+exim -DVALUE=resume -odf resume@test.ex abcd@test.ex xyz@test.ex
+Test message to two different hosts, one does not support resume
+****
+# allow time for ticket to hit renewal time
+sleep 3
+exim -DVALUE=resume -odf renewal@test.ex
+Test message.
+****
+exim -DVALUE=resume -odf postrenewal@test.ex
+Test message.
+****
+sleep 3
+exim -DVALUE=resume -odf timeout@test.ex
+Test message.
+****
+exim -odf notreq@test.ex
+Test message, not requesting resumption.
+****
+killdaemon
+sleep 1
+sudo rm DIR/spool/db/tls
+#
+#
+### TLS1.3
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim -DVALUE=resume -odf getticket@test.ex
+Test message. Contains FF: ÿ
+****
+exim -DVALUE=resume -odf resume@test.ex abcd@test.ex xyz@test.ex
+Test message to two different hosts, one does not support resume
+****
+# allow time for ticket to hit renewal time
+sleep 3
+exim -DVALUE=resume -odf renewal@test.ex
+Test message.
+****
+exim -DVALUE=resume -odf postrenewal@test.ex
+Test message.
+****
+sleep 3
+exim -DVALUE=resume -odf timeout@test.ex
+Test message.
+****
+exim -odf notreq@test.ex
+Test message, not requesting resumption.
+****
+killdaemon
+no_msglog_check
diff --git a/test/scripts/5891-Resume-OpenSSL/REQUIRES b/test/scripts/5891-Resume-OpenSSL/REQUIRES
new file mode 100644 (file)
index 0000000..027b4dc
--- /dev/null
@@ -0,0 +1,3 @@
+support OpenSSL
+running IPv4
+support Experimental_TLS_resume
diff --git a/test/stderr/5890 b/test/stderr/5890
new file mode 100644 (file)
index 0000000..6b5c434
--- /dev/null
@@ -0,0 +1,6 @@
+### TLS1.2
+### TLS1.3
+
+******** SERVER ********
+### TLS1.2
+### TLS1.3
diff --git a/test/stderr/5891 b/test/stderr/5891
new file mode 100644 (file)
index 0000000..6b5c434
--- /dev/null
@@ -0,0 +1,6 @@
+### TLS1.2
+### TLS1.3
+
+******** SERVER ********
+### TLS1.2
+### TLS1.3
index 272aa06a1345b1e18496c2e86b4aab21e973d94f..0ea38119065164dd058459bf008aa43b118807da 100644 (file)
@@ -78,7 +78,7 @@ OPT =
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/tls_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/tls_conf_prefix"
-keep_environment = PATH
+keep_environment = PATH:SSLKEYLOGFILE
 exim_path = TESTSUITE/eximdir/exim
 host_lookup_order = bydns
 spool_directory = TESTSUITE/spool
 exim_path = TESTSUITE/eximdir/exim
 host_lookup_order = bydns
 spool_directory = TESTSUITE/spool
@@ -118,7 +118,7 @@ OPT =
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/tls_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/tls_conf_prefix"
-keep_environment = PATH
+keep_environment = PATH:SSLKEYLOGFILE
 exim_path = TESTSUITE/eximdir/exim
 host_lookup_order = bydns
 spool_directory = TESTSUITE/spool
 exim_path = TESTSUITE/eximdir/exim
 host_lookup_order = bydns
 spool_directory = TESTSUITE/spool
index ef918a86ba2fde04927cd0306b03911ffae45aa1..f08550f6f2db6c96fdaea9f3b67cc5324a07df39 100644 (file)
@@ -4,7 +4,7 @@
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/tls_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/std_conf_prefix"
 # 1 "TESTSUITE/aux-var/tls_conf_prefix"
-keep_environment = PATH
+keep_environment = PATH:SSLKEYLOGFILE
 exim_path = TESTSUITE/eximdir/exim
 host_lookup_order = bydns
 spool_directory = TESTSUITE/spool
 exim_path = TESTSUITE/eximdir/exim
 host_lookup_order = bydns
 spool_directory = TESTSUITE/spool
diff --git a/test/stdout/5890 b/test/stdout/5890
new file mode 100644 (file)
index 0000000..6b5c434
--- /dev/null
@@ -0,0 +1,6 @@
+### TLS1.2
+### TLS1.3
+
+******** SERVER ********
+### TLS1.2
+### TLS1.3
diff --git a/test/stdout/5891 b/test/stdout/5891
new file mode 100644 (file)
index 0000000..6b5c434
--- /dev/null
@@ -0,0 +1,6 @@
+### TLS1.2
+### TLS1.3
+
+******** SERVER ********
+### TLS1.2
+### TLS1.3