in tls/s2n_connection.c [287:380]
int s2n_connection_set_config(struct s2n_connection *conn, struct s2n_config *config)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(config);
if (conn->config == config) {
return 0;
}
/* s2n_config invariant: any s2n_config is always in a state that respects the
* config->security_policy certificate preferences. Therefore we only need to
* validate certificates here if the connection is using a security policy override.
*/
const struct s2n_security_policy *security_policy_override = conn->security_policy_override;
if (security_policy_override) {
POSIX_GUARD_RESULT(s2n_config_validate_loaded_certificates(config, security_policy_override));
}
/* We only support one client certificate */
if (s2n_config_get_num_default_certs(config) > 1 && conn->mode == S2N_CLIENT) {
POSIX_BAIL(S2N_ERR_TOO_MANY_CERTIFICATES);
}
s2n_x509_validator_wipe(&conn->x509_validator);
if (config->disable_x509_validation) {
POSIX_GUARD(s2n_x509_validator_init_no_x509_validation(&conn->x509_validator));
} else {
POSIX_GUARD(s2n_x509_validator_init(&conn->x509_validator, &config->trust_store, config->check_ocsp));
if (!conn->verify_host_fn_overridden) {
if (config->verify_host_fn != NULL) {
conn->verify_host_fn = config->verify_host_fn;
conn->data_for_verify_host = config->data_for_verify_host;
} else {
conn->verify_host_fn = s2n_default_verify_host;
conn->data_for_verify_host = conn;
}
}
if (config->max_verify_cert_chain_depth_set) {
POSIX_GUARD(s2n_x509_validator_set_max_chain_depth(&conn->x509_validator, config->max_verify_cert_chain_depth));
}
}
conn->tickets_to_send = config->initial_tickets_to_send;
if (conn->psk_params.psk_list.len == 0 && !conn->psk_mode_overridden) {
POSIX_GUARD(s2n_connection_set_psk_mode(conn, config->psk_mode));
conn->psk_mode_overridden = false;
}
/* If at least one certificate does not have a private key configured,
* the config must provide an async pkey callback.
* The handshake could still fail if the callback doesn't offload the
* signature, but this at least catches configuration mistakes.
*/
if (config->no_signing_key) {
POSIX_ENSURE(config->async_pkey_cb, S2N_ERR_NO_PRIVATE_KEY);
}
if (config->quic_enabled) {
/* If QUIC is ever enabled for a connection via the config,
* we should enforce that it can never be disabled by
* changing the config.
*
* Enabling QUIC indicates that the connection is being used by
* a QUIC implementation, which never changes. Disabling QUIC
* partially through a connection could also potentially be
* dangerous, as QUIC handles encryption.
*/
POSIX_GUARD(s2n_connection_enable_quic(conn));
}
if (config->send_buffer_size_override) {
conn->multirecord_send = true;
}
/* Historically, calling s2n_config_set_verification_ca_location enabled OCSP stapling
* regardless of the value set by an application calling s2n_config_set_status_request_type.
* We maintain this behavior for backwards compatibility.
*
* However, the s2n_config_set_verification_ca_location behavior predates client authentication
* support for OCSP stapling, so could only affect whether clients requested OCSP stapling. We
* therefore only have to maintain the legacy behavior for clients, not servers.
*
* Note: The Rust bindings do not maintain the legacy behavior.
*/
conn->request_ocsp_status = config->ocsp_status_requested_by_user;
if (config->ocsp_status_requested_by_s2n && conn->mode == S2N_CLIENT) {
conn->request_ocsp_status = true;
}
conn->config = config;
return S2N_SUCCESS;
}