int s2n_connection_set_config()

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;
}