+/* remember: Expand_check_tlsvar() is expand_check() but fiddling with
+state members, assuming consistent naming; and expand_check() returns
+false if expansion failed, unless expansion was forced to fail. */
+
+/* check if we at least have a certificate, before doing expensive
+D-H generation. */
+
+if (!state->lib_state.conn_certs)
+ {
+ if ( !Expand_check_tlsvar(tls_certificate, errstr)
+ || f.expand_string_forcedfail)
+ {
+ if (f.expand_string_forcedfail)
+ *errstr = US"expansion of tls_certificate failed";
+ return DEFER;
+ }
+
+ /* certificate is mandatory in server, optional in client */
+
+ if ( !state->exp_tls_certificate
+ || !*state->exp_tls_certificate
+ )
+ if (!host)
+ return tls_install_selfsign(state, errstr);
+ else
+ DEBUG(D_tls) debug_printf("TLS: no client certificate specified; okay\n");
+
+ if ( state->tls_privatekey && !Expand_check_tlsvar(tls_privatekey, errstr)
+ || f.expand_string_forcedfail
+ )
+ {
+ if (f.expand_string_forcedfail)
+ *errstr = US"expansion of tls_privatekey failed";
+ return DEFER;
+ }
+
+ /* tls_privatekey is optional, defaulting to same file as certificate */
+
+ if (!state->tls_privatekey || !*state->tls_privatekey)
+ {
+ state->tls_privatekey = state->tls_certificate;
+ state->exp_tls_privatekey = state->exp_tls_certificate;
+ }
+
+ if (state->exp_tls_certificate && *state->exp_tls_certificate)
+ {
+ BOOL load = TRUE;
+ DEBUG(D_tls) debug_printf("certificate file = %s\nkey file = %s\n",
+ state->exp_tls_certificate, state->exp_tls_privatekey);
+
+ if (state->received_sni)
+ if ( Ustrcmp(state->exp_tls_certificate, saved_tls_certificate) == 0
+ && Ustrcmp(state->exp_tls_privatekey, saved_tls_privatekey) == 0
+ )
+ {
+ DEBUG(D_tls) debug_printf("TLS SNI: cert and key unchanged\n");
+ load = FALSE; /* avoid re-loading the same certs */
+ }
+ else /* unload the pre-SNI certs before loading new ones */
+ {
+ DEBUG(D_tls) debug_printf("TLS SNI: have a changed cert/key pair\n");
+ gnutls_certificate_free_keys(state->lib_state.x509_cred);
+ }
+
+ if ( load
+ && (rc = host
+ ? creds_load_client_certs(state, host, state->exp_tls_certificate,
+ state->exp_tls_privatekey, errstr)
+ : creds_load_server_certs(state, state->exp_tls_certificate,
+ state->exp_tls_privatekey,
+#ifdef DISABLE_OCSP
+ NULL,
+#else
+ tls_ocsp_file,
+#endif
+ errstr)
+ ) )
+ {
+ DEBUG(D_tls) debug_printf("load-cert: '%s'\n", *errstr);
+ return rc;
+ }
+ }
+ }
+else
+ {
+ DEBUG(D_tls)
+ debug_printf("%s certs were preloaded\n", host ? "client" : "server");
+
+ if (!state->tls_privatekey) state->tls_privatekey = state->tls_certificate;
+ state->exp_tls_certificate = US state->tls_certificate;
+ state->exp_tls_privatekey = US state->tls_privatekey;
+
+#ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
+ if (state->lib_state.ocsp_hook)
+ gnutls_handshake_set_hook_function(state->session,
+ GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, tls_server_hook_cb);
+#endif
+ }
+
+
+/* Set the trusted CAs file if one is provided, and then add the CRL if one is
+provided. Experiment shows that, if the certificate file is empty, an unhelpful
+error message is provided. However, if we just refrain from setting anything up
+in that case, certificate verification fails, which seems to be the correct
+behaviour.
+If none was configured and we can't handle "system", treat as empty. */
+
+if (!state->lib_state.cabundle)
+ {
+ if (state->tls_verify_certificates && *state->tls_verify_certificates)
+ {
+ if (!Expand_check_tlsvar(tls_verify_certificates, errstr))
+ return DEFER;
+#ifndef SUPPORT_SYSDEFAULT_CABUNDLE
+ if (Ustrcmp(state->exp_tls_verify_certificates, "system") == 0)
+ state->exp_tls_verify_certificates = NULL;
+#endif
+ if (state->tls_crl && *state->tls_crl)
+ if (!Expand_check_tlsvar(tls_crl, errstr))
+ return DEFER;
+
+ if (!(state->exp_tls_verify_certificates &&
+ *state->exp_tls_verify_certificates))
+ {
+ DEBUG(D_tls)
+ debug_printf("TLS: tls_verify_certificates expanded empty, ignoring\n");
+ /* With no tls_verify_certificates, we ignore tls_crl too */
+ return OK;
+ }
+ }
+ else
+ {
+ DEBUG(D_tls)
+ debug_printf("TLS: tls_verify_certificates not set or empty, ignoring\n");
+ return OK;
+ }
+ rc = creds_load_cabundle(state, state->exp_tls_verify_certificates, host, errstr);
+ if (rc != OK) return rc;
+ }
+else
+ {
+ DEBUG(D_tls)
+ debug_printf("%s CA bundle was preloaded\n", host ? "client" : "server");
+ state->exp_tls_verify_certificates = US state->tls_verify_certificates;
+
+#ifdef SUPPORT_CA_DIR
+/* Mimic the behaviour with OpenSSL of not advertising a usable-cert list
+when using the directory-of-certs config model. */
+ if (state->lib_state.ca_rdn_emulate)
+ gnutls_certificate_send_x509_rdn_sequence(state->session, 1);
+#endif
+ }
+
+
+if (!state->lib_state.crl)
+ {
+ if ( state->tls_crl && *state->tls_crl
+ && state->exp_tls_crl && *state->exp_tls_crl)
+ return creds_load_crl(state, state->exp_tls_crl, errstr);
+ }
+else
+ {
+ DEBUG(D_tls)
+ debug_printf("%s CRL was preloaded\n", host ? "client" : "server");
+ state->exp_tls_crl = US state->tls_crl;
+ }