+ ob->tls_preload.x509_cred = NULL;
+ return;
+ }
+creds_basic_init(ob->tls_preload.x509_cred, FALSE);
+
+tpt_dummy_state.session = NULL;
+tpt_dummy_state.lib_state = ob->tls_preload;
+
+#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
+if ( opt_set_and_noexpand(ob->tls_certificate)
+ && opt_unset_or_noexpand(ob->tls_privatekey))
+ {
+ if ( !watch
+ || ( tls_set_watch(ob->tls_certificate, FALSE)
+ && tls_set_watch(ob->tls_privatekey, FALSE)
+ ) )
+ {
+ const uschar * pkey = ob->tls_privatekey;
+
+ DEBUG(D_tls)
+ debug_printf("TLS: preloading client certs for transport '%s'\n", t->name);
+
+ /* The state->lib_state.x509_cred is used for the certs load, and is the sole
+ structure element used. So we can set up a dummy. The hoat arg only
+ selects a retcode in case of fail, so any value */
+
+ if (creds_load_client_certs(&tpt_dummy_state, dummy_host,
+ ob->tls_certificate, pkey ? pkey : ob->tls_certificate,
+ &dummy_errstr) == OK)
+ ob->tls_preload.conn_certs = TRUE;
+ }
+ }
+else
+ DEBUG(D_tls)
+ debug_printf("TLS: not preloading client certs, for transport '%s'\n", t->name);
+
+if (opt_set_and_noexpand(ob->tls_verify_certificates))
+ {
+ if (!watch || tls_set_watch(ob->tls_verify_certificates, FALSE))
+ {
+ DEBUG(D_tls)
+ debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
+ if (creds_load_cabundle(&tpt_dummy_state, ob->tls_verify_certificates,
+ dummy_host, &dummy_errstr) != OK)
+ return;
+ ob->tls_preload.cabundle = TRUE;
+
+ if (opt_set_and_noexpand(ob->tls_crl))
+ {
+ if (!watch || tls_set_watch(ob->tls_crl, FALSE))
+ {
+ DEBUG(D_tls) debug_printf("TLS: preloading CRL for transport '%s'\n", t->name);
+ if (creds_load_crl(&tpt_dummy_state, ob->tls_crl, &dummy_errstr) != OK)
+ return;
+ ob->tls_preload.crl = TRUE;
+ }
+ }
+ else
+ DEBUG(D_tls) debug_printf("TLS: not preloading CRL, for transport '%s'\n", t->name);
+ }
+ }
+else
+ DEBUG(D_tls)
+ debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name);
+
+/* We do not preload tls_require_ciphers to to the transport as it implicitly
+depends on DANE or plain usage. */
+
+#endif
+}
+
+
+#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
+/* Invalidate the creds cached, by dropping the current ones.
+Call when we notice one of the source files has changed. */
+
+static void
+tls_server_creds_invalidate(void)
+{
+if (state_server.lib_state.pri_cache)
+ gnutls_priority_deinit(state_server.lib_state.pri_cache);
+state_server.lib_state.pri_cache = NULL;
+
+if (state_server.lib_state.x509_cred)
+ gnutls_certificate_free_credentials(state_server.lib_state.x509_cred);
+state_server.lib_state = null_tls_preload;
+}
+
+
+static void
+tls_client_creds_invalidate(transport_instance * t)
+{
+smtp_transport_options_block * ob = t->options_block;
+if (ob->tls_preload.x509_cred)
+ gnutls_certificate_free_credentials(ob->tls_preload.x509_cred);
+ob->tls_preload = null_tls_preload;
+}
+#endif
+
+
+/*************************************************
+* Variables re-expanded post-SNI *
+*************************************************/
+
+/* Called from both server and client code, via tls_init(), and also from
+the SNI callback after receiving an SNI, if tls_certificate includes "tls_sni".
+
+We can tell the two apart by state->received_sni being non-NULL in callback.
+
+The callback should not call us unless state->trigger_sni_changes is true,
+which we are responsible for setting on the first pass through.
+
+Arguments:
+ state exim_gnutls_state_st *
+ errstr error string pointer
+
+Returns: OK/DEFER/FAIL
+*/
+
+static int
+tls_expand_session_files(exim_gnutls_state_st * state, uschar ** errstr)
+{
+int rc;
+const host_item *host = state->host; /* macro should be reconsidered? */
+const uschar *saved_tls_certificate = NULL;
+const uschar *saved_tls_privatekey = NULL;
+const uschar *saved_tls_verify_certificates = NULL;
+const uschar *saved_tls_crl = NULL;
+int cert_count;
+
+/* We check for tls_sni *before* expansion. */
+if (!host) /* server */
+ if (!state->received_sni)
+ {
+ if ( state->tls_certificate
+ && ( Ustrstr(state->tls_certificate, US"tls_sni")
+ || Ustrstr(state->tls_certificate, US"tls_in_sni")
+ || Ustrstr(state->tls_certificate, US"tls_out_sni")
+ ) )
+ {
+ DEBUG(D_tls) debug_printf("We will re-expand TLS session files if we receive SNI\n");
+ state->trigger_sni_changes = TRUE;
+ }
+ }
+ else /* SNI callback case */