GnuTLS: Fix client detection of server reject of client cert under TLS1.3
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 16 Feb 2019 12:59:23 +0000 (12:59 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 16 Feb 2019 12:59:23 +0000 (12:59 +0000)
12 files changed:
doc/doc-txt/ChangeLog
src/src/deliver.c
src/src/smtp_out.c
src/src/tls-gnu.c
src/src/transports/lmtp.c
src/src/transports/smtp.c
test/confs/2027
test/confs/5652
test/confs/5821
test/log/2027
test/runtest
test/scripts/2000-GnuTLS/2027

index 18db733aa8a6aedbb212030b9e9e61ed94c67dfb..6a9aae36573dfc8299657628b7b91dada8a6d71c 100644 (file)
@@ -11,7 +11,7 @@ Exim version 4.93
 JH/01 OpenSSL: With debug enabled output keying information sufficient, server
       side, to decode a TLS 1.3 packet capture.
 
 JH/01 OpenSSL: With debug enabled output keying information sufficient, server
       side, to decode a TLS 1.3 packet capture.
 
-JH/02 OpenSSL: suppress the sending of (stateful) TLS1.3 session tickets.
+JH/02 OpenSSL: Suppress the sending of (stateful) TLS1.3 session tickets.
       Previously the default library behaviour applied, sending two, each in
       its own TCP segment.
 
       Previously the default library behaviour applied, sending two, each in
       its own TCP segment.
 
@@ -25,6 +25,13 @@ JH/05 DKIM: ensure that dkim_domain elements are lowercased before use.
 JH/06 Fix buggy handling of autoreply bounce_return_size_limit, and a possible
       buffer overrun for (non-chunking) other transports.
 
 JH/06 Fix buggy handling of autoreply bounce_return_size_limit, and a possible
       buffer overrun for (non-chunking) other transports.
 
+JH/07 GnuTLS: Our use of late (post-handshake) certificate verification, under
+      TLS1.3, means that a server rejecting a client certificate is not visible
+      to the client until the first read of encrypted data (typically the
+      response to EHLO).  Add detection for that case and treat it as a failed
+      TLS connection attempt, so that the normal retry-in-clear can work (if
+      suitably configured).
+
 
 Exim version 4.92
 -----------------
 
 Exim version 4.92
 -----------------
index ebb64778c9dc7e74da348107ed0559d213ff2f0c..50647007072abfb30bc0df1c7cca61cc8885a212 100644 (file)
@@ -7401,7 +7401,7 @@ if (addr_senddsn)
 
     tctx.u.fd = fd;
     tctx.options = topt_add_return_path | topt_no_body;
 
     tctx.u.fd = fd;
     tctx.options = topt_add_return_path | topt_no_body;
-    /*XXX hmm, retval ignored.
+    /*XXX hmm, FALSE(fail) retval ignored.
     Could error for any number of reasons, and they are not handled. */
     transport_write_message(&tctx, 0);
     fflush(f);
     Could error for any number of reasons, and they are not handled. */
     transport_write_message(&tctx, 0);
     fflush(f);
index 8a4dace7e7f324f8589228035ac750f5422f4599..b7a8354797fa5c8b26ab0b60c1823ae839411976 100644 (file)
@@ -690,20 +690,22 @@ Returns:    TRUE if a valid, non-error response was received; else FALSE
 /*XXX could move to smtp transport; no other users */
 
 BOOL
 /*XXX could move to smtp transport; no other users */
 
 BOOL
-smtp_read_response(void * sx0, uschar *buffer, int size, int okdigit,
+smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit,
    int timeout)
 {
 smtp_context * sx = sx0;
    int timeout)
 {
 smtp_context * sx = sx0;
-uschar *ptr = buffer;
-int count = 0;
+uschar * ptr = buffer;
+int count = 0, rc;
 
 errno = 0;  /* Ensure errno starts out zero */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
 if (sx->pending_BANNER || sx->pending_EHLO)
 
 errno = 0;  /* Ensure errno starts out zero */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
 if (sx->pending_BANNER || sx->pending_EHLO)
-  if (smtp_reap_early_pipe(sx, &count) != OK)
+  if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
     {
     DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
     {
     DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
+    buffer[0] = '\0';
+    if (rc == DEFER) errno = ERRNO_TLSFAILURE;
     return FALSE;
     }
 #endif
     return FALSE;
     }
 #endif
index faad38f760e12412a0ead7e925009999fb71d56d..1752bf3d8ecf603b8f2223857e4112a838097b87 100644 (file)
@@ -238,7 +238,7 @@ static gnutls_dh_params_t dh_server_params = NULL;
 
 static const int ssl_session_timeout = 200;
 
 
 static const int ssl_session_timeout = 200;
 
-static const char * const exim_default_gnutls_priority = "NORMAL";
+static const uschar * const exim_default_gnutls_priority = US"NORMAL";
 
 /* Guard library core initialisation */
 
 
 /* Guard library core initialisation */
 
@@ -1287,7 +1287,6 @@ int rc;
 size_t sz;
 const char *errpos;
 uschar *p;
 size_t sz;
 const char *errpos;
 uschar *p;
-BOOL want_default_priorities;
 
 if (!exim_gnutls_base_init_done)
   {
 
 if (!exim_gnutls_base_init_done)
   {
@@ -1396,32 +1395,24 @@ and replaces gnutls_require_kx, gnutls_require_mac & gnutls_require_protocols.
 This was backwards incompatible, but means Exim no longer needs to track
 all algorithms and provide string forms for them. */
 
 This was backwards incompatible, but means Exim no longer needs to track
 all algorithms and provide string forms for them. */
 
-want_default_priorities = TRUE;
-
+p = NULL;
 if (state->tls_require_ciphers && *state->tls_require_ciphers)
   {
   if (!expand_check_tlsvar(tls_require_ciphers, errstr))
     return DEFER;
   if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers)
     {
 if (state->tls_require_ciphers && *state->tls_require_ciphers)
   {
   if (!expand_check_tlsvar(tls_require_ciphers, errstr))
     return DEFER;
   if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers)
     {
-    DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n",
-        state->exp_tls_require_ciphers);
-
-    rc = gnutls_priority_init(&state->priority_cache,
-        CS state->exp_tls_require_ciphers, &errpos);
-    want_default_priorities = FALSE;
     p = state->exp_tls_require_ciphers;
     p = state->exp_tls_require_ciphers;
+    DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n", p);
     }
   }
     }
   }
-if (want_default_priorities)
+if (!p)
   {
   {
+  p = exim_default_gnutls_priority;
   DEBUG(D_tls)
   DEBUG(D_tls)
-    debug_printf("GnuTLS using default session cipher/priority \"%s\"\n",
-        exim_default_gnutls_priority);
-  rc = gnutls_priority_init(&state->priority_cache,
-      exim_default_gnutls_priority, &errpos);
-  p = US exim_default_gnutls_priority;
+    debug_printf("GnuTLS using default session cipher/priority \"%s\"\n", p);
   }
   }
+rc = gnutls_priority_init(&state->priority_cache, CCS p, &errpos);
 
 exim_gnutls_err_check(rc, string_sprintf(
       "gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"",
 
 exim_gnutls_err_check(rc, string_sprintf(
       "gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"",
index f007f4a97a7065f0ee3fe5eadc030350e03d091c..b2bf5f0dae0801e7b989b5ef147765d841cae262 100644 (file)
@@ -122,7 +122,8 @@ Arguments:
 Returns:       TRUE if a "QUIT" command should be sent, else FALSE
 */
 
 Returns:       TRUE if a "QUIT" command should be sent, else FALSE
 */
 
-static BOOL check_response(int *errno_value, int more_errno, uschar *buffer,
+static BOOL
+check_response(int *errno_value, int more_errno, uschar *buffer,
   int *yield, uschar **message)
 {
 *yield = '4';    /* Default setting is to give a temporary error */
   int *yield, uschar **message)
 {
 *yield = '4';    /* Default setting is to give a temporary error */
index 9ee1304bc3f9bbf862788e4c87cd386fbb354b1d..6ff993d571f51dd6bdb9d768b9db5080bd279e1c 100644 (file)
@@ -593,6 +593,11 @@ switch(*errno_value)
          pl, smtp_command, s);
     return FALSE;
 
          pl, smtp_command, s);
     return FALSE;
 
+  case ERRNO_TLSFAILURE:       /* Handle bad first read; can happen with
+                               GnuTLS and TLS1.3 */
+    *message = US"bad first read from TLS conn";
+    return TRUE;
+
   case ERRNO_FILTER_FAIL:      /* Handle a failed filter process error;
                          can't send QUIT as we mustn't end the DATA. */
     *message = string_sprintf("transport filter process failed (%d)%s",
   case ERRNO_FILTER_FAIL:      /* Handle a failed filter process error;
                          can't send QUIT as we mustn't end the DATA. */
     *message = string_sprintf("transport filter process failed (%d)%s",
@@ -941,6 +946,7 @@ Arguments:
 
 Return:
  OK    all well
 
 Return:
  OK    all well
+ DEFER error on first read of TLS'd conn
  FAIL  SMTP error in response
 */
 int
  FAIL  SMTP error in response
 */
 int
@@ -948,6 +954,7 @@ smtp_reap_early_pipe(smtp_context * sx, int * countp)
 {
 BOOL pending_BANNER = sx->pending_BANNER;
 BOOL pending_EHLO = sx->pending_EHLO;
 {
 BOOL pending_BANNER = sx->pending_BANNER;
 BOOL pending_EHLO = sx->pending_EHLO;
+int rc = FAIL;
 
 sx->pending_BANNER = FALSE;    /* clear early to avoid recursion */
 sx->pending_EHLO = FALSE;
 
 sx->pending_BANNER = FALSE;    /* clear early to avoid recursion */
 sx->pending_EHLO = FALSE;
@@ -959,6 +966,7 @@ if (pending_BANNER)
   if (!smtp_reap_banner(sx))
     {
     DEBUG(D_transport) debug_printf("bad banner\n");
   if (!smtp_reap_banner(sx))
     {
     DEBUG(D_transport) debug_printf("bad banner\n");
+    if (tls_out.active.sock >= 0) rc = DEFER;
     goto fail;
     }
   }
     goto fail;
     }
   }
@@ -973,6 +981,7 @@ if (pending_EHLO)
   if (!smtp_reap_ehlo(sx))
     {
     DEBUG(D_transport) debug_printf("bad response for EHLO\n");
   if (!smtp_reap_ehlo(sx))
     {
     DEBUG(D_transport) debug_printf("bad response for EHLO\n");
+    if (tls_out.active.sock >= 0) rc = DEFER;
     goto fail;
     }
 
     goto fail;
     }
 
@@ -1010,7 +1019,7 @@ return OK;
 fail:
   invalidate_ehlo_cache_entry(sx);
   (void) smtp_discard_responses(sx, sx->conn_args.ob, *countp);
 fail:
   invalidate_ehlo_cache_entry(sx);
   (void) smtp_discard_responses(sx, sx->conn_args.ob, *countp);
-  return FAIL;
+  return rc;
 }
 #endif
 
 }
 #endif
 
@@ -1055,6 +1064,7 @@ Returns:      3 if at least one address had 2xx and one had 5xx
              -2 I/O or other non-response error for RCPT
              -3 DATA or MAIL failed - errno and buffer set
             -4 banner or EHLO failed (early-pipelining)
              -2 I/O or other non-response error for RCPT
              -3 DATA or MAIL failed - errno and buffer set
             -4 banner or EHLO failed (early-pipelining)
+            -5 banner or EHLO failed (early-pipelining, TLS)
 */
 
 static int
 */
 
 static int
@@ -1063,10 +1073,11 @@ sync_responses(smtp_context * sx, int count, int pending_DATA)
 address_item * addr = sx->sync_addr;
 smtp_transport_options_block * ob = sx->conn_args.ob;
 int yield = 0;
 address_item * addr = sx->sync_addr;
 smtp_transport_options_block * ob = sx->conn_args.ob;
 int yield = 0;
+int rc;
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
-if (smtp_reap_early_pipe(sx, &count) != OK)
-  return -4;
+if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
+  return rc == FAIL ? -4 : -5;
 #endif
 
 /* Handle the response for a MAIL command. On error, reinstate the original
 #endif
 
 /* Handle the response for a MAIL command. On error, reinstate the original
@@ -1082,6 +1093,8 @@ if (sx->pending_MAIL)
     {
     DEBUG(D_transport) debug_printf("bad response for MAIL\n");
     Ustrcpy(big_buffer, mail_command);  /* Fits, because it came from there! */
     {
     DEBUG(D_transport) debug_printf("bad response for MAIL\n");
     Ustrcpy(big_buffer, mail_command);  /* Fits, because it came from there! */
+    if (errno == ERRNO_TLSFAILURE)
+      return -5;
     if (errno == 0 && sx->buffer[0] != 0)
       {
       int save_errno = 0;
     if (errno == 0 && sx->buffer[0] != 0)
       {
       int save_errno = 0;
@@ -1140,6 +1153,11 @@ while (count-- > 0)
       }
     }
 
       }
     }
 
+  /* Error on first TLS read */
+
+  else if (errno == ERRNO_TLSFAILURE)
+    return -5;
+
   /* Timeout while reading the response */
 
   else if (errno == ETIMEDOUT)
   /* Timeout while reading the response */
 
   else if (errno == ETIMEDOUT)
@@ -1252,6 +1270,10 @@ if (pending_DATA != 0)
     int code;
     uschar *msg;
     BOOL pass_message;
     int code;
     uschar *msg;
     BOOL pass_message;
+
+    if (errno == ERRNO_TLSFAILURE)     /* Error on first TLS read */
+      return -5;
+
     if (pending_DATA > 0 || (yield & 1) != 0)
       {
       if (errno == 0 && sx->buffer[0] == '4')
     if (pending_DATA > 0 || (yield & 1) != 0)
       {
       if (errno == 0 && sx->buffer[0] == '4')
@@ -1800,7 +1822,9 @@ Args:
    tc_chunk_last       add LAST option to SMTP BDAT command
    tc_reap_prev                reap response to previous SMTP commands
 
    tc_chunk_last       add LAST option to SMTP BDAT command
    tc_reap_prev                reap response to previous SMTP commands
 
-Returns:       OK or ERROR
+Returns:
+  OK or ERROR
+  DEFER                        TLS error on first read (EHLO-resp); errno set
 */
 
 static int
 */
 
 static int
@@ -1857,10 +1881,12 @@ if (flags & tc_reap_prev  &&  prev_cmd_count > 0)
     case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */
     case 0: break;                     /* No 2xx or 5xx, but no probs */
 
     case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */
     case 0: break;                     /* No 2xx or 5xx, but no probs */
 
-    case -1:                           /* Timeout on RCPT */
+    case -5: errno = ERRNO_TLSFAILURE;
+            return DEFER;
 #ifdef EXPERIMENTAL_PIPE_CONNECT
     case -4:                           /* non-2xx for pipelined banner or EHLO */
 #endif
 #ifdef EXPERIMENTAL_PIPE_CONNECT
     case -4:                           /* non-2xx for pipelined banner or EHLO */
 #endif
+    case -1:                           /* Timeout on RCPT */
     default: return ERROR;             /* I/O error, or any MAIL/DATA error */
     }
   cmd_count = 1;
     default: return ERROR;             /* I/O error, or any MAIL/DATA error */
     }
   cmd_count = 1;
@@ -1931,6 +1957,9 @@ BOOL pass_message = FALSE;
 uschar * message = NULL;
 int yield = OK;
 int rc;
 uschar * message = NULL;
 int yield = OK;
 int rc;
+#ifdef SUPPORT_TLS
+uschar * tls_errstr;
+#endif
 
 sx->conn_args.ob = ob;
 
 
 sx->conn_args.ob = ob;
 
@@ -2471,27 +2500,27 @@ if (  smtp_peer_options & OPTION_TLS
   else
   TLS_NEGOTIATE:
     {
   else
   TLS_NEGOTIATE:
     {
-    uschar * errstr;
     sx->cctx.tls_ctx = tls_client_start(sx->cctx.sock, sx->conn_args.host,
                            sx->addrlist, sx->conn_args.tblock,
 # ifdef SUPPORT_DANE
                             sx->dane ? &tlsa_dnsa : NULL,
 # endif
     sx->cctx.tls_ctx = tls_client_start(sx->cctx.sock, sx->conn_args.host,
                            sx->addrlist, sx->conn_args.tblock,
 # ifdef SUPPORT_DANE
                             sx->dane ? &tlsa_dnsa : NULL,
 # endif
-                            &tls_out, &errstr);
+                            &tls_out, &tls_errstr);
 
     if (!sx->cctx.tls_ctx)
       {
       /* TLS negotiation failed; give an error. From outside, this function may
       be called again to try in clear on a new connection, if the options permit
       it for this host. */
 
     if (!sx->cctx.tls_ctx)
       {
       /* TLS negotiation failed; give an error. From outside, this function may
       be called again to try in clear on a new connection, if the options permit
       it for this host. */
-      DEBUG(D_tls) debug_printf("TLS session fail: %s\n", errstr);
+GNUTLS_CONN_FAILED:
+      DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr);
 
 # ifdef SUPPORT_DANE
       if (sx->dane)
         {
        log_write(0, LOG_MAIN,
          "DANE attempt failed; TLS connection to %s [%s]: %s",
 
 # ifdef SUPPORT_DANE
       if (sx->dane)
         {
        log_write(0, LOG_MAIN,
          "DANE attempt failed; TLS connection to %s [%s]: %s",
-         sx->conn_args.host->name, sx->conn_args.host->address, errstr);
+         sx->conn_args.host->name, sx->conn_args.host->address, tls_errstr);
 #  ifndef DISABLE_EVENT
        (void) event_raise(sx->conn_args.tblock->event_action,
          US"dane:fail", US"validation-failure");       /* could do with better detail */
 #  ifndef DISABLE_EVENT
        (void) event_raise(sx->conn_args.tblock->event_action,
          US"dane:fail", US"validation-failure");       /* could do with better detail */
@@ -2500,7 +2529,7 @@ if (  smtp_peer_options & OPTION_TLS
 # endif
 
       errno = ERRNO_TLSFAILURE;
 # endif
 
       errno = ERRNO_TLSFAILURE;
-      message = string_sprintf("TLS session: %s", errstr);
+      message = string_sprintf("TLS session: %s", tls_errstr);
       sx->send_quit = FALSE;
       goto TLS_FAILED;
       }
       sx->send_quit = FALSE;
       goto TLS_FAILED;
       }
@@ -2598,7 +2627,22 @@ if (tls_out.active.sock >= 0)
 #endif
     {
     if (!smtp_reap_ehlo(sx))
 #endif
     {
     if (!smtp_reap_ehlo(sx))
+#ifdef USE_GNUTLS
+      {
+      /* The GnuTLS layer in Exim only spots a server-rejection of a client
+      cert late, under TLS1.3 - which means here; the first time we try to
+      receive crypted data.  Treat it as if it was a connect-time failure.
+      See also the early-pipe equivalent... which will be hard; every call
+      to sync_responses will need to check the result.
+      It would be nicer to have GnuTLS check the cert during the handshake.
+      Can it do that, with all the flexibility we need? */
+
+      tls_errstr = US"error on first read";
+      goto GNUTLS_CONN_FAILED;
+      }
+#else
       goto RESPONSE_FAILED;
       goto RESPONSE_FAILED;
+#endif
     smtp_peer_options = 0;
     }
   }
     smtp_peer_options = 0;
     }
   }
@@ -3257,6 +3301,7 @@ for (addr = sx->first_addr, address_count = 0;
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
       case -4: return -1;                      /* non-2xx for pipelined banner or EHLO */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
       case -4: return -1;                      /* non-2xx for pipelined banner or EHLO */
+      case -5: return -1;                      /* TLS first-read error */
 #endif
       }
     sx->pending_MAIL = FALSE;            /* Dealt with MAIL */
 #endif
       }
     sx->pending_MAIL = FALSE;            /* Dealt with MAIL */
@@ -3582,11 +3627,12 @@ if (  !(sx.peer_offered & OPTION_CHUNKING)
 
     case 1: sx.ok = TRUE;            /* 2xx (only) => OK, but if LMTP, */
     if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */
 
     case 1: sx.ok = TRUE;            /* 2xx (only) => OK, but if LMTP, */
     if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */
-    case 0: break;                       /* No 2xx or 5xx, but no probs */
+    case 0: break;                     /* No 2xx or 5xx, but no probs */
 
 
-    case -1: goto END_OFF;               /* Timeout on RCPT */
+    case -1: goto END_OFF;             /* Timeout on RCPT */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
+    case -5:                           /* TLS first-read error */
     case -4:  HDEBUG(D_transport)
                debug_printf("failed reaping pipelined cmd responses\n");
 #endif
     case -4:  HDEBUG(D_transport)
                debug_printf("failed reaping pipelined cmd responses\n");
 #endif
@@ -3723,19 +3769,20 @@ else
       {
       case 3: sx.ok = TRUE;            /* 2xx & 5xx => OK & progress made */
       case 2: sx.completed_addr = TRUE;    /* 5xx (only) => progress made */
       {
       case 3: sx.ok = TRUE;            /* 2xx & 5xx => OK & progress made */
       case 2: sx.completed_addr = TRUE;    /* 5xx (only) => progress made */
-      break;
+             break;
 
 
-      case 1: sx.ok = TRUE;            /* 2xx (only) => OK, but if LMTP, */
+      case 1: sx.ok = TRUE;            /* 2xx (only) => OK, but if LMTP, */
       if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */
       if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */
-      case 0: break;                       /* No 2xx or 5xx, but no probs */
+      case 0: break;                   /* No 2xx or 5xx, but no probs */
 
 
-      case -1: goto END_OFF;               /* Timeout on RCPT */
+      case -1: goto END_OFF;           /* Timeout on RCPT */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
+      case -5:                         /* TLS first-read error */
       case -4:  HDEBUG(D_transport)
                  debug_printf("failed reaping pipelined cmd responses\n");
 #endif
       case -4:  HDEBUG(D_transport)
                  debug_printf("failed reaping pipelined cmd responses\n");
 #endif
-      default: goto RESPONSE_FAILED;       /* I/O error, or any MAIL/DATA error */
+      default: goto RESPONSE_FAILED;   /* I/O error, or any MAIL/DATA error */
       }
     }
 
       }
     }
 
index cc47218fb9ad98d89bd0377b361790bb49d8279d..c1b93a2ce052a80c715f80f67587b777b8866389 100644 (file)
@@ -47,9 +47,11 @@ local_delivery:
   user = CALLER
 
 send_to_server:
   user = CALLER
 
 send_to_server:
-  driver = smtp
+  driver =     smtp
   allow_localhost
   allow_localhost
-  hosts = ${if eq{$local_part}{userx}{127.0.0.1}{HOSTIPV4}}
-  port = PORT_D
+  hosts =      ${if eq{$local_part}{userx}{127.0.0.1}{HOSTIPV4}}
+  port =       PORT_D
+  tls_verify_certificates =    DIR/aux-fixed/cert1
+  tls_verify_cert_hostnames =  :
 
 # End
 
 # End
index 13c8d8617a80913c0f4c7e03de35003d01018a06..28d3a95bb8448a1e3b7de3f9fa0ca7d1c1cf7035 100644 (file)
@@ -29,6 +29,7 @@ tls_ocsp_file =   DRSA/server1.example.com/server1.example.com.ocsp.good.resp \
              : DECDSA/server1.example_ec.com/server1.example_ec.com.ocsp.good.resp
 
 
              : DECDSA/server1.example_ec.com/server1.example_ec.com.ocsp.good.resp
 
 
+tls_require_ciphers = NORMAL:!VERS-TLS1.3
 
 # ------ ACL ------
 
 
 # ------ ACL ------
 
index 86ddbdedd6d0e472dd741d0c78d47377e69170e0..8a2d6459eb492349b391394d5cff0cc55036a50f 100644 (file)
@@ -23,7 +23,7 @@ tls_certificate = ${if eq {SERVER}{server} {CDIR2/fullchain.pem}fail}
 tls_privatekey =  ${if eq {SERVER}{server} {CDIR2/server1.example.com.unlocked.key}fail}
 
 # Permit two specific ciphers
 tls_privatekey =  ${if eq {SERVER}{server} {CDIR2/server1.example.com.unlocked.key}fail}
 
 # Permit two specific ciphers
-tls_require_ciphers = NORMAL:-KX-ALL:+RSA:-CIPHER-ALL:+AES-128-CBC:+CAMELLIA-256-GCM
+tls_require_ciphers = NORMAL:-VERS-TLS1.3:-KX-ALL:+RSA:-CIPHER-ALL:+AES-128-CBC:+CAMELLIA-256-GCM
 
 # ----- Routers -----
 begin routers
 
 # ----- Routers -----
 begin routers
index 0bdd86a577c64af059ae9bb46bbe75648375baa1..499351cd0009c73262a513d18704feab50b777bf 100644 (file)
@@ -1,7 +1,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
-1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no C="250 OK id=10HmaZ-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes C="250 OK id=10HmaZ-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 TLS session: (gnutls_handshake): A TLS fatal alert has been received.: delivering unencrypted to H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
 1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbA-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 TLS session: (gnutls_handshake): A TLS fatal alert has been received.: delivering unencrypted to H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
 1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbA-0005vi-00"
index 77b701c0b4bf3354b58ff65ee9230d9ebebd20d0..7aaf1032da0630743d7d4cee8f5afd19a4c17180 100755 (executable)
@@ -553,7 +553,7 @@ RESET_AFTER_EXTRA_LINE_READ:
   # (discarding kex, cipher, mac).  For TLS 1.3 there is no kex
   # element (and no _WITH); insert a spurious "RSA".
 
   # (discarding kex, cipher, mac).  For TLS 1.3 there is no kex
   # element (and no _WITH); insert a spurious "RSA".
 
-  s/^\s+by .+ with .+ \K tls TLS_.*?([^_]+)_WITH.+$/(TLS1.x:ke-\1-AES256-SHAnnn:xxx)/;
+  s/^\s+by .+ with .+ \K tls TLS_.*?([^_]+)_WITH.+$/(TLS1.x:ke-$1-AES256-SHAnnn:xxx)/;
   s/^\s+by .+ with .+ \K tls TLS_.+$/(TLS1.x:ke-RSA-AES256-SHAnnn:xxx)/;
 
   # Test machines might have various different TLS library versions supporting
   s/^\s+by .+ with .+ \K tls TLS_.+$/(TLS1.x:ke-RSA-AES256-SHAnnn:xxx)/;
 
   # Test machines might have various different TLS library versions supporting
@@ -1263,6 +1263,20 @@ RESET_AFTER_EXTRA_LINE_READ:
     s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./;
     s/ARC: AMS signing: privkey PEM-block import: error:\K[0-9A-F]{8}:(PEM routines):get_name:(no start line)/0906D06C:$1:PEM_read_bio:$2/;
 
     s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./;
     s/ARC: AMS signing: privkey PEM-block import: error:\K[0-9A-F]{8}:(PEM routines):get_name:(no start line)/0906D06C:$1:PEM_read_bio:$2/;
 
+    # gnutls version variances
+    if (/TLS error on connection \(recv\): .* Decode error/)
+      {
+      my $prev = $_;
+      $_ = <IN>;
+      if (/error on first read/)
+       {
+       s/TLS session: \Kerror on first read:/(gnutls_handshake): A TLS fatal alert has been received.:/;
+       goto RESET_AFTER_EXTRA_LINE_READ;
+       }
+      else
+       { $_ = $prev; }
+      }
+
     # DKIM timestamps
     if ( /(DKIM: d=.*) t=([0-9]*) x=([0-9]*) / )
       {
     # DKIM timestamps
     if ( /(DKIM: d=.*) t=([0-9]*) x=([0-9]*) / )
       {
index 0d94ac4cd6837a4f31344de90a51d33433795f57..3e071b665d02c0159c2a93986fb4a2430553c779 100644 (file)
@@ -3,9 +3,11 @@ gnutls
 munge gnutls_handshake
 exim -DSERVER=server -bd -oX PORT_D
 ****
 munge gnutls_handshake
 exim -DSERVER=server -bd -oX PORT_D
 ****
+# will send to 127.0.0.1 and the server requests a client-cert
 exim userx@test.ex
 Test message
 ****
 exim userx@test.ex
 Test message
 ****
+# will send to HOSTIPV4 and the server requests&requires
 exim usery@test.ex
 Test message
 ****
 exim usery@test.ex
 Test message
 ****