/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2019 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Portions Copyright (c) The OpenSSL Project 1999 */
# endif
#endif
+#define TESTSUITE_TICKET_LIFE 10 /* seconds */
/*************************************************
* OpenSSL option parse *
*************************************************/
}
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
#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
{
#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
/* 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*/
) )
reexpand_tls_files_for_sni = TRUE;
- if (!expand_check(state->certificate, US"tls_certificate", &expanded, errstr))
+ if ( !expand_check(state->certificate, US"tls_certificate", &expanded, errstr)
+ || f.expand_string_forcedfail)
+ {
+ if (f.expand_string_forcedfail)
+ *errstr = US"expansion of tls_certificate failed";
return DEFER;
+ }
if (expanded)
if (state->is_server)
if ((err = tls_add_certfile(sctx, state, expanded, errstr)))
return err;
- if ( state->privatekey
- && !expand_check(state->privatekey, US"tls_privatekey", &expanded, errstr))
+ if ( state->privatekey
+ && !expand_check(state->privatekey, US"tls_privatekey", &expanded, errstr)
+ || f.expand_string_forcedfail)
+ {
+ if (f.expand_string_forcedfail)
+ *errstr = US"expansion of tls_privatekey failed";
return DEFER;
+ }
/* If expansion was forced to fail, key_expanded will be NULL. If the result
of the expansion is an empty string, ignore it also, and assume the private
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;
}
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;
}
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;
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
static int
-tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
+tls_servername_cb(SSL * s, int * ad ARG_UNUSED, void * arg)
{
-const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
-exim_openssl_state_st *state = (exim_openssl_state_st *) arg;
+const char * servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+exim_openssl_state_st * state = (exim_openssl_state_st *) arg;
int rc;
int old_pool = store_pool;
-uschar * dummy_errstr;
+uschar * errstr;
if (!servername)
return SSL_TLSEXT_ERR_OK;
not confident that memcpy wouldn't break some internal reference counting.
Especially since there's a references struct member, which would be off. */
-if (lib_ctx_new(&server_sni, NULL, &dummy_errstr) != OK)
+if (lib_ctx_new(&server_sni, NULL, &errstr) != OK)
goto bad;
/* Not sure how many of these are actually needed, since SSL object
SSL_CTX_set_tlsext_servername_arg(server_sni, state);
}
-if ( !init_dh(server_sni, state->dhparam, &dummy_errstr)
- || !init_ecdh(server_sni, &dummy_errstr)
+if ( !init_dh(server_sni, state->dhparam, &errstr)
+ || !init_ecdh(server_sni, &errstr)
)
goto bad;
{
uschar * v_certs = tls_verify_certificates;
if ((rc = setup_certs(server_sni, &v_certs, tls_crl, NULL,
- &dummy_errstr)) != OK)
+ &errstr)) != OK)
goto bad;
if (v_certs && *v_certs)
/* do this after setup_certs, because this can require the certs for verifying
OCSP information. */
-if ((rc = tls_expand_session_files(server_sni, state, &dummy_errstr)) != OK)
+if ((rc = tls_expand_session_files(server_sni, state, &errstr)) != OK)
goto bad;
DEBUG(D_tls) debug_printf("Switching SSL context.\n");
SSL_set_SSL_CTX(s, server_sni);
return SSL_TLSEXT_ERR_OK;
-bad: return SSL_TLSEXT_ERR_ALERT_FATAL;
+bad:
+ log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
#endif /* EXIM_HAVE_OPENSSL_TLSEXT */
DEBUG(D_tls) bp = BIO_new(BIO_s_mem());
/* Use the CA & chain that verified the server cert to verify the stapled info */
+ /*XXX could we do an event here, for observability of ocsp? What reasonable data could we give access to? */
+ /* Dates would be a start. Do we need another opaque variable type, as for certs, plus an extract expansion? */
{
/* If this routine is not available, we've avoided [in tls_client_start()]
#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;
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_state);
+ /* debug_printf("tls_exdata_idx %d cbinfo %p\n", tls_exdata_idx, client_static_state); */
}
tlsp->resumption = RESUME_SUPPORTED;