godot/thirdparty/mbedtls/library/ssl_tls12_client.c

/*
 *  TLS client-side functions
 *
 *  Copyright The Mbed TLS Contributors
 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 */

#include "common.h"

#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_2)

#include "mbedtls/platform.h"

#include "mbedtls/ssl.h"
#include "ssl_client.h"
#include "ssl_misc.h"
#include "debug_internal.h"
#include "mbedtls/error.h"
#include "mbedtls/constant_time.h"

#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include "psa_util_internal.h"
#include "psa/crypto.h"
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
/* Define a local translating function to save code size by not using too many
 * arguments in each translating place. */
static int local_err_translation(psa_status_t status)
{
    return psa_status_to_mbedtls(status, psa_to_ssl_errors,
                                 ARRAY_LENGTH(psa_to_ssl_errors),
                                 psa_generic_status_to_mbedtls);
}
#define PSA_TO_MBEDTLS_ERR
#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
#endif /* MBEDTLS_USE_PSA_CRYPTO */

#include <string.h>

#include <stdint.h>

#if defined(MBEDTLS_HAVE_TIME)
#include "mbedtls/platform_time.h"
#endif

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
#include "mbedtls/platform_util.h"
#endif

#if defined(MBEDTLS_SSL_RENEGOTIATION)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_renegotiation_ext(mbedtls_ssl_context *ssl,
                                       unsigned char *buf,
                                       const unsigned char *end,
                                       size_t *olen)
{}
#endif /* MBEDTLS_SSL_RENEGOTIATION */

#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_1_2_ENABLED) || \
    defined(MBEDTLS_KEY_EXCHANGE_ECDSA_CERT_REQ_ALLOWED_ENABLED) || \
    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)

MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_supported_point_formats_ext(mbedtls_ssl_context *ssl,
                                                 unsigned char *buf,
                                                 const unsigned char *end,
                                                 size_t *olen)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_1_2_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_ECDSA_CERT_REQ_ALLOWED_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */

#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl,
                                      unsigned char *buf,
                                      const unsigned char *end,
                                      size_t *olen)
{
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    unsigned char *p = buf;
    size_t kkpp_len = 0;

    *olen = 0;

    /* Skip costly extension if we can't use EC J-PAKE anyway */
#if defined(MBEDTLS_USE_PSA_CRYPTO)
    if (ssl->handshake->psa_pake_ctx_is_ok != 1) {
        return 0;
    }
#else
    if (mbedtls_ecjpake_check(&ssl->handshake->ecjpake_ctx) != 0) {
        return 0;
    }
#endif /* MBEDTLS_USE_PSA_CRYPTO */

    MBEDTLS_SSL_DEBUG_MSG(3,
                          ("client hello, adding ecjpake_kkpp extension"));

    MBEDTLS_SSL_CHK_BUF_PTR(p, end, 4);

    MBEDTLS_PUT_UINT16_BE(MBEDTLS_TLS_EXT_ECJPAKE_KKPP, p, 0);
    p += 2;

    /*
     * We may need to send ClientHello multiple times for Hello verification.
     * We don't want to compute fresh values every time (both for performance
     * and consistency reasons), so cache the extension content.
     */
    if (ssl->handshake->ecjpake_cache == NULL ||
        ssl->handshake->ecjpake_cache_len == 0) {
        MBEDTLS_SSL_DEBUG_MSG(3, ("generating new ecjpake parameters"));

#if defined(MBEDTLS_USE_PSA_CRYPTO)
        ret = mbedtls_psa_ecjpake_write_round(&ssl->handshake->psa_pake_ctx,
                                              p + 2, end - p - 2, &kkpp_len,
                                              MBEDTLS_ECJPAKE_ROUND_ONE);
        if (ret != 0) {
            psa_destroy_key(ssl->handshake->psa_pake_password);
            psa_pake_abort(&ssl->handshake->psa_pake_ctx);
            MBEDTLS_SSL_DEBUG_RET(1, "psa_pake_output", ret);
            return ret;
        }
#else
        ret = mbedtls_ecjpake_write_round_one(&ssl->handshake->ecjpake_ctx,
                                              p + 2, end - p - 2, &kkpp_len,
                                              ssl->conf->f_rng, ssl->conf->p_rng);
        if (ret != 0) {
            MBEDTLS_SSL_DEBUG_RET(1,
                                  "mbedtls_ecjpake_write_round_one", ret);
            return ret;
        }
#endif /* MBEDTLS_USE_PSA_CRYPTO */

        ssl->handshake->ecjpake_cache = mbedtls_calloc(1, kkpp_len);
        if (ssl->handshake->ecjpake_cache == NULL) {
            MBEDTLS_SSL_DEBUG_MSG(1, ("allocation failed"));
            return MBEDTLS_ERR_SSL_ALLOC_FAILED;
        }

        memcpy(ssl->handshake->ecjpake_cache, p + 2, kkpp_len);
        ssl->handshake->ecjpake_cache_len = kkpp_len;
    } else {
        MBEDTLS_SSL_DEBUG_MSG(3, ("re-using cached ecjpake parameters"));

        kkpp_len = ssl->handshake->ecjpake_cache_len;
        MBEDTLS_SSL_CHK_BUF_PTR(p + 2, end, kkpp_len);

        memcpy(p + 2, ssl->handshake->ecjpake_cache, kkpp_len);
    }

    MBEDTLS_PUT_UINT16_BE(kkpp_len, p, 0);
    p += 2;

    *olen = kkpp_len + 4;

    return 0;
}
#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */

#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_cid_ext(mbedtls_ssl_context *ssl,
                             unsigned char *buf,
                             const unsigned char *end,
                             size_t *olen)
{}
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */

#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_max_fragment_length_ext(mbedtls_ssl_context *ssl,
                                             unsigned char *buf,
                                             const unsigned char *end,
                                             size_t *olen)
{}
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */

#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_encrypt_then_mac_ext(mbedtls_ssl_context *ssl,
                                          unsigned char *buf,
                                          const unsigned char *end,
                                          size_t *olen)
{}
#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */

#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_extended_ms_ext(mbedtls_ssl_context *ssl,
                                     unsigned char *buf,
                                     const unsigned char *end,
                                     size_t *olen)
{}
#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_session_ticket_ext(mbedtls_ssl_context *ssl,
                                        unsigned char *buf,
                                        const unsigned char *end,
                                        size_t *olen)
{}
#endif /* MBEDTLS_SSL_SESSION_TICKETS */

#if defined(MBEDTLS_SSL_DTLS_SRTP)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_use_srtp_ext(mbedtls_ssl_context *ssl,
                                  unsigned char *buf,
                                  const unsigned char *end,
                                  size_t *olen)
{
    unsigned char *p = buf;
    size_t protection_profiles_index = 0, ext_len = 0;
    uint16_t mki_len = 0, profile_value = 0;

    *olen = 0;

    if ((ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM) ||
        (ssl->conf->dtls_srtp_profile_list == NULL) ||
        (ssl->conf->dtls_srtp_profile_list_len == 0)) {
        return 0;
    }

    /* RFC 5764 section 4.1.1
     * uint8 SRTPProtectionProfile[2];
     *
     * struct {
     *   SRTPProtectionProfiles SRTPProtectionProfiles;
     *   opaque srtp_mki<0..255>;
     * } UseSRTPData;
     * SRTPProtectionProfile SRTPProtectionProfiles<2..2^16-1>;
     */
    if (ssl->conf->dtls_srtp_mki_support == MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED) {
        mki_len = ssl->dtls_srtp_info.mki_len;
    }
    /* Extension length = 2 bytes for profiles length,
     *                    ssl->conf->dtls_srtp_profile_list_len * 2 (each profile is 2 bytes length ),
     *                    1 byte for srtp_mki vector length and the mki_len value
     */
    ext_len = 2 + 2 * (ssl->conf->dtls_srtp_profile_list_len) + 1 + mki_len;

    MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, adding use_srtp extension"));

    /* Check there is room in the buffer for the extension + 4 bytes
     * - the extension tag (2 bytes)
     * - the extension length (2 bytes)
     */
    MBEDTLS_SSL_CHK_BUF_PTR(p, end, ext_len + 4);

    MBEDTLS_PUT_UINT16_BE(MBEDTLS_TLS_EXT_USE_SRTP, p, 0);
    p += 2;

    MBEDTLS_PUT_UINT16_BE(ext_len, p, 0);
    p += 2;

    /* protection profile length: 2*(ssl->conf->dtls_srtp_profile_list_len) */
    /* micro-optimization:
     * the list size is limited to MBEDTLS_TLS_SRTP_MAX_PROFILE_LIST_LENGTH
     * which is lower than 127, so the upper byte of the length is always 0
     * For the documentation, the more generic code is left in comments
     * *p++ = (unsigned char)( ( ( 2 * ssl->conf->dtls_srtp_profile_list_len )
     *                        >> 8 ) & 0xFF );
     */
    *p++ = 0;
    *p++ = MBEDTLS_BYTE_0(2 * ssl->conf->dtls_srtp_profile_list_len);

    for (protection_profiles_index = 0;
         protection_profiles_index < ssl->conf->dtls_srtp_profile_list_len;
         protection_profiles_index++) {
        profile_value = mbedtls_ssl_check_srtp_profile_value
                            (ssl->conf->dtls_srtp_profile_list[protection_profiles_index]);
        if (profile_value != MBEDTLS_TLS_SRTP_UNSET) {
            MBEDTLS_SSL_DEBUG_MSG(3, ("ssl_write_use_srtp_ext, add profile: %04x",
                                      profile_value));
            MBEDTLS_PUT_UINT16_BE(profile_value, p, 0);
            p += 2;
        } else {
            /*
             * Note: we shall never arrive here as protection profiles
             * is checked by mbedtls_ssl_conf_dtls_srtp_protection_profiles function
             */
            MBEDTLS_SSL_DEBUG_MSG(3,
                                  ("client hello, "
                                   "illegal DTLS-SRTP protection profile %d",
                                   ssl->conf->dtls_srtp_profile_list[protection_profiles_index]
                                  ));
            return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
        }
    }

    *p++ = mki_len & 0xFF;

    if (mki_len != 0) {
        memcpy(p, ssl->dtls_srtp_info.mki_value, mki_len);
        /*
         * Increment p to point to the current position.
         */
        p += mki_len;
        MBEDTLS_SSL_DEBUG_BUF(3, "sending mki",  ssl->dtls_srtp_info.mki_value,
                              ssl->dtls_srtp_info.mki_len);
    }

    /*
     * total extension length: extension type (2 bytes)
     *                         + extension length (2 bytes)
     *                         + protection profile length (2 bytes)
     *                         + 2 * number of protection profiles
     *                         + srtp_mki vector length(1 byte)
     *                         + mki value
     */
    *olen = p - buf;

    return 0;
}
#endif /* MBEDTLS_SSL_DTLS_SRTP */

int mbedtls_ssl_tls12_write_client_hello_exts(mbedtls_ssl_context *ssl,
                                              unsigned char *buf,
                                              const unsigned char *end,
                                              int uses_ec,
                                              size_t *out_len)
{}

MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_renegotiation_info(mbedtls_ssl_context *ssl,
                                        const unsigned char *buf,
                                        size_t len)
{}

#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_max_fragment_length_ext(mbedtls_ssl_context *ssl,
                                             const unsigned char *buf,
                                             size_t len)
{}
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */

#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_cid_ext(mbedtls_ssl_context *ssl,
                             const unsigned char *buf,
                             size_t len)
{}
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */

#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_encrypt_then_mac_ext(mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len)
{}
#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */

#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_extended_ms_ext(mbedtls_ssl_context *ssl,
                                     const unsigned char *buf,
                                     size_t len)
{}
#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_session_ticket_ext(mbedtls_ssl_context *ssl,
                                        const unsigned char *buf,
                                        size_t len)
{}
#endif /* MBEDTLS_SSL_SESSION_TICKETS */

#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_1_2_ENABLED) || \
    defined(MBEDTLS_KEY_EXCHANGE_ECDSA_CERT_REQ_ALLOWED_ENABLED) || \
    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_supported_point_formats_ext(mbedtls_ssl_context *ssl,
                                                 const unsigned char *buf,
                                                 size_t len)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_1_2_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_ECDSA_CERT_REQ_ALLOWED_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */

#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_ecjpake_kkpp(mbedtls_ssl_context *ssl,
                                  const unsigned char *buf,
                                  size_t len)
{
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

    if (ssl->handshake->ciphersuite_info->key_exchange !=
        MBEDTLS_KEY_EXCHANGE_ECJPAKE) {
        MBEDTLS_SSL_DEBUG_MSG(3, ("skip ecjpake kkpp extension"));
        return 0;
    }

    /* If we got here, we no longer need our cached extension */
    mbedtls_free(ssl->handshake->ecjpake_cache);
    ssl->handshake->ecjpake_cache = NULL;
    ssl->handshake->ecjpake_cache_len = 0;

#if defined(MBEDTLS_USE_PSA_CRYPTO)
    if ((ret = mbedtls_psa_ecjpake_read_round(
             &ssl->handshake->psa_pake_ctx, buf, len,
             MBEDTLS_ECJPAKE_ROUND_ONE)) != 0) {
        psa_destroy_key(ssl->handshake->psa_pake_password);
        psa_pake_abort(&ssl->handshake->psa_pake_ctx);

        MBEDTLS_SSL_DEBUG_RET(1, "psa_pake_input round one", ret);
        mbedtls_ssl_send_alert_message(
            ssl,
            MBEDTLS_SSL_ALERT_LEVEL_FATAL,
            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
        return ret;
    }

    return 0;
#else
    if ((ret = mbedtls_ecjpake_read_round_one(&ssl->handshake->ecjpake_ctx,
                                              buf, len)) != 0) {
        MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ecjpake_read_round_one", ret);
        mbedtls_ssl_send_alert_message(
            ssl,
            MBEDTLS_SSL_ALERT_LEVEL_FATAL,
            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
        return ret;
    }

    return 0;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
}
#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */

#if defined(MBEDTLS_SSL_ALPN)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_alpn_ext(mbedtls_ssl_context *ssl,
                              const unsigned char *buf, size_t len)
{}
#endif /* MBEDTLS_SSL_ALPN */

#if defined(MBEDTLS_SSL_DTLS_SRTP)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_use_srtp_ext(mbedtls_ssl_context *ssl,
                                  const unsigned char *buf,
                                  size_t len)
{
    mbedtls_ssl_srtp_profile server_protection = MBEDTLS_TLS_SRTP_UNSET;
    size_t i, mki_len = 0;
    uint16_t server_protection_profile_value = 0;

    /* If use_srtp is not configured, just ignore the extension */
    if ((ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM) ||
        (ssl->conf->dtls_srtp_profile_list == NULL) ||
        (ssl->conf->dtls_srtp_profile_list_len == 0)) {
        return 0;
    }

    /* RFC 5764 section 4.1.1
     * uint8 SRTPProtectionProfile[2];
     *
     * struct {
     *   SRTPProtectionProfiles SRTPProtectionProfiles;
     *   opaque srtp_mki<0..255>;
     * } UseSRTPData;

     * SRTPProtectionProfile SRTPProtectionProfiles<2..2^16-1>;
     *
     */
    if (ssl->conf->dtls_srtp_mki_support == MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED) {
        mki_len = ssl->dtls_srtp_info.mki_len;
    }

    /*
     * Length is 5 + optional mki_value : one protection profile length (2 bytes)
     *                                      + protection profile (2 bytes)
     *                                      + mki_len(1 byte)
     *                                      and optional srtp_mki
     */
    if ((len < 5) || (len != (buf[4] + 5u))) {
        return MBEDTLS_ERR_SSL_DECODE_ERROR;
    }

    /*
     * get the server protection profile
     */

    /*
     * protection profile length must be 0x0002 as we must have only
     * one protection profile in server Hello
     */
    if ((buf[0] != 0) || (buf[1] != 2)) {
        return MBEDTLS_ERR_SSL_DECODE_ERROR;
    }

    server_protection_profile_value = (buf[2] << 8) | buf[3];
    server_protection = mbedtls_ssl_check_srtp_profile_value(
        server_protection_profile_value);
    if (server_protection != MBEDTLS_TLS_SRTP_UNSET) {
        MBEDTLS_SSL_DEBUG_MSG(3, ("found srtp profile: %s",
                                  mbedtls_ssl_get_srtp_profile_as_string(
                                      server_protection)));
    }

    ssl->dtls_srtp_info.chosen_dtls_srtp_profile = MBEDTLS_TLS_SRTP_UNSET;

    /*
     * Check we have the server profile in our list
     */
    for (i = 0; i < ssl->conf->dtls_srtp_profile_list_len; i++) {
        if (server_protection == ssl->conf->dtls_srtp_profile_list[i]) {
            ssl->dtls_srtp_info.chosen_dtls_srtp_profile = ssl->conf->dtls_srtp_profile_list[i];
            MBEDTLS_SSL_DEBUG_MSG(3, ("selected srtp profile: %s",
                                      mbedtls_ssl_get_srtp_profile_as_string(
                                          server_protection)));
            break;
        }
    }

    /* If no match was found : server problem, it shall never answer with incompatible profile */
    if (ssl->dtls_srtp_info.chosen_dtls_srtp_profile == MBEDTLS_TLS_SRTP_UNSET) {
        mbedtls_ssl_send_alert_message(ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
                                       MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
    }

    /* If server does not use mki in its reply, make sure the client won't keep
     * one as negotiated */
    if (len == 5) {
        ssl->dtls_srtp_info.mki_len = 0;
    }

    /*
     * RFC5764:
     *  If the client detects a nonzero-length MKI in the server's response
     *  that is different than the one the client offered, then the client
     *  MUST abort the handshake and SHOULD send an invalid_parameter alert.
     */
    if (len > 5  && (buf[4] != mki_len ||
                     (memcmp(ssl->dtls_srtp_info.mki_value, &buf[5], mki_len)))) {
        mbedtls_ssl_send_alert_message(ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
                                       MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER);
        return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
    }
#if defined(MBEDTLS_DEBUG_C)
    if (len > 5) {
        MBEDTLS_SSL_DEBUG_BUF(3, "received mki", ssl->dtls_srtp_info.mki_value,
                              ssl->dtls_srtp_info.mki_len);
    }
#endif
    return 0;
}
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/*
 * Parse HelloVerifyRequest.  Only called after verifying the HS type.
 */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_hello_verify_request(mbedtls_ssl_context *ssl)
{}
#endif /* MBEDTLS_SSL_PROTO_DTLS */

MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_hello(mbedtls_ssl_context *ssl)
{}

#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) ||                       \
    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_dh_params(mbedtls_ssl_context *ssl,
                                      unsigned char **p,
                                      unsigned char *end)
{
    int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
    size_t dhm_actual_bitlen;

    /*
     * Ephemeral DH parameters:
     *
     * struct {
     *     opaque dh_p<1..2^16-1>;
     *     opaque dh_g<1..2^16-1>;
     *     opaque dh_Ys<1..2^16-1>;
     * } ServerDHParams;
     */
    if ((ret = mbedtls_dhm_read_params(&ssl->handshake->dhm_ctx,
                                       p, end)) != 0) {
        MBEDTLS_SSL_DEBUG_RET(2, ("mbedtls_dhm_read_params"), ret);
        return ret;
    }

    dhm_actual_bitlen = mbedtls_dhm_get_bitlen(&ssl->handshake->dhm_ctx);
    if (dhm_actual_bitlen < ssl->conf->dhm_min_bitlen) {
        MBEDTLS_SSL_DEBUG_MSG(1, ("DHM prime too short: %" MBEDTLS_PRINTF_SIZET " < %u",
                                  dhm_actual_bitlen,
                                  ssl->conf->dhm_min_bitlen));
        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
    }

    MBEDTLS_SSL_DEBUG_MPI(3, "DHM: P ", &ssl->handshake->dhm_ctx.P);
    MBEDTLS_SSL_DEBUG_MPI(3, "DHM: G ", &ssl->handshake->dhm_ctx.G);
    MBEDTLS_SSL_DEBUG_MPI(3, "DHM: GY", &ssl->handshake->dhm_ctx.GY);

    return ret;
}
#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */

#if defined(MBEDTLS_USE_PSA_CRYPTO)
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)   ||   \
    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)   ||   \
    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_ecdh_params(mbedtls_ssl_context *ssl,
                                        unsigned char **p,
                                        unsigned char *end)
{
    uint16_t tls_id;
    size_t ecpoint_len;
    mbedtls_ssl_handshake_params *handshake = ssl->handshake;
    psa_key_type_t key_type = PSA_KEY_TYPE_NONE;
    size_t ec_bits = 0;

    /*
     * struct {
     *     ECParameters curve_params;
     *     ECPoint      public;
     * } ServerECDHParams;
     *
     *  1       curve_type (must be "named_curve")
     *  2..3    NamedCurve
     *  4       ECPoint.len
     *  5+      ECPoint contents
     */
    if (end - *p < 4) {
        return MBEDTLS_ERR_SSL_DECODE_ERROR;
    }

    /* First byte is curve_type; only named_curve is handled */
    if (*(*p)++ != MBEDTLS_ECP_TLS_NAMED_CURVE) {
        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
    }

    /* Next two bytes are the namedcurve value */
    tls_id = MBEDTLS_GET_UINT16_BE(*p, 0);
    *p += 2;

    /* Check it's a curve we offered */
    if (mbedtls_ssl_check_curve_tls_id(ssl, tls_id) != 0) {
        MBEDTLS_SSL_DEBUG_MSG(2,
                              ("bad server key exchange message (ECDHE curve): %u",
                               (unsigned) tls_id));
        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
    }

    /* Convert EC's TLS ID to PSA key type. */
    if (mbedtls_ssl_get_psa_curve_info_from_tls_id(tls_id, &key_type,
                                                   &ec_bits) == PSA_ERROR_NOT_SUPPORTED) {
        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
    }
    handshake->xxdh_psa_type = key_type;
    handshake->xxdh_psa_bits = ec_bits;

    /* Keep a copy of the peer's public key */
    ecpoint_len = *(*p)++;
    if ((size_t) (end - *p) < ecpoint_len) {
        return MBEDTLS_ERR_SSL_DECODE_ERROR;
    }

    if (ecpoint_len > sizeof(handshake->xxdh_psa_peerkey)) {
        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
    }

    memcpy(handshake->xxdh_psa_peerkey, *p, ecpoint_len);
    handshake->xxdh_psa_peerkey_len = ecpoint_len;
    *p += ecpoint_len;

    return 0;
}
#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED   ||
          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED   ||
          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
#else
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)   ||   \
    defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)    ||   \
    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)   ||   \
    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||   \
    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_check_server_ecdh_params(const mbedtls_ssl_context *ssl)
{}

#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED   ||
          MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED    ||
          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED   ||
          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */

#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ||     \
    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_ecdh_params(mbedtls_ssl_context *ssl,
                                        unsigned char **p,
                                        unsigned char *end)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || \
          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \
          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
#endif /* !MBEDTLS_USE_PSA_CRYPTO */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_psk_hint(mbedtls_ssl_context *ssl,
                                     unsigned char **p,
                                     unsigned char *end)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */

#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) ||                           \
    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
/*
 * Generate a pre-master secret and encrypt it with the server's RSA key
 */
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_encrypted_pms(mbedtls_ssl_context *ssl,
                                   size_t offset, size_t *olen,
                                   size_t pms_offset)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED ||
          MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */

#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_get_ecdh_params_from_cert(mbedtls_ssl_context *ssl)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
          MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */

MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_key_exchange(mbedtls_ssl_context *ssl)
{}

#if !defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_certificate_request(mbedtls_ssl_context *ssl)
{
    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
        ssl->handshake->ciphersuite_info;

    MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse certificate request"));

    if (!mbedtls_ssl_ciphersuite_cert_req_allowed(ciphersuite_info)) {
        MBEDTLS_SSL_DEBUG_MSG(2, ("<= skip parse certificate request"));
        ssl->state++;
        return 0;
    }

    MBEDTLS_SSL_DEBUG_MSG(1, ("should never happen"));
    return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
#else /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_certificate_request(mbedtls_ssl_context *ssl)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */

MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_server_hello_done(mbedtls_ssl_context *ssl)
{}

MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl)
{}

#if !defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_certificate_verify(mbedtls_ssl_context *ssl)
{
    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
        ssl->handshake->ciphersuite_info;
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

    MBEDTLS_SSL_DEBUG_MSG(2, ("=> write certificate verify"));

    if ((ret = mbedtls_ssl_derive_keys(ssl)) != 0) {
        MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_derive_keys", ret);
        return ret;
    }

    if (!mbedtls_ssl_ciphersuite_cert_req_allowed(ciphersuite_info)) {
        MBEDTLS_SSL_DEBUG_MSG(2, ("<= skip write certificate verify"));
        ssl->state++;
        return 0;
    }

    MBEDTLS_SSL_DEBUG_MSG(1, ("should never happen"));
    return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
#else /* !MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_write_certificate_verify(mbedtls_ssl_context *ssl)
{}
#endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_parse_new_session_ticket(mbedtls_ssl_context *ssl)
{}
#endif /* MBEDTLS_SSL_SESSION_TICKETS */

/*
 * SSL handshake -- client side -- single step
 */
int mbedtls_ssl_handshake_client_step(mbedtls_ssl_context *ssl)
{}

#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_TLS1_2 */