OpenSSL: log conns rejected for bad ALPN, with the offered value
[exim.git] / src / src / tls-openssl.c
index 3b060cc9c695561637b7a439891df80034399ccb..513ba0d3a5c5b54f01c5fded80cc5b5bdbf2d12a 100644 (file)
@@ -155,6 +155,7 @@ change this guard and punt the issue for a while longer. */
 # endif
 #endif
 
+#define TESTSUITE_TICKET_LIFE 10       /* seconds */
 /*************************************************
 *        OpenSSL option parse                    *
 *************************************************/
@@ -675,12 +676,12 @@ if (dh_bitsize <= tls_dh_max_bits)
     }
   else
     DEBUG(D_tls)
-      debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
+      debug_printf(" Diffie-Hellman initialized from %s with %d-bit prime\n",
        dhexpanded ? dhexpanded : US"default", dh_bitsize);
   }
 else
   DEBUG(D_tls)
-    debug_printf("dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
+    debug_printf(" dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
        dhexpanded ? dhexpanded : US"default", dh_bitsize, tls_dh_max_bits);
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
@@ -730,19 +731,27 @@ return TRUE;
 #else
 
 uschar * exp_curve;
-int nid;
-BOOL rv;
+int nid, rc;
 
 # ifndef EXIM_HAVE_ECDH
 DEBUG(D_tls)
-  debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
+  debug_printf(" No OpenSSL API to define ECDH parameters, skipping\n");
 return TRUE;
 # else
 
 if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
   return FALSE;
+
+/* Is the option deliberately empty? */
+
 if (!exp_curve || !*exp_curve)
+  {
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+  DEBUG(D_tls) debug_printf( " ECDH OpenSSL 1.0.2+: clearing curves list\n");
+  (void) SSL_CTX_set1_curves(sctx, &nid, 0);
+#endif
   return TRUE;
+  }
 
 /* "auto" needs to be handled carefully.
  * OpenSSL <  1.0.2: we do not select anything, but fallback to prime256v1
@@ -755,31 +764,31 @@ if (Ustrcmp(exp_curve, "auto") == 0)
   {
 #if OPENSSL_VERSION_NUMBER < 0x10002000L
   DEBUG(D_tls) debug_printf(
-    "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
+    " ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
   exp_curve = US"prime256v1";
 #else
 # if defined SSL_CTRL_SET_ECDH_AUTO
   DEBUG(D_tls) debug_printf(
-    "ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
+    " ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
   SSL_CTX_set_ecdh_auto(sctx, 1);
   return TRUE;
 # else
   DEBUG(D_tls) debug_printf(
-    "ECDH OpenSSL 1.1.0+: temp key parameter settings: default selection\n");
+    " ECDH OpenSSL 1.1.0+: temp key parameter settings: library default selection\n");
   return TRUE;
 # endif
 #endif
   }
 
-DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
 if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
 #   ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID
    && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef
 #   endif
    )
   {
-  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
-    NULL, NULL, errstr);
+  uschar * s = string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve);
+  DEBUG(D_tls) debug_printf("TLS error '%s'\n", s);
+  if (errstr) *errstr = s;
   return FALSE;
   }
 
@@ -795,23 +804,23 @@ if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
   /* The "tmp" in the name here refers to setting a temporary key
   not to the stability of the interface. */
 
-  if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
+  if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh)) == 0)
     tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr);
   else
-    DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
+    DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve);
   EC_KEY_free(ecdh);
  }
 
 #else  /* v 3.0.0 + */
 
-if ((rv = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
+if ((rc = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
   tls_error(string_sprintf("Error enabling '%s' group", exp_curve), NULL, NULL, errstr);
 else
-  DEBUG(D_tls) debug_printf("ECDH: enabled '%s' group\n", exp_curve);
+  DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' group\n", exp_curve);
 
 #endif
 
-return !rv;
+return !!rc;
 
 # endif        /*EXIM_HAVE_ECDH*/
 #endif /*OPENSSL_NO_ECDH*/
@@ -1745,7 +1754,7 @@ state_server.lib_state.lib_ctx = ctx;
 
 if (opt_unset_or_noexpand(tls_dhparam))
   {
-  DEBUG(D_tls) debug_printf("TLS: preloading DH params for server\n");
+  DEBUG(D_tls) debug_printf("TLS: preloading DH params '%s' for server\n", tls_dhparam);
   if (init_dh(ctx, tls_dhparam, &dummy_errstr))
     state_server.lib_state.dh = TRUE;
   }
@@ -1753,7 +1762,7 @@ else
   DEBUG(D_tls) debug_printf("TLS: not preloading DH params for server\n");
 if (opt_unset_or_noexpand(tls_eccurve))
   {
-  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for server\n");
+  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve '%s' for server\n", tls_eccurve);
   if (init_ecdh(ctx, &dummy_errstr))
     state_server.lib_state.ecdh = TRUE;
   }
@@ -2044,7 +2053,7 @@ if (exim_tk.name[0])
   exim_tk_old = exim_tk;
   }
 
-if (f.running_in_test_harness) ssl_session_timeout = 6;
+if (f.running_in_test_harness) ssl_session_timeout = TESTSUITE_TICKET_LIFE;
 
 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;
@@ -2315,6 +2324,8 @@ static int
 tls_server_alpn_cb(SSL *ssl, const uschar ** out, uschar * outlen,
   const uschar * in, unsigned int inlen, void * arg)
 {
+gstring * g = NULL;
+
 server_seen_alpn = TRUE;
 DEBUG(D_tls)
   {
@@ -2345,12 +2356,19 @@ if (  inlen > 1         /* at least one name */
       }
   }
 
-/* More than one name from clilent, or name did not match our list. */
+/* More than one name from client, or name did not match our list. */
 
 /* This will be fatal to the TLS conn; would be nice to kill TCP also.
 Maybe as an option in future; for now leave control to the config (must-tls). */
 
-DEBUG(D_tls) debug_printf("TLS ALPN rejected\n");
+for (int pos = 0, siz; pos < inlen; pos += siz+1)
+  {
+  siz = in[pos];
+  if (pos + 1 + siz > inlen) siz = inlen - pos - 1;
+  g = string_append_listele_n(g, ':', in + pos + 1, siz);
+  }
+log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g));
+gstring_release_unused(g);
 return SSL_TLSEXT_ERR_ALERT_FATAL;
 }
 #endif /* EXIM_HAVE_ALPN */
@@ -3908,16 +3926,17 @@ if (tlsp->host_resumable)
 #ifdef EXIM_HAVE_SESSION_TICKET
          SSL_SESSION_get_ticket_lifetime_hint(ss);
 #else                  /* Use, fairly arbitrilarily, what we as server would */
-         f.running_in_test_harness ? 6 : ssl_session_timeout;
+         f.running_in_test_harness ? TESTSUITE_TICKET_LIFE : ssl_session_timeout;
 #endif
-       if (lifetime + dt->time_stamp < time(NULL))
+       time_t now = time(NULL), expires = lifetime + dt->time_stamp;
+       if (expires < now)
          {
-         DEBUG(D_tls) debug_printf("session expired\n");
+         DEBUG(D_tls) debug_printf("session expired (by " TIME_T_FMT "s from %lus)\n", now - expires, lifetime);
          dbfn_delete(dbm_file, tlsp->resume_index);
          }
        else if (SSL_set_session(ssl, ss))
          {
-         DEBUG(D_tls) debug_printf("good session\n");
+         DEBUG(D_tls) debug_printf("good session (" TIME_T_FMT "s left of %lus)\n", expires - now, lifetime);
          tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
          tlsp->verify_override = dt->verify_override;
          tlsp->ocsp = dt->ocsp;