From aa5f5c1f5d1256955a690f04613e03683467a875 Mon Sep 17 00:00:00 2001 From: XiaokangQian Date: Sat, 18 Sep 2021 06:20:25 +0000 Subject: [PATCH] TLS1.3: Add server finish processing in client side Signed-off-by: XiaokangQian --- include/mbedtls/ssl.h | 12 ++- library/ssl_misc.h | 103 +++++++++++++++++++ library/ssl_tls13_generic.c | 153 ++++++++++++++++++++++++++++ library/ssl_tls13_keys.c | 194 ++++++++++++++++++++++++++++++++++++ library/ssl_tls13_keys.h | 61 ++++++++++++ 5 files changed, 522 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 5d04a115fa..3e10181253 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -39,7 +39,6 @@ #if defined(MBEDTLS_DHM_C) #include "mbedtls/dhm.h" #endif - /* Adding guard for MBEDTLS_ECDSA_C to ensure no compile errors due * to guards also being in ssl_srv.c and ssl_cli.c. There is a gap * in functionality that access to ecdh_ctx structure is needed for @@ -637,6 +636,7 @@ typedef enum MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_SSL_END_OF_EARLY_DATA, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY, #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ @@ -1050,6 +1050,14 @@ typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +typedef struct +{ + unsigned char client_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char server_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char exporter_master_secret [ MBEDTLS_MD_MAX_SIZE ]; + unsigned char resumption_master_secret [ MBEDTLS_MD_MAX_SIZE ]; +} mbedtls_ssl_tls1_3_application_secrets; + #if defined(MBEDTLS_SSL_DTLS_SRTP) #define MBEDTLS_TLS_SRTP_MAX_MKI_LENGTH 255 @@ -1114,6 +1122,8 @@ struct mbedtls_ssl_session * to be studied whether one of them can be removed. */ unsigned char MBEDTLS_PRIVATE(minor_ver); /*!< The TLS version used in the session. */ + mbedtls_ssl_tls1_3_application_secrets MBEDTLS_PRIVATE(app_secrets); + #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) mbedtls_x509_crt *MBEDTLS_PRIVATE(peer_cert); /*!< peer X.509 cert chain */ diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 23d5970d91..ae6cbfab5b 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -719,6 +719,104 @@ struct mbedtls_ssl_handshake_params * but can be overwritten by the HRR. */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* + * State-local variables used during the processing + * of a specific handshake state. + */ + union + { + /* Outgoing Finished message */ + struct + { + uint8_t preparation_done; + + /* Buffer holding digest of the handshake up to + * but excluding the outgoing finished message. */ + unsigned char digest[MBEDTLS_MD_MAX_SIZE]; + size_t digest_len; + } finished_out; + + /* Incoming Finished message */ + struct + { + /* Buffer holding digest of the handshake up to but + * excluding the peer's incoming finished message. */ + unsigned char digest[MBEDTLS_MD_MAX_SIZE]; + size_t digest_len; + } finished_in; + +#if defined(MBEDTLS_SSL_CLI_C) + + /* Client, incoming ServerKeyExchange */ + struct + { + uint8_t preparation_done; + } srv_key_exchange; + + /* Client, incoming ServerHello */ + struct + { +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_info_seen; +#else + int dummy; +#endif + } srv_hello_in; + + /* Client, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } cli_key_exch_out; + + /* Client, outgoing Certificate Verify */ + struct + { + uint8_t preparation_done; + } crt_vrfy_out; + + /* Client, outgoing ClientHello */ + struct + { + uint8_t preparation_done; + } cli_hello_out; + +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + + /* Server, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } cli_key_exch_in; + + /* Server, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } encrypted_extensions_out; + +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Incoming CertificateVerify */ + struct + { + unsigned char verify_buffer[ 64 + 33 + 1 + MBEDTLS_MD_MAX_SIZE ]; + size_t verify_buffer_len; + } certificate_verify_in; + + /* Outgoing CertificateVerify */ + struct + { + unsigned char handshake_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t handshake_hash_len; + } certificate_verify_out; + + } state_local; + + /* End of state-local variables. */ + mbedtls_ssl_ciphersuite_t const *ciphersuite_info; size_t pmslen; /*!< premaster length */ @@ -1162,6 +1260,11 @@ static inline int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ); int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_read_certificate_process(mbedtls_ssl_context *ssl); +int mbedtls_ssl_write_certificate_process(mbedtls_ssl_context *ssl); +int mbedtls_ssl_tls1_3_finished_in_process( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_tls1_3_finished_out_process( mbedtls_ssl_context *ssl ); + int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ); diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 75b11c93af..c9bf78e6a7 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -845,6 +845,159 @@ cleanup: return( ret ); } +/* + * + * STATE HANDLING: Incoming Finished + * Overview + */ + +/* Main entry point: orchestrates the other functions */ +int mbedtls_ssl_tls1_3_finished_in_process( mbedtls_ssl_context* ssl ); + +static int ssl_finished_in_preprocess( mbedtls_ssl_context* ssl ); +static int ssl_finished_in_postprocess( mbedtls_ssl_context* ssl ); +static int ssl_finished_in_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +/* + * Implementation + */ + +int mbedtls_ssl_tls1_3_finished_in_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + /* Preprocessing step: Compute handshake digest */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_preprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls1_3_fetch_handshake_msg( ssl, + MBEDTLS_SSL_HS_FINISHED, + &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_parse( ssl, buf, buflen ) ); + mbedtls_ssl_tls1_3_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_FINISHED, buf, buflen ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + return( ret ); +} + +static int ssl_finished_in_preprocess( mbedtls_ssl_context* ssl ) +{ + int ret; + + ret = mbedtls_ssl_tls1_3_calc_finished( ssl, + ssl->handshake->state_local.finished_in.digest, + sizeof( ssl->handshake->state_local.finished_in.digest ), + &ssl->handshake->state_local.finished_in.digest_len, + ssl->conf->endpoint ^ 1 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_calc_finished", ret ); + return( ret ); + } + + return( 0 ); +} + +static int ssl_finished_in_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + /* Structural validation */ + if( buflen != ssl->handshake->state_local.finished_in.digest_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + + MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_DECODE_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Hash (self-computed):", + ssl->handshake->state_local.finished_in.digest, + ssl->handshake->state_local.finished_in.digest_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Hash (received message):", buf, + ssl->handshake->state_local.finished_in.digest_len ); + + /* Semantic validation */ + if( mbedtls_ssl_safer_memcmp( buf, + ssl->handshake->state_local.finished_in.digest, + ssl->handshake->state_local.finished_in.digest_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + + MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); + } + return( 0 ); +} + +static int ssl_finished_in_postprocess_cli( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_ssl_key_set traffic_keys; + mbedtls_ssl_transform *transform_application; + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_application( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_application", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_generate_application_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_application_keys", ret ); + return( ret ); + } + + transform_application = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_application == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + + ssl->transform_application = transform_application; + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_END_OF_EARLY_DATA ); + return( 0 ); +} + +static int ssl_finished_in_postprocess( mbedtls_ssl_context* ssl ) +{ + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + return( ssl_finished_in_postprocess_cli( ssl ) ); + } + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c index 96f5310797..010d6352da 100644 --- a/library/ssl_tls13_keys.c +++ b/library/ssl_tls13_keys.c @@ -564,6 +564,36 @@ int mbedtls_ssl_tls1_3_derive_resumption_master_secret( return( 0 ); } +int mbedtls_ssl_tls1_3_key_schedule_stage_application( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; +#if defined(MBEDTLS_DEBUG_C) + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); +#endif /* MBEDTLS_DEBUG_C */ + + /* + * Compute MasterSecret + */ + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + ssl->handshake->tls1_3_master_secrets.handshake, + NULL, 0, + ssl->handshake->tls1_3_master_secrets.app ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Master secret", + ssl->handshake->tls1_3_master_secrets.app, md_size ); + + return( 0 ); +} + static int ssl_tls1_3_calc_finished_core( mbedtls_md_type_t md_type, unsigned char const *base_key, unsigned char const *transcript, @@ -614,6 +644,54 @@ exit: return( ret ); } +int mbedtls_ssl_tls1_3_calc_finished( mbedtls_ssl_context* ssl, + unsigned char* dst, + size_t dst_len, + size_t *actual_len, + int from ) +{ + int ret; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + unsigned char const *base_key = NULL; + + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; + const mbedtls_md_info_t* const md = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_tls1_3_calc_finished" ) ); + + if( dst_len < md_size ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_BUF( 4, "handshake hash", transcript, transcript_len ); + + if( from == MBEDTLS_SSL_IS_CLIENT ) + base_key = ssl->handshake->tls1_3_hs_secrets.client_handshake_traffic_secret; + else + base_key = ssl->handshake->tls1_3_hs_secrets.server_handshake_traffic_secret; + + ret = ssl_tls1_3_calc_finished_core( md_type, base_key, transcript, dst ); + if( ret != 0 ) + return( ret ); + *actual_len = md_size; + + MBEDTLS_SSL_DEBUG_BUF( 3, "verify_data for finished message", dst, md_size ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_calc_finished" ) ); + return( 0 ); +} + int mbedtls_ssl_tls1_3_create_psk_binder( mbedtls_ssl_context *ssl, const mbedtls_md_type_t md_type, unsigned char const *psk, size_t psk_len, @@ -1028,4 +1106,120 @@ int mbedtls_ssl_tls13_key_schedule_stage_handshake( mbedtls_ssl_context *ssl ) return( 0 ); } +/* Generate application traffic keys since any records following a 1-RTT Finished message + * MUST be encrypted under the application traffic key. + */ +int mbedtls_ssl_tls1_3_generate_application_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + /* Address at which to store the application secrets */ + mbedtls_ssl_tls1_3_application_secrets * const app_secrets = + &ssl->session_negotiate->app_secrets; + + /* Holding the transcript up to and including the ServerFinished */ + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + /* Variables relating to the hash for the chosen ciphersuite. */ + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + /* Variables relating to the cipher for the chosen ciphersuite. */ + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive application traffic keys" ) ); + + /* Extract basic information about hash and ciphersuite */ + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + /* Compute current handshake transcript. It's the caller's responsiblity + * to call this at the right time, that is, after the ServerFinished. */ + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + /* Compute application secrets from master secret and transcript hash. */ + + ret = mbedtls_ssl_tls1_3_derive_application_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.app, + transcript, transcript_len, + app_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_derive_application_secrets", ret ); + return( ret ); + } + + /* Derive first epoch of IV + Key for application traffic. */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + app_secrets->client_application_traffic_secret_N, + app_secrets->server_application_traffic_secret_N, + md_size, keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Client application traffic secret", + app_secrets->client_application_traffic_secret_N, + md_size ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Server application traffic secret", + app_secrets->server_application_traffic_secret_N, + md_size ); + + /* + * Export client/server application traffic secret 0 + */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->f_export_keys != NULL ) + { + ssl->f_export_keys( ssl->p_export_keys, + MBEDTLS_SSL_KEY_EXPORT_TLS13_CLIENT_APPLICATION_TRAFFIC_SECRET, + app_secrets->client_application_traffic_secret_N, md_size, + ssl->handshake->randbytes + 32, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS_PRF_NONE /* TODO: FIX! */ ); + + ssl->f_export_keys( ssl->p_export_keys, + MBEDTLS_SSL_KEY_EXPORT_TLS13_SERVER_APPLICATION_TRAFFIC_SECRET, + app_secrets->server_application_traffic_secret_N, md_size, + ssl->handshake->randbytes + 32, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS_PRF_NONE /* TODO: FIX! */ ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + MBEDTLS_SSL_DEBUG_BUF( 4, "client application_write_key:", + traffic_keys->client_write_key, keylen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "server application write key", + traffic_keys->server_write_key, keylen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "client application write IV", + traffic_keys->client_write_iv, ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "server application write IV", + traffic_keys->server_write_iv, ivlen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive application traffic keys" ) ); + return( 0 ); +} + #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h index 165b58a2d4..78bfc2a3d6 100644 --- a/library/ssl_tls13_keys.h +++ b/library/ssl_tls13_keys.h @@ -570,4 +570,65 @@ int mbedtls_ssl_tls13_key_schedule_stage_handshake( mbedtls_ssl_context *ssl ); int mbedtls_ssl_tls13_generate_handshake_keys( mbedtls_ssl_context *ssl, mbedtls_ssl_key_set *traffic_keys ); +/** + * \brief Transition into application stage of TLS 1.3 key schedule. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Handshake -> Application transition. + * + * In the handshake stage, mbedtls_ssl_tls1_3_generate_application_keys() + * can be used to derive the handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in key schedule + * stage \c Handshake. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_application( + mbedtls_ssl_context *ssl ); + +/** + * \brief Compute TLS 1.3 application traffic keys. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Application, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * \param traffic_keys The address at which to store the application traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_application_keys( + mbedtls_ssl_context* ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Calculate content of TLS 1.3 Finished message. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Handshake, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * \param dst The address at which to write the Finished content. + * \param dst_len The size of \p dst in bytes. + * \param actual_len The address at which to store the amount of data + * actually written to \p dst upon success. + * \param from The endpoint the Finished message originates from: + * - #MBEDTLS_SSL_IS_CLIENT for the Client's Finished message + * - #MBEDTLS_SSL_IS_SERVER for the Server's Finished message + * + * \note Both client and server call this function twice, once to + * generate their own Finished message, and once to verify the + * peer's Finished message. + + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_calc_finished( mbedtls_ssl_context *ssl, + unsigned char *dst, + size_t dst_len, + size_t *actual_len, + int from ); + #endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */