| /* |
| * TLS shared functions |
| * |
| * Copyright The Mbed TLS Contributors |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| * not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /* |
| * http://www.ietf.org/rfc/rfc2246.txt |
| * http://www.ietf.org/rfc/rfc4346.txt |
| */ |
| |
| #include "common.h" |
| |
| #if defined(MBEDTLS_SSL_TLS_C) |
| |
| #include <assert.h> |
| |
| #if defined(MBEDTLS_PLATFORM_C) |
| #include "mbedtls/platform.h" |
| #else |
| #include <stdlib.h> |
| #include <stdio.h> |
| #define mbedtls_calloc calloc |
| #define mbedtls_free free |
| #define mbedtls_printf printf |
| #endif /* !MBEDTLS_PLATFORM_C */ |
| |
| #include "mbedtls/ssl.h" |
| #include "ssl_client.h" |
| #include "ssl_debug_helpers.h" |
| #include "ssl_misc.h" |
| #include "mbedtls/debug.h" |
| #include "mbedtls/error.h" |
| #include "mbedtls/platform_util.h" |
| #include "mbedtls/version.h" |
| #include "mbedtls/constant_time.h" |
| |
| #include <string.h> |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| #include "mbedtls/psa_util.h" |
| #include "psa/crypto.h" |
| #endif |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| #include "mbedtls/oid.h" |
| #endif |
| |
| #if defined(MBEDTLS_TEST_HOOKS) |
| static mbedtls_ssl_chk_buf_ptr_args chk_buf_ptr_fail_args; |
| |
| void mbedtls_ssl_set_chk_buf_ptr_fail_args( |
| const uint8_t *cur, const uint8_t *end, size_t need ) |
| { |
| chk_buf_ptr_fail_args.cur = cur; |
| chk_buf_ptr_fail_args.end = end; |
| chk_buf_ptr_fail_args.need = need; |
| } |
| |
| void mbedtls_ssl_reset_chk_buf_ptr_fail_args( void ) |
| { |
| memset( &chk_buf_ptr_fail_args, 0, sizeof( chk_buf_ptr_fail_args ) ); |
| } |
| |
| int mbedtls_ssl_cmp_chk_buf_ptr_fail_args( mbedtls_ssl_chk_buf_ptr_args *args ) |
| { |
| return( ( chk_buf_ptr_fail_args.cur != args->cur ) || |
| ( chk_buf_ptr_fail_args.end != args->end ) || |
| ( chk_buf_ptr_fail_args.need != args->need ) ); |
| } |
| #endif /* MBEDTLS_TEST_HOOKS */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| /* Top-level Connection ID API */ |
| |
| int mbedtls_ssl_conf_cid( mbedtls_ssl_config *conf, |
| size_t len, |
| int ignore_other_cid ) |
| { |
| if( len > MBEDTLS_SSL_CID_IN_LEN_MAX ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| if( ignore_other_cid != MBEDTLS_SSL_UNEXPECTED_CID_FAIL && |
| ignore_other_cid != MBEDTLS_SSL_UNEXPECTED_CID_IGNORE ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| conf->ignore_unexpected_cid = ignore_other_cid; |
| conf->cid_len = len; |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_set_cid( mbedtls_ssl_context *ssl, |
| int enable, |
| unsigned char const *own_cid, |
| size_t own_cid_len ) |
| { |
| if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| ssl->negotiate_cid = enable; |
| if( enable == MBEDTLS_SSL_CID_DISABLED ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Disable use of CID extension." ) ); |
| return( 0 ); |
| } |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Enable use of CID extension." ) ); |
| MBEDTLS_SSL_DEBUG_BUF( 3, "Own CID", own_cid, own_cid_len ); |
| |
| if( own_cid_len != ssl->conf->cid_len ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "CID length %u does not match CID length %u in config", |
| (unsigned) own_cid_len, |
| (unsigned) ssl->conf->cid_len ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| memcpy( ssl->own_cid, own_cid, own_cid_len ); |
| /* Truncation is not an issue here because |
| * MBEDTLS_SSL_CID_IN_LEN_MAX at most 255. */ |
| ssl->own_cid_len = (uint8_t) own_cid_len; |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_get_own_cid( mbedtls_ssl_context *ssl, |
| int *enabled, |
| unsigned char own_cid[MBEDTLS_SSL_CID_OUT_LEN_MAX], |
| size_t *own_cid_len ) |
| { |
| *enabled = MBEDTLS_SSL_CID_DISABLED; |
| |
| if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| /* We report MBEDTLS_SSL_CID_DISABLED in case the CID length is |
| * zero as this is indistinguishable from not requesting to use |
| * the CID extension. */ |
| if( ssl->own_cid_len == 0 || ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED ) |
| return( 0 ); |
| |
| if( own_cid_len != NULL ) |
| { |
| *own_cid_len = ssl->own_cid_len; |
| if( own_cid != NULL ) |
| memcpy( own_cid, ssl->own_cid, ssl->own_cid_len ); |
| } |
| |
| *enabled = MBEDTLS_SSL_CID_ENABLED; |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_get_peer_cid( mbedtls_ssl_context *ssl, |
| int *enabled, |
| unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ], |
| size_t *peer_cid_len ) |
| { |
| *enabled = MBEDTLS_SSL_CID_DISABLED; |
| |
| if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM || |
| mbedtls_ssl_is_handshake_over( ssl ) == 0 ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| /* We report MBEDTLS_SSL_CID_DISABLED in case the CID extensions |
| * were used, but client and server requested the empty CID. |
| * This is indistinguishable from not using the CID extension |
| * in the first place. */ |
| if( ssl->transform_in->in_cid_len == 0 && |
| ssl->transform_in->out_cid_len == 0 ) |
| { |
| return( 0 ); |
| } |
| |
| if( peer_cid_len != NULL ) |
| { |
| *peer_cid_len = ssl->transform_in->out_cid_len; |
| if( peer_cid != NULL ) |
| { |
| memcpy( peer_cid, ssl->transform_in->out_cid, |
| ssl->transform_in->out_cid_len ); |
| } |
| } |
| |
| *enabled = MBEDTLS_SSL_CID_ENABLED; |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ |
| |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| /* |
| * Convert max_fragment_length codes to length. |
| * RFC 6066 says: |
| * enum{ |
| * 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255) |
| * } MaxFragmentLength; |
| * and we add 0 -> extension unused |
| */ |
| static unsigned int ssl_mfl_code_to_length( int mfl ) |
| { |
| switch( mfl ) |
| { |
| case MBEDTLS_SSL_MAX_FRAG_LEN_NONE: |
| return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ); |
| case MBEDTLS_SSL_MAX_FRAG_LEN_512: |
| return 512; |
| case MBEDTLS_SSL_MAX_FRAG_LEN_1024: |
| return 1024; |
| case MBEDTLS_SSL_MAX_FRAG_LEN_2048: |
| return 2048; |
| case MBEDTLS_SSL_MAX_FRAG_LEN_4096: |
| return 4096; |
| default: |
| return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ); |
| } |
| } |
| #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ |
| |
| int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, |
| const mbedtls_ssl_session *src ) |
| { |
| mbedtls_ssl_session_free( dst ); |
| memcpy( dst, src, sizeof( mbedtls_ssl_session ) ); |
| |
| #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) |
| dst->ticket = NULL; |
| #endif |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| |
| #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) |
| if( src->peer_cert != NULL ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) ); |
| if( dst->peer_cert == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| mbedtls_x509_crt_init( dst->peer_cert ); |
| |
| if( ( ret = mbedtls_x509_crt_parse_der( dst->peer_cert, src->peer_cert->raw.p, |
| src->peer_cert->raw.len ) ) != 0 ) |
| { |
| mbedtls_free( dst->peer_cert ); |
| dst->peer_cert = NULL; |
| return( ret ); |
| } |
| } |
| #else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ |
| if( src->peer_cert_digest != NULL ) |
| { |
| dst->peer_cert_digest = |
| mbedtls_calloc( 1, src->peer_cert_digest_len ); |
| if( dst->peer_cert_digest == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| memcpy( dst->peer_cert_digest, src->peer_cert_digest, |
| src->peer_cert_digest_len ); |
| dst->peer_cert_digest_type = src->peer_cert_digest_type; |
| dst->peer_cert_digest_len = src->peer_cert_digest_len; |
| } |
| #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ |
| |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) |
| if( src->ticket != NULL ) |
| { |
| dst->ticket = mbedtls_calloc( 1, src->ticket_len ); |
| if( dst->ticket == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| memcpy( dst->ticket, src->ticket, src->ticket_len ); |
| } |
| #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ |
| |
| return( 0 ); |
| } |
| |
| #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int resize_buffer( unsigned char **buffer, size_t len_new, size_t *len_old ) |
| { |
| unsigned char* resized_buffer = mbedtls_calloc( 1, len_new ); |
| if( resized_buffer == NULL ) |
| return -1; |
| |
| /* We want to copy len_new bytes when downsizing the buffer, and |
| * len_old bytes when upsizing, so we choose the smaller of two sizes, |
| * to fit one buffer into another. Size checks, ensuring that no data is |
| * lost, are done outside of this function. */ |
| memcpy( resized_buffer, *buffer, |
| ( len_new < *len_old ) ? len_new : *len_old ); |
| mbedtls_platform_zeroize( *buffer, *len_old ); |
| mbedtls_free( *buffer ); |
| |
| *buffer = resized_buffer; |
| *len_old = len_new; |
| |
| return 0; |
| } |
| |
| static void handle_buffer_resizing( mbedtls_ssl_context *ssl, int downsizing, |
| size_t in_buf_new_len, |
| size_t out_buf_new_len ) |
| { |
| int modified = 0; |
| size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0; |
| size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0; |
| if( ssl->in_buf != NULL ) |
| { |
| written_in = ssl->in_msg - ssl->in_buf; |
| iv_offset_in = ssl->in_iv - ssl->in_buf; |
| len_offset_in = ssl->in_len - ssl->in_buf; |
| if( downsizing ? |
| ssl->in_buf_len > in_buf_new_len && ssl->in_left < in_buf_new_len : |
| ssl->in_buf_len < in_buf_new_len ) |
| { |
| if( resize_buffer( &ssl->in_buf, in_buf_new_len, &ssl->in_buf_len ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) ); |
| } |
| else |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %" MBEDTLS_PRINTF_SIZET, |
| in_buf_new_len ) ); |
| modified = 1; |
| } |
| } |
| } |
| |
| if( ssl->out_buf != NULL ) |
| { |
| written_out = ssl->out_msg - ssl->out_buf; |
| iv_offset_out = ssl->out_iv - ssl->out_buf; |
| len_offset_out = ssl->out_len - ssl->out_buf; |
| if( downsizing ? |
| ssl->out_buf_len > out_buf_new_len && ssl->out_left < out_buf_new_len : |
| ssl->out_buf_len < out_buf_new_len ) |
| { |
| if( resize_buffer( &ssl->out_buf, out_buf_new_len, &ssl->out_buf_len ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) ); |
| } |
| else |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %" MBEDTLS_PRINTF_SIZET, |
| out_buf_new_len ) ); |
| modified = 1; |
| } |
| } |
| } |
| if( modified ) |
| { |
| /* Update pointers here to avoid doing it twice. */ |
| mbedtls_ssl_reset_in_out_pointers( ssl ); |
| /* Fields below might not be properly updated with record |
| * splitting or with CID, so they are manually updated here. */ |
| ssl->out_msg = ssl->out_buf + written_out; |
| ssl->out_len = ssl->out_buf + len_offset_out; |
| ssl->out_iv = ssl->out_buf + iv_offset_out; |
| |
| ssl->in_msg = ssl->in_buf + written_in; |
| ssl->in_len = ssl->in_buf + len_offset_in; |
| ssl->in_iv = ssl->in_buf + iv_offset_in; |
| } |
| } |
| #endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| |
| #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) |
| typedef int (*tls_prf_fn)( const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ); |
| |
| static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id ); |
| |
| #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */ |
| |
| /* Type for the TLS PRF */ |
| typedef int ssl_tls_prf_t(const unsigned char *, size_t, const char *, |
| const unsigned char *, size_t, |
| unsigned char *, size_t); |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_tls12_populate_transform( mbedtls_ssl_transform *transform, |
| int ciphersuite, |
| const unsigned char master[48], |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM) |
| int encrypt_then_mac, |
| #endif /* MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM */ |
| ssl_tls_prf_t tls_prf, |
| const unsigned char randbytes[64], |
| mbedtls_ssl_protocol_version tls_version, |
| unsigned endpoint, |
| const mbedtls_ssl_context *ssl ); |
| |
| #if defined(MBEDTLS_SHA256_C) |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int tls_prf_sha256( const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ); |
| static void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *,unsigned char*, size_t * ); |
| static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int ); |
| |
| #endif /* MBEDTLS_SHA256_C */ |
| |
| #if defined(MBEDTLS_SHA384_C) |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int tls_prf_sha384( const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ); |
| |
| static void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *, unsigned char*, size_t * ); |
| static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int ); |
| #endif /* MBEDTLS_SHA384_C */ |
| |
| static size_t ssl_session_save_tls12( const mbedtls_ssl_session *session, |
| unsigned char *buf, |
| size_t buf_len ); |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_session_load_tls12( mbedtls_ssl_session *session, |
| const unsigned char *buf, |
| size_t len ); |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| static void ssl_update_checksum_start( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| |
| #if defined(MBEDTLS_SHA256_C) |
| static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| #endif /* MBEDTLS_SHA256_C */ |
| |
| #if defined(MBEDTLS_SHA384_C) |
| static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| #endif /* MBEDTLS_SHA384_C */ |
| |
| int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, |
| const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ) |
| { |
| mbedtls_ssl_tls_prf_cb *tls_prf = NULL; |
| |
| switch( prf ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_SHA384_C) |
| case MBEDTLS_SSL_TLS_PRF_SHA384: |
| tls_prf = tls_prf_sha384; |
| break; |
| #endif /* MBEDTLS_SHA384_C */ |
| #if defined(MBEDTLS_SHA256_C) |
| case MBEDTLS_SSL_TLS_PRF_SHA256: |
| tls_prf = tls_prf_sha256; |
| break; |
| #endif /* MBEDTLS_SHA256_C */ |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| default: |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) ); |
| } |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| static void ssl_clear_peer_cert( mbedtls_ssl_session *session ) |
| { |
| #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) |
| if( session->peer_cert != NULL ) |
| { |
| mbedtls_x509_crt_free( session->peer_cert ); |
| mbedtls_free( session->peer_cert ); |
| session->peer_cert = NULL; |
| } |
| #else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ |
| if( session->peer_cert_digest != NULL ) |
| { |
| /* Zeroization is not necessary. */ |
| mbedtls_free( session->peer_cert_digest ); |
| session->peer_cert_digest = NULL; |
| session->peer_cert_digest_type = MBEDTLS_MD_NONE; |
| session->peer_cert_digest_len = 0; |
| } |
| #endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ |
| } |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, |
| const mbedtls_ssl_ciphersuite_t *ciphersuite_info ) |
| { |
| ((void) ciphersuite_info); |
| |
| #if defined(MBEDTLS_SHA384_C) |
| if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) |
| ssl->handshake->update_checksum = ssl_update_checksum_sha384; |
| else |
| #endif |
| #if defined(MBEDTLS_SHA256_C) |
| if( ciphersuite_info->mac != MBEDTLS_MD_SHA384 ) |
| ssl->handshake->update_checksum = ssl_update_checksum_sha256; |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return; |
| } |
| } |
| |
| static void mbedtls_ssl_add_hs_hdr_to_checksum( mbedtls_ssl_context *ssl, |
| unsigned hs_type, |
| size_t total_hs_len ) |
| { |
| unsigned char hs_hdr[4]; |
| |
| /* Build HS header for checksum update. */ |
| hs_hdr[0] = MBEDTLS_BYTE_0( hs_type ); |
| hs_hdr[1] = MBEDTLS_BYTE_2( total_hs_len ); |
| hs_hdr[2] = MBEDTLS_BYTE_1( total_hs_len ); |
| hs_hdr[3] = MBEDTLS_BYTE_0( total_hs_len ); |
| |
| ssl->handshake->update_checksum( ssl, hs_hdr, sizeof( hs_hdr ) ); |
| } |
| |
| void mbedtls_ssl_add_hs_msg_to_checksum( mbedtls_ssl_context *ssl, |
| unsigned hs_type, |
| unsigned char const *msg, |
| size_t msg_len ) |
| { |
| mbedtls_ssl_add_hs_hdr_to_checksum( ssl, hs_type, msg_len ); |
| ssl->handshake->update_checksum( ssl, msg, msg_len ); |
| } |
| |
| void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) |
| { |
| ((void) ssl); |
| #if defined(MBEDTLS_SHA256_C) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_hash_abort( &ssl->handshake->fin_sha256_psa ); |
| psa_hash_setup( &ssl->handshake->fin_sha256_psa, PSA_ALG_SHA_256 ); |
| #else |
| mbedtls_sha256_starts( &ssl->handshake->fin_sha256, 0 ); |
| #endif |
| #endif |
| #if defined(MBEDTLS_SHA384_C) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_hash_abort( &ssl->handshake->fin_sha384_psa ); |
| psa_hash_setup( &ssl->handshake->fin_sha384_psa, PSA_ALG_SHA_384 ); |
| #else |
| mbedtls_sha512_starts( &ssl->handshake->fin_sha512, 1 ); |
| #endif |
| #endif |
| } |
| |
| static void ssl_update_checksum_start( mbedtls_ssl_context *ssl, |
| const unsigned char *buf, size_t len ) |
| { |
| #if defined(MBEDTLS_SHA256_C) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_hash_update( &ssl->handshake->fin_sha256_psa, buf, len ); |
| #else |
| mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); |
| #endif |
| #endif |
| #if defined(MBEDTLS_SHA384_C) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_hash_update( &ssl->handshake->fin_sha384_psa, buf, len ); |
| #else |
| mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); |
| #endif |
| #endif |
| } |
| |
| #if defined(MBEDTLS_SHA256_C) |
| static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, |
| const unsigned char *buf, size_t len ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_hash_update( &ssl->handshake->fin_sha256_psa, buf, len ); |
| #else |
| mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); |
| #endif |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SHA384_C) |
| static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, |
| const unsigned char *buf, size_t len ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_hash_update( &ssl->handshake->fin_sha384_psa, buf, len ); |
| #else |
| mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); |
| #endif |
| } |
| #endif |
| |
| static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) |
| { |
| memset( handshake, 0, sizeof( mbedtls_ssl_handshake_params ) ); |
| |
| #if defined(MBEDTLS_SHA256_C) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| handshake->fin_sha256_psa = psa_hash_operation_init(); |
| psa_hash_setup( &handshake->fin_sha256_psa, PSA_ALG_SHA_256 ); |
| #else |
| mbedtls_sha256_init( &handshake->fin_sha256 ); |
| mbedtls_sha256_starts( &handshake->fin_sha256, 0 ); |
| #endif |
| #endif |
| #if defined(MBEDTLS_SHA384_C) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| handshake->fin_sha384_psa = psa_hash_operation_init(); |
| psa_hash_setup( &handshake->fin_sha384_psa, PSA_ALG_SHA_384 ); |
| #else |
| mbedtls_sha512_init( &handshake->fin_sha512 ); |
| mbedtls_sha512_starts( &handshake->fin_sha512, 1 ); |
| #endif |
| #endif |
| |
| handshake->update_checksum = ssl_update_checksum_start; |
| |
| #if defined(MBEDTLS_DHM_C) |
| mbedtls_dhm_init( &handshake->dhm_ctx ); |
| #endif |
| #if !defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_ECDH_C) |
| mbedtls_ecdh_init( &handshake->ecdh_ctx ); |
| #endif |
| #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) |
| mbedtls_ecjpake_init( &handshake->ecjpake_ctx ); |
| #if defined(MBEDTLS_SSL_CLI_C) |
| handshake->ecjpake_cache = NULL; |
| handshake->ecjpake_cache_len = 0; |
| #endif |
| #endif |
| |
| #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) |
| mbedtls_x509_crt_restart_init( &handshake->ecrs_ctx ); |
| #endif |
| |
| #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) |
| handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; |
| #endif |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) && \ |
| !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) |
| mbedtls_pk_init( &handshake->peer_pubkey ); |
| #endif |
| } |
| |
| void mbedtls_ssl_transform_init( mbedtls_ssl_transform *transform ) |
| { |
| memset( transform, 0, sizeof(mbedtls_ssl_transform) ); |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| transform->psa_key_enc = MBEDTLS_SVC_KEY_ID_INIT; |
| transform->psa_key_dec = MBEDTLS_SVC_KEY_ID_INIT; |
| #else |
| mbedtls_cipher_init( &transform->cipher_ctx_enc ); |
| mbedtls_cipher_init( &transform->cipher_ctx_dec ); |
| #endif |
| |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| transform->psa_mac_enc = MBEDTLS_SVC_KEY_ID_INIT; |
| transform->psa_mac_dec = MBEDTLS_SVC_KEY_ID_INIT; |
| #else |
| mbedtls_md_init( &transform->md_ctx_enc ); |
| mbedtls_md_init( &transform->md_ctx_dec ); |
| #endif |
| #endif |
| } |
| |
| void mbedtls_ssl_session_init( mbedtls_ssl_session *session ) |
| { |
| memset( session, 0, sizeof(mbedtls_ssl_session) ); |
| } |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_handshake_init( mbedtls_ssl_context *ssl ) |
| { |
| /* Clear old handshake information if present */ |
| if( ssl->transform_negotiate ) |
| mbedtls_ssl_transform_free( ssl->transform_negotiate ); |
| if( ssl->session_negotiate ) |
| mbedtls_ssl_session_free( ssl->session_negotiate ); |
| if( ssl->handshake ) |
| mbedtls_ssl_handshake_free( ssl ); |
| |
| /* |
| * Either the pointers are now NULL or cleared properly and can be freed. |
| * Now allocate missing structures. |
| */ |
| if( ssl->transform_negotiate == NULL ) |
| { |
| ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); |
| } |
| |
| if( ssl->session_negotiate == NULL ) |
| { |
| ssl->session_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_session) ); |
| } |
| |
| if( ssl->handshake == NULL ) |
| { |
| ssl->handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); |
| } |
| #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) |
| /* If the buffers are too small - reallocate */ |
| |
| handle_buffer_resizing( ssl, 0, MBEDTLS_SSL_IN_BUFFER_LEN, |
| MBEDTLS_SSL_OUT_BUFFER_LEN ); |
| #endif |
| |
| /* All pointers should exist and can be directly freed without issue */ |
| if( ssl->handshake == NULL || |
| ssl->transform_negotiate == NULL || |
| ssl->session_negotiate == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc() of ssl sub-contexts failed" ) ); |
| |
| mbedtls_free( ssl->handshake ); |
| mbedtls_free( ssl->transform_negotiate ); |
| mbedtls_free( ssl->session_negotiate ); |
| |
| ssl->handshake = NULL; |
| ssl->transform_negotiate = NULL; |
| ssl->session_negotiate = NULL; |
| |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| } |
| |
| /* Initialize structures */ |
| mbedtls_ssl_session_init( ssl->session_negotiate ); |
| mbedtls_ssl_transform_init( ssl->transform_negotiate ); |
| ssl_handshake_params_init( ssl->handshake ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| ssl->handshake->alt_transform_out = ssl->transform_out; |
| |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; |
| else |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; |
| |
| mbedtls_ssl_set_timer( ssl, 0 ); |
| } |
| #endif |
| |
| /* |
| * curve_list is translated to IANA TLS group identifiers here because |
| * mbedtls_ssl_conf_curves returns void and so can't return |
| * any error codes. |
| */ |
| #if defined(MBEDTLS_ECP_C) |
| #if !defined(MBEDTLS_DEPRECATED_REMOVED) |
| /* Heap allocate and translate curve_list from internal to IANA group ids */ |
| if ( ssl->conf->curve_list != NULL ) |
| { |
| size_t length; |
| const mbedtls_ecp_group_id *curve_list = ssl->conf->curve_list; |
| |
| for( length = 0; ( curve_list[length] != MBEDTLS_ECP_DP_NONE ) && |
| ( length < MBEDTLS_ECP_DP_MAX ); length++ ) {} |
| |
| /* Leave room for zero termination */ |
| uint16_t *group_list = mbedtls_calloc( length + 1, sizeof(uint16_t) ); |
| if ( group_list == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| for( size_t i = 0; i < length; i++ ) |
| { |
| const mbedtls_ecp_curve_info *info = |
| mbedtls_ecp_curve_info_from_grp_id( curve_list[i] ); |
| if ( info == NULL ) |
| { |
| mbedtls_free( group_list ); |
| return( MBEDTLS_ERR_SSL_BAD_CONFIG ); |
| } |
| group_list[i] = info->tls_id; |
| } |
| |
| group_list[length] = 0; |
| |
| ssl->handshake->group_list = group_list; |
| ssl->handshake->group_list_heap_allocated = 1; |
| } |
| else |
| { |
| ssl->handshake->group_list = ssl->conf->group_list; |
| ssl->handshake->group_list_heap_allocated = 0; |
| } |
| #endif /* MBEDTLS_DEPRECATED_REMOVED */ |
| #endif /* MBEDTLS_ECP_C */ |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) |
| #if !defined(MBEDTLS_DEPRECATED_REMOVED) |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| /* Heap allocate and translate sig_hashes from internal hash identifiers to |
| signature algorithms IANA identifiers. */ |
| if ( mbedtls_ssl_conf_is_tls12_only( ssl->conf ) && |
| ssl->conf->sig_hashes != NULL ) |
| { |
| const int *md; |
| const int *sig_hashes = ssl->conf->sig_hashes; |
| size_t sig_algs_len = 0; |
| uint16_t *p; |
| |
| #if defined(static_assert) |
| static_assert( MBEDTLS_SSL_MAX_SIG_ALG_LIST_LEN |
| <= ( SIZE_MAX - ( 2 * sizeof(uint16_t) ) ), |
| "MBEDTLS_SSL_MAX_SIG_ALG_LIST_LEN too big" ); |
| #endif |
| |
| for( md = sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) |
| { |
| if( mbedtls_ssl_hash_from_md_alg( *md ) == MBEDTLS_SSL_HASH_NONE ) |
| continue; |
| #if defined(MBEDTLS_ECDSA_C) |
| sig_algs_len += sizeof( uint16_t ); |
| #endif |
| |
| #if defined(MBEDTLS_RSA_C) |
| sig_algs_len += sizeof( uint16_t ); |
| #endif |
| if( sig_algs_len > MBEDTLS_SSL_MAX_SIG_ALG_LIST_LEN ) |
| return( MBEDTLS_ERR_SSL_BAD_CONFIG ); |
| } |
| |
| if( sig_algs_len < MBEDTLS_SSL_MIN_SIG_ALG_LIST_LEN ) |
| return( MBEDTLS_ERR_SSL_BAD_CONFIG ); |
| |
| ssl->handshake->sig_algs = mbedtls_calloc( 1, sig_algs_len + |
| sizeof( uint16_t )); |
| if( ssl->handshake->sig_algs == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| p = (uint16_t *)ssl->handshake->sig_algs; |
| for( md = sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) |
| { |
| unsigned char hash = mbedtls_ssl_hash_from_md_alg( *md ); |
| if( hash == MBEDTLS_SSL_HASH_NONE ) |
| continue; |
| #if defined(MBEDTLS_ECDSA_C) |
| *p = (( hash << 8 ) | MBEDTLS_SSL_SIG_ECDSA); |
| p++; |
| #endif |
| #if defined(MBEDTLS_RSA_C) |
| *p = (( hash << 8 ) | MBEDTLS_SSL_SIG_RSA); |
| p++; |
| #endif |
| } |
| *p = MBEDTLS_TLS_SIG_NONE; |
| ssl->handshake->sig_algs_heap_allocated = 1; |
| } |
| else |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| { |
| ssl->handshake->sig_algs_heap_allocated = 0; |
| } |
| #endif /* !MBEDTLS_DEPRECATED_REMOVED */ |
| #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ |
| return( 0 ); |
| } |
| |
| #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) |
| /* Dummy cookie callbacks for defaults */ |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_cookie_write_dummy( void *ctx, |
| unsigned char **p, unsigned char *end, |
| const unsigned char *cli_id, size_t cli_id_len ) |
| { |
| ((void) ctx); |
| ((void) p); |
| ((void) end); |
| ((void) cli_id); |
| ((void) cli_id_len); |
| |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_cookie_check_dummy( void *ctx, |
| const unsigned char *cookie, size_t cookie_len, |
| const unsigned char *cli_id, size_t cli_id_len ) |
| { |
| ((void) ctx); |
| ((void) cookie); |
| ((void) cookie_len); |
| ((void) cli_id); |
| ((void) cli_id_len); |
| |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ |
| |
| /* |
| * Initialize an SSL context |
| */ |
| void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) |
| { |
| memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); |
| } |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_conf_version_check( const mbedtls_ssl_context *ssl ) |
| { |
| const mbedtls_ssl_config *conf = ssl->conf; |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| if( mbedtls_ssl_conf_is_tls13_only( conf ) ) |
| { |
| if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS 1.3 is not yet supported." ) ); |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 4, ( "The SSL configuration is tls13 only." ) ); |
| return( 0 ); |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( mbedtls_ssl_conf_is_tls12_only( conf ) ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 4, ( "The SSL configuration is tls12 only." ) ); |
| return( 0 ); |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| if( mbedtls_ssl_conf_is_hybrid_tls12_tls13( conf ) ) |
| { |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS not yet supported in Hybrid TLS 1.3 + TLS 1.2" ) ); |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| if( conf->endpoint == MBEDTLS_SSL_IS_SERVER ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLS 1.3 server is not supported yet." ) ); |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| |
| MBEDTLS_SSL_DEBUG_MSG( 4, ( "The SSL configuration is TLS 1.3 or TLS 1.2." ) ); |
| return( 0 ); |
| } |
| #endif |
| |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "The SSL configuration is invalid." ) ); |
| return( MBEDTLS_ERR_SSL_BAD_CONFIG ); |
| } |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_conf_check(const mbedtls_ssl_context *ssl) |
| { |
| int ret; |
| ret = ssl_conf_version_check( ssl ); |
| if( ret != 0 ) |
| return( ret ); |
| |
| /* Space for further checks */ |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Setup an SSL context |
| */ |
| |
| int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, |
| const mbedtls_ssl_config *conf ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; |
| size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; |
| |
| ssl->conf = conf; |
| |
| if( ( ret = ssl_conf_check( ssl ) ) != 0 ) |
| return( ret ); |
| |
| /* |
| * Prepare base structures |
| */ |
| |
| /* Set to NULL in case of an error condition */ |
| ssl->out_buf = NULL; |
| |
| #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) |
| ssl->in_buf_len = in_buf_len; |
| #endif |
| ssl->in_buf = mbedtls_calloc( 1, in_buf_len ); |
| if( ssl->in_buf == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed", in_buf_len ) ); |
| ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; |
| goto error; |
| } |
| |
| #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) |
| ssl->out_buf_len = out_buf_len; |
| #endif |
| ssl->out_buf = mbedtls_calloc( 1, out_buf_len ); |
| if( ssl->out_buf == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed", out_buf_len ) ); |
| ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; |
| goto error; |
| } |
| |
| mbedtls_ssl_reset_in_out_pointers( ssl ); |
| |
| #if defined(MBEDTLS_SSL_DTLS_SRTP) |
| memset( &ssl->dtls_srtp_info, 0, sizeof(ssl->dtls_srtp_info) ); |
| #endif |
| |
| if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) |
| goto error; |
| |
| return( 0 ); |
| |
| error: |
| mbedtls_free( ssl->in_buf ); |
| mbedtls_free( ssl->out_buf ); |
| |
| ssl->conf = NULL; |
| |
| #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) |
| ssl->in_buf_len = 0; |
| ssl->out_buf_len = 0; |
| #endif |
| ssl->in_buf = NULL; |
| ssl->out_buf = NULL; |
| |
| ssl->in_hdr = NULL; |
| ssl->in_ctr = NULL; |
| ssl->in_len = NULL; |
| ssl->in_iv = NULL; |
| ssl->in_msg = NULL; |
| |
| ssl->out_hdr = NULL; |
| ssl->out_ctr = NULL; |
| ssl->out_len = NULL; |
| ssl->out_iv = NULL; |
| ssl->out_msg = NULL; |
| |
| return( ret ); |
| } |
| |
| /* |
| * Reset an initialized and used SSL context for re-use while retaining |
| * all application-set variables, function pointers and data. |
| * |
| * If partial is non-zero, keep data in the input buffer and client ID. |
| * (Use when a DTLS client reconnects from the same port.) |
| */ |
| void mbedtls_ssl_session_reset_msg_layer( mbedtls_ssl_context *ssl, |
| int partial ) |
| { |
| #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) |
| size_t in_buf_len = ssl->in_buf_len; |
| size_t out_buf_len = ssl->out_buf_len; |
| #else |
| size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; |
| size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; |
| #endif |
| |
| #if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || !defined(MBEDTLS_SSL_SRV_C) |
| partial = 0; |
| #endif |
| |
| /* Cancel any possibly running timer */ |
| mbedtls_ssl_set_timer( ssl, 0 ); |
| |
| mbedtls_ssl_reset_in_out_pointers( ssl ); |
| |
| /* Reset incoming message parsing */ |
| ssl->in_offt = NULL; |
| ssl->nb_zero = 0; |
| ssl->in_msgtype = 0; |
| ssl->in_msglen = 0; |
| ssl->in_hslen = 0; |
| ssl->keep_current_message = 0; |
| ssl->transform_in = NULL; |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| ssl->next_record_offset = 0; |
| ssl->in_epoch = 0; |
| #endif |
| |
| /* Keep current datagram if partial == 1 */ |
| if( partial == 0 ) |
| { |
| ssl->in_left = 0; |
| memset( ssl->in_buf, 0, in_buf_len ); |
| } |
| |
| ssl->send_alert = 0; |
| |
| /* Reset outgoing message writing */ |
| ssl->out_msgtype = 0; |
| ssl->out_msglen = 0; |
| ssl->out_left = 0; |
| memset( ssl->out_buf, 0, out_buf_len ); |
| memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) ); |
| ssl->transform_out = NULL; |
| |
| #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) |
| mbedtls_ssl_dtls_replay_reset( ssl ); |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( ssl->transform ) |
| { |
| mbedtls_ssl_transform_free( ssl->transform ); |
| mbedtls_free( ssl->transform ); |
| ssl->transform = NULL; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| mbedtls_ssl_transform_free( ssl->transform_application ); |
| mbedtls_free( ssl->transform_application ); |
| ssl->transform_application = NULL; |
| |
| if( ssl->handshake != NULL ) |
| { |
| mbedtls_ssl_transform_free( ssl->handshake->transform_earlydata ); |
| mbedtls_free( ssl->handshake->transform_earlydata ); |
| ssl->handshake->transform_earlydata = NULL; |
| |
| mbedtls_ssl_transform_free( ssl->handshake->transform_handshake ); |
| mbedtls_free( ssl->handshake->transform_handshake ); |
| ssl->handshake->transform_handshake = NULL; |
| } |
| |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ |
| } |
| |
| int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| ssl->state = MBEDTLS_SSL_HELLO_REQUEST; |
| |
| mbedtls_ssl_session_reset_msg_layer( ssl, partial ); |
| |
| /* Reset renegotiation state */ |
| #if defined(MBEDTLS_SSL_RENEGOTIATION) |
| ssl->renego_status = MBEDTLS_SSL_INITIAL_HANDSHAKE; |
| ssl->renego_records_seen = 0; |
| |
| ssl->verify_data_len = 0; |
| memset( ssl->own_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); |
| memset( ssl->peer_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); |
| #endif |
| ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; |
| |
| ssl->session_in = NULL; |
| ssl->session_out = NULL; |
| if( ssl->session ) |
| { |
| mbedtls_ssl_session_free( ssl->session ); |
| mbedtls_free( ssl->session ); |
| ssl->session = NULL; |
| } |
| |
| #if defined(MBEDTLS_SSL_ALPN) |
| ssl->alpn_chosen = NULL; |
| #endif |
| |
| #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) |
| #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) |
| if( partial == 0 ) |
| #endif |
| { |
| mbedtls_free( ssl->cli_id ); |
| ssl->cli_id = NULL; |
| ssl->cli_id_len = 0; |
| } |
| #endif |
| |
| if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) |
| return( ret ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Reset an initialized and used SSL context for re-use while retaining |
| * all application-set variables, function pointers and data. |
| */ |
| int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ) |
| { |
| return( mbedtls_ssl_session_reset_int( ssl, 0 ) ); |
| } |
| |
| /* |
| * SSL set accessors |
| */ |
| void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ) |
| { |
| conf->endpoint = endpoint; |
| } |
| |
| void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ) |
| { |
| conf->transport = transport; |
| } |
| |
| #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) |
| void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ) |
| { |
| conf->anti_replay = mode; |
| } |
| #endif |
| |
| void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ) |
| { |
| conf->badmac_limit = limit; |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| |
| void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl, |
| unsigned allow_packing ) |
| { |
| ssl->disable_datagram_packing = !allow_packing; |
| } |
| |
| void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, |
| uint32_t min, uint32_t max ) |
| { |
| conf->hs_timeout_min = min; |
| conf->hs_timeout_max = max; |
| } |
| #endif |
| |
| void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ) |
| { |
| conf->authmode = authmode; |
| } |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, |
| int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), |
| void *p_vrfy ) |
| { |
| conf->f_vrfy = f_vrfy; |
| conf->p_vrfy = p_vrfy; |
| } |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, |
| int (*f_rng)(void *, unsigned char *, size_t), |
| void *p_rng ) |
| { |
| conf->f_rng = f_rng; |
| conf->p_rng = p_rng; |
| } |
| |
| void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, |
| void (*f_dbg)(void *, int, const char *, int, const char *), |
| void *p_dbg ) |
| { |
| conf->f_dbg = f_dbg; |
| conf->p_dbg = p_dbg; |
| } |
| |
| void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, |
| void *p_bio, |
| mbedtls_ssl_send_t *f_send, |
| mbedtls_ssl_recv_t *f_recv, |
| mbedtls_ssl_recv_timeout_t *f_recv_timeout ) |
| { |
| ssl->p_bio = p_bio; |
| ssl->f_send = f_send; |
| ssl->f_recv = f_recv; |
| ssl->f_recv_timeout = f_recv_timeout; |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu ) |
| { |
| ssl->mtu = mtu; |
| } |
| #endif |
| |
| void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ) |
| { |
| conf->read_timeout = timeout; |
| } |
| |
| void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, |
| void *p_timer, |
| mbedtls_ssl_set_timer_t *f_set_timer, |
| mbedtls_ssl_get_timer_t *f_get_timer ) |
| { |
| ssl->p_timer = p_timer; |
| ssl->f_set_timer = f_set_timer; |
| ssl->f_get_timer = f_get_timer; |
| |
| /* Make sure we start with no timer running */ |
| mbedtls_ssl_set_timer( ssl, 0 ); |
| } |
| |
| #if defined(MBEDTLS_SSL_SRV_C) |
| void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, |
| void *p_cache, |
| mbedtls_ssl_cache_get_t *f_get_cache, |
| mbedtls_ssl_cache_set_t *f_set_cache ) |
| { |
| conf->p_cache = p_cache; |
| conf->f_get_cache = f_get_cache; |
| conf->f_set_cache = f_set_cache; |
| } |
| #endif /* MBEDTLS_SSL_SRV_C */ |
| |
| #if defined(MBEDTLS_SSL_CLI_C) |
| int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| if( ssl == NULL || |
| session == NULL || |
| ssl->session_negotiate == NULL || |
| ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| if( ssl->handshake->resume == 1 ) |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| |
| if( ( ret = mbedtls_ssl_session_copy( ssl->session_negotiate, |
| session ) ) != 0 ) |
| return( ret ); |
| |
| ssl->handshake->resume = 1; |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_CLI_C */ |
| |
| void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, |
| const int *ciphersuites ) |
| { |
| conf->ciphersuite_list = ciphersuites; |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| void mbedtls_ssl_conf_tls13_key_exchange_modes( mbedtls_ssl_config *conf, |
| const int kex_modes ) |
| { |
| conf->tls13_kex_modes = kex_modes & MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, |
| const mbedtls_x509_crt_profile *profile ) |
| { |
| conf->cert_profile = profile; |
| } |
| |
| static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) |
| { |
| mbedtls_ssl_key_cert *cur = key_cert, *next; |
| |
| while( cur != NULL ) |
| { |
| next = cur->next; |
| mbedtls_free( cur ); |
| cur = next; |
| } |
| } |
| |
| /* Append a new keycert entry to a (possibly empty) list */ |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, |
| mbedtls_x509_crt *cert, |
| mbedtls_pk_context *key ) |
| { |
| mbedtls_ssl_key_cert *new_cert; |
| |
| if( cert == NULL ) |
| { |
| /* Free list if cert is null */ |
| ssl_key_cert_free( *head ); |
| *head = NULL; |
| return( 0 ); |
| } |
| |
| new_cert = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); |
| if( new_cert == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| new_cert->cert = cert; |
| new_cert->key = key; |
| new_cert->next = NULL; |
| |
| /* Update head if the list was null, else add to the end */ |
| if( *head == NULL ) |
| { |
| *head = new_cert; |
| } |
| else |
| { |
| mbedtls_ssl_key_cert *cur = *head; |
| while( cur->next != NULL ) |
| cur = cur->next; |
| cur->next = new_cert; |
| } |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, |
| mbedtls_x509_crt *own_cert, |
| mbedtls_pk_context *pk_key ) |
| { |
| return( ssl_append_key_cert( &conf->key_cert, own_cert, pk_key ) ); |
| } |
| |
| void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, |
| mbedtls_x509_crt *ca_chain, |
| mbedtls_x509_crl *ca_crl ) |
| { |
| conf->ca_chain = ca_chain; |
| conf->ca_crl = ca_crl; |
| |
| #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) |
| /* mbedtls_ssl_conf_ca_chain() and mbedtls_ssl_conf_ca_cb() |
| * cannot be used together. */ |
| conf->f_ca_cb = NULL; |
| conf->p_ca_cb = NULL; |
| #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ |
| } |
| |
| #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) |
| void mbedtls_ssl_conf_ca_cb( mbedtls_ssl_config *conf, |
| mbedtls_x509_crt_ca_cb_t f_ca_cb, |
| void *p_ca_cb ) |
| { |
| conf->f_ca_cb = f_ca_cb; |
| conf->p_ca_cb = p_ca_cb; |
| |
| /* mbedtls_ssl_conf_ca_chain() and mbedtls_ssl_conf_ca_cb() |
| * cannot be used together. */ |
| conf->ca_chain = NULL; |
| conf->ca_crl = NULL; |
| } |
| #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) |
| const unsigned char *mbedtls_ssl_get_hs_sni( mbedtls_ssl_context *ssl, |
| size_t *name_len ) |
| { |
| *name_len = ssl->handshake->sni_name_len; |
| return( ssl->handshake->sni_name ); |
| } |
| |
| int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, |
| mbedtls_x509_crt *own_cert, |
| mbedtls_pk_context *pk_key ) |
| { |
| return( ssl_append_key_cert( &ssl->handshake->sni_key_cert, |
| own_cert, pk_key ) ); |
| } |
| |
| void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, |
| mbedtls_x509_crt *ca_chain, |
| mbedtls_x509_crl *ca_crl ) |
| { |
| ssl->handshake->sni_ca_chain = ca_chain; |
| ssl->handshake->sni_ca_crl = ca_crl; |
| } |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED) |
| void mbedtls_ssl_set_hs_dn_hints( mbedtls_ssl_context *ssl, |
| const mbedtls_x509_crt *crt) |
| { |
| ssl->handshake->dn_hints = crt; |
| } |
| #endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */ |
| |
| void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, |
| int authmode ) |
| { |
| ssl->handshake->sni_authmode = authmode; |
| } |
| #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl, |
| int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), |
| void *p_vrfy ) |
| { |
| ssl->f_vrfy = f_vrfy; |
| ssl->p_vrfy = p_vrfy; |
| } |
| #endif |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) |
| /* |
| * Set EC J-PAKE password for current handshake |
| */ |
| int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, |
| const unsigned char *pw, |
| size_t pw_len ) |
| { |
| mbedtls_ecjpake_role role; |
| |
| if( ssl->handshake == NULL || ssl->conf == NULL ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) |
| role = MBEDTLS_ECJPAKE_SERVER; |
| else |
| role = MBEDTLS_ECJPAKE_CLIENT; |
| |
| return( mbedtls_ecjpake_setup( &ssl->handshake->ecjpake_ctx, |
| role, |
| MBEDTLS_MD_SHA256, |
| MBEDTLS_ECP_DP_SECP256R1, |
| pw, pw_len ) ); |
| } |
| #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_conf_psk_is_configured( mbedtls_ssl_config const *conf ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| if( !mbedtls_svc_key_id_is_null( conf->psk_opaque ) ) |
| return( 1 ); |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| if( conf->psk != NULL ) |
| return( 1 ); |
| |
| return( 0 ); |
| } |
| |
| static void ssl_conf_remove_psk( mbedtls_ssl_config *conf ) |
| { |
| /* Remove reference to existing PSK, if any. */ |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| if( ! mbedtls_svc_key_id_is_null( conf->psk_opaque ) ) |
| { |
| /* The maintenance of the PSK key slot is the |
| * user's responsibility. */ |
| conf->psk_opaque = MBEDTLS_SVC_KEY_ID_INIT; |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| if( conf->psk != NULL ) |
| { |
| mbedtls_platform_zeroize( conf->psk, conf->psk_len ); |
| |
| mbedtls_free( conf->psk ); |
| conf->psk = NULL; |
| conf->psk_len = 0; |
| } |
| |
| /* Remove reference to PSK identity, if any. */ |
| if( conf->psk_identity != NULL ) |
| { |
| mbedtls_free( conf->psk_identity ); |
| conf->psk_identity = NULL; |
| conf->psk_identity_len = 0; |
| } |
| } |
| |
| /* This function assumes that PSK identity in the SSL config is unset. |
| * It checks that the provided identity is well-formed and attempts |
| * to make a copy of it in the SSL config. |
| * On failure, the PSK identity in the config remains unset. */ |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_conf_set_psk_identity( mbedtls_ssl_config *conf, |
| unsigned char const *psk_identity, |
| size_t psk_identity_len ) |
| { |
| /* Identity len will be encoded on two bytes */ |
| if( psk_identity == NULL || |
| ( psk_identity_len >> 16 ) != 0 || |
| psk_identity_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| conf->psk_identity = mbedtls_calloc( 1, psk_identity_len ); |
| if( conf->psk_identity == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| conf->psk_identity_len = psk_identity_len; |
| memcpy( conf->psk_identity, psk_identity, conf->psk_identity_len ); |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, |
| const unsigned char *psk, size_t psk_len, |
| const unsigned char *psk_identity, size_t psk_identity_len ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| /* We currently only support one PSK, raw or opaque. */ |
| if( ssl_conf_psk_is_configured( conf ) ) |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| |
| /* Check and set raw PSK */ |
| if( psk == NULL ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| if( psk_len == 0 ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| if( psk_len > MBEDTLS_PSK_MAX_LEN ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| conf->psk_len = psk_len; |
| memcpy( conf->psk, psk, conf->psk_len ); |
| |
| /* Check and set PSK Identity */ |
| ret = ssl_conf_set_psk_identity( conf, psk_identity, psk_identity_len ); |
| if( ret != 0 ) |
| ssl_conf_remove_psk( conf ); |
| |
| return( ret ); |
| } |
| |
| static void ssl_remove_psk( mbedtls_ssl_context *ssl ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| if( ! mbedtls_svc_key_id_is_null( ssl->handshake->psk_opaque ) ) |
| { |
| /* The maintenance of the external PSK key slot is the |
| * user's responsibility. */ |
| if( ssl->handshake->psk_opaque_is_internal ) |
| { |
| psa_destroy_key( ssl->handshake->psk_opaque ); |
| ssl->handshake->psk_opaque_is_internal = 0; |
| } |
| ssl->handshake->psk_opaque = MBEDTLS_SVC_KEY_ID_INIT; |
| } |
| #else |
| if( ssl->handshake->psk != NULL ) |
| { |
| mbedtls_platform_zeroize( ssl->handshake->psk, |
| ssl->handshake->psk_len ); |
| mbedtls_free( ssl->handshake->psk ); |
| ssl->handshake->psk_len = 0; |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| } |
| |
| int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, |
| const unsigned char *psk, size_t psk_len ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_key_attributes_t key_attributes = psa_key_attributes_init(); |
| psa_status_t status; |
| psa_algorithm_t alg; |
| mbedtls_svc_key_id_t key; |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| |
| if( psk == NULL || ssl->handshake == NULL ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| if( psk_len > MBEDTLS_PSK_MAX_LEN ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| ssl_remove_psk( ssl ); |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| if( ssl->handshake->ciphersuite_info->mac == MBEDTLS_MD_SHA384) |
| alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384); |
| else |
| alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256); |
| |
| psa_set_key_usage_flags( &key_attributes, PSA_KEY_USAGE_DERIVE ); |
| psa_set_key_algorithm( &key_attributes, alg ); |
| psa_set_key_type( &key_attributes, PSA_KEY_TYPE_DERIVE ); |
| |
| status = psa_import_key( &key_attributes, psk, psk_len, &key ); |
| if( status != PSA_SUCCESS ) |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| |
| /* Allow calling psa_destroy_key() on psk remove */ |
| ssl->handshake->psk_opaque_is_internal = 1; |
| return mbedtls_ssl_set_hs_psk_opaque( ssl, key ); |
| #else |
| if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| ssl->handshake->psk_len = psk_len; |
| memcpy( ssl->handshake->psk, psk, ssl->handshake->psk_len ); |
| |
| return( 0 ); |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| } |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf, |
| mbedtls_svc_key_id_t psk, |
| const unsigned char *psk_identity, |
| size_t psk_identity_len ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| /* We currently only support one PSK, raw or opaque. */ |
| if( ssl_conf_psk_is_configured( conf ) ) |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| |
| /* Check and set opaque PSK */ |
| if( mbedtls_svc_key_id_is_null( psk ) ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| conf->psk_opaque = psk; |
| |
| /* Check and set PSK Identity */ |
| ret = ssl_conf_set_psk_identity( conf, psk_identity, |
| psk_identity_len ); |
| if( ret != 0 ) |
| ssl_conf_remove_psk( conf ); |
| |
| return( ret ); |
| } |
| |
| int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl, |
| mbedtls_svc_key_id_t psk ) |
| { |
| if( ( mbedtls_svc_key_id_is_null( psk ) ) || |
| ( ssl->handshake == NULL ) ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| ssl_remove_psk( ssl ); |
| ssl->handshake->psk_opaque = psk; |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| |
| void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, |
| int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, |
| size_t), |
| void *p_psk ) |
| { |
| conf->f_psk = f_psk; |
| conf->p_psk = p_psk; |
| } |
| #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| static mbedtls_ssl_mode_t mbedtls_ssl_get_base_mode( |
| psa_algorithm_t alg ) |
| { |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) |
| if( alg == PSA_ALG_CBC_NO_PADDING ) |
| return( MBEDTLS_SSL_MODE_CBC ); |
| #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ |
| if( PSA_ALG_IS_AEAD( alg ) ) |
| return( MBEDTLS_SSL_MODE_AEAD ); |
| return( MBEDTLS_SSL_MODE_STREAM ); |
| } |
| |
| #else /* MBEDTLS_USE_PSA_CRYPTO */ |
| |
| static mbedtls_ssl_mode_t mbedtls_ssl_get_base_mode( |
| mbedtls_cipher_mode_t mode ) |
| { |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) |
| if( mode == MBEDTLS_MODE_CBC ) |
| return( MBEDTLS_SSL_MODE_CBC ); |
| #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ |
| |
| #if defined(MBEDTLS_GCM_C) || \ |
| defined(MBEDTLS_CCM_C) || \ |
| defined(MBEDTLS_CHACHAPOLY_C) |
| if( mode == MBEDTLS_MODE_GCM || |
| mode == MBEDTLS_MODE_CCM || |
| mode == MBEDTLS_MODE_CHACHAPOLY ) |
| return( MBEDTLS_SSL_MODE_AEAD ); |
| #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */ |
| |
| return( MBEDTLS_SSL_MODE_STREAM ); |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| |
| static mbedtls_ssl_mode_t mbedtls_ssl_get_actual_mode( |
| mbedtls_ssl_mode_t base_mode, |
| int encrypt_then_mac ) |
| { |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM) |
| if( encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED && |
| base_mode == MBEDTLS_SSL_MODE_CBC ) |
| { |
| return( MBEDTLS_SSL_MODE_CBC_ETM ); |
| } |
| #else |
| (void) encrypt_then_mac; |
| #endif |
| return( base_mode ); |
| } |
| |
| mbedtls_ssl_mode_t mbedtls_ssl_get_mode_from_transform( |
| const mbedtls_ssl_transform *transform ) |
| { |
| mbedtls_ssl_mode_t base_mode = mbedtls_ssl_get_base_mode( |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| transform->psa_alg |
| #else |
| mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ) |
| #endif |
| ); |
| |
| int encrypt_then_mac = 0; |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM) |
| encrypt_then_mac = transform->encrypt_then_mac; |
| #endif |
| return( mbedtls_ssl_get_actual_mode( base_mode, encrypt_then_mac ) ); |
| } |
| |
| mbedtls_ssl_mode_t mbedtls_ssl_get_mode_from_ciphersuite( |
| #if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM) |
| int encrypt_then_mac, |
| #endif /* MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM */ |
| const mbedtls_ssl_ciphersuite_t *suite ) |
| { |
| mbedtls_ssl_mode_t base_mode = MBEDTLS_SSL_MODE_STREAM; |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| psa_status_t status; |
| psa_algorithm_t alg; |
| psa_key_type_t type; |
| size_t size; |
| status = mbedtls_ssl_cipher_to_psa( suite->cipher, 0, &alg, &type, &size ); |
| if( status == PSA_SUCCESS ) |
| base_mode = mbedtls_ssl_get_base_mode( alg ); |
| #else |
| const mbedtls_cipher_info_t *cipher = |
| mbedtls_cipher_info_from_type( suite->cipher ); |
| if( cipher != NULL ) |
| { |
| base_mode = |
| mbedtls_ssl_get_base_mode( |
| mbedtls_cipher_info_get_mode( cipher ) ); |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| |
| #if !defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC_ETM) |
| int encrypt_then_mac = 0; |
| #endif |
| return( mbedtls_ssl_get_actual_mode( base_mode, encrypt_then_mac ) ); |
| } |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| psa_status_t mbedtls_ssl_cipher_to_psa( mbedtls_cipher_type_t mbedtls_cipher_type, |
| size_t taglen, |
| psa_algorithm_t *alg, |
| psa_key_type_t *key_type, |
| size_t *key_size ) |
| { |
| switch ( mbedtls_cipher_type ) |
| { |
| case MBEDTLS_CIPHER_AES_128_CBC: |
| *alg = PSA_ALG_CBC_NO_PADDING; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_AES_128_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_AES_128_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_AES_192_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 192; |
| break; |
| case MBEDTLS_CIPHER_AES_192_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 192; |
| break; |
| case MBEDTLS_CIPHER_AES_256_CBC: |
| *alg = PSA_ALG_CBC_NO_PADDING; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_AES_256_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_AES_256_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_AES; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_ARIA_128_CBC: |
| *alg = PSA_ALG_CBC_NO_PADDING; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_ARIA_128_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_ARIA_128_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_ARIA_192_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 192; |
| break; |
| case MBEDTLS_CIPHER_ARIA_192_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 192; |
| break; |
| case MBEDTLS_CIPHER_ARIA_256_CBC: |
| *alg = PSA_ALG_CBC_NO_PADDING; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_ARIA_256_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_ARIA_256_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_ARIA; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_128_CBC: |
| *alg = PSA_ALG_CBC_NO_PADDING; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_128_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_128_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 128; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_192_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 192; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_192_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 192; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_256_CBC: |
| *alg = PSA_ALG_CBC_NO_PADDING; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_256_CCM: |
| *alg = taglen ? PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, taglen ) : PSA_ALG_CCM; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_CAMELLIA_256_GCM: |
| *alg = PSA_ALG_GCM; |
| *key_type = PSA_KEY_TYPE_CAMELLIA; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_CHACHA20_POLY1305: |
| *alg = PSA_ALG_CHACHA20_POLY1305; |
| *key_type = PSA_KEY_TYPE_CHACHA20; |
| *key_size = 256; |
| break; |
| case MBEDTLS_CIPHER_NULL: |
| *alg = MBEDTLS_SSL_NULL_CIPHER; |
| *key_type = 0; |
| *key_size = 0; |
| break; |
| default: |
| return PSA_ERROR_NOT_SUPPORTED; |
| } |
| |
| return PSA_SUCCESS; |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */ |
| |
| #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) |
| int mbedtls_ssl_conf_dh_param_bin( mbedtls_ssl_config *conf, |
| const unsigned char *dhm_P, size_t P_len, |
| const unsigned char *dhm_G, size_t G_len ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| mbedtls_mpi_free( &conf->dhm_P ); |
| mbedtls_mpi_free( &conf->dhm_G ); |
| |
| if( ( ret = mbedtls_mpi_read_binary( &conf->dhm_P, dhm_P, P_len ) ) != 0 || |
| ( ret = mbedtls_mpi_read_binary( &conf->dhm_G, dhm_G, G_len ) ) != 0 ) |
| { |
| mbedtls_mpi_free( &conf->dhm_P ); |
| mbedtls_mpi_free( &conf->dhm_G ); |
| return( ret ); |
| } |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| mbedtls_mpi_free( &conf->dhm_P ); |
| mbedtls_mpi_free( &conf->dhm_G ); |
| |
| if( ( ret = mbedtls_dhm_get_value( dhm_ctx, MBEDTLS_DHM_PARAM_P, |
| &conf->dhm_P ) ) != 0 || |
| ( ret = mbedtls_dhm_get_value( dhm_ctx, MBEDTLS_DHM_PARAM_G, |
| &conf->dhm_G ) ) != 0 ) |
| { |
| mbedtls_mpi_free( &conf->dhm_P ); |
| mbedtls_mpi_free( &conf->dhm_G ); |
| return( ret ); |
| } |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_SRV_C */ |
| |
| #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) |
| /* |
| * Set the minimum length for Diffie-Hellman parameters |
| */ |
| void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, |
| unsigned int bitlen ) |
| { |
| conf->dhm_min_bitlen = bitlen; |
| } |
| #endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) |
| #if !defined(MBEDTLS_DEPRECATED_REMOVED) && defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| /* |
| * Set allowed/preferred hashes for handshake signatures |
| */ |
| void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, |
| const int *hashes ) |
| { |
| conf->sig_hashes = hashes; |
| } |
| #endif /* !MBEDTLS_DEPRECATED_REMOVED && MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| /* Configure allowed signature algorithms for handshake */ |
| void mbedtls_ssl_conf_sig_algs( mbedtls_ssl_config *conf, |
| const uint16_t* sig_algs ) |
| { |
| #if !defined(MBEDTLS_DEPRECATED_REMOVED) |
| conf->sig_hashes = NULL; |
| #endif /* !MBEDTLS_DEPRECATED_REMOVED */ |
| conf->sig_algs = sig_algs; |
| } |
| #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ |
| |
| #if defined(MBEDTLS_ECP_C) |
| #if !defined(MBEDTLS_DEPRECATED_REMOVED) |
| /* |
| * Set the allowed elliptic curves |
| * |
| * mbedtls_ssl_setup() takes the provided list |
| * and translates it to a list of IANA TLS group identifiers, |
| * stored in ssl->handshake->group_list. |
| * |
| */ |
| void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, |
| const mbedtls_ecp_group_id *curve_list ) |
| { |
| conf->curve_list = curve_list; |
| conf->group_list = NULL; |
| } |
| #endif /* MBEDTLS_DEPRECATED_REMOVED */ |
| #endif /* MBEDTLS_ECP_C */ |
| |
| /* |
| * Set the allowed groups |
| */ |
| void mbedtls_ssl_conf_groups( mbedtls_ssl_config *conf, |
| const uint16_t *group_list ) |
| { |
| #if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_DEPRECATED_REMOVED) |
| conf->curve_list = NULL; |
| #endif |
| conf->group_list = group_list; |
| } |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) |
| { |
| /* Initialize to suppress unnecessary compiler warning */ |
| size_t hostname_len = 0; |
| |
| /* Check if new hostname is valid before |
| * making any change to current one */ |
| if( hostname != NULL ) |
| { |
| hostname_len = strlen( hostname ); |
| |
| if( hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| /* Now it's clear that we will overwrite the old hostname, |
| * so we can free it safely */ |
| |
| if( ssl->hostname != NULL ) |
| { |
| mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) ); |
| mbedtls_free( ssl->hostname ); |
| } |
| |
| /* Passing NULL as hostname shall clear the old one */ |
| |
| if( hostname == NULL ) |
| { |
| ssl->hostname = NULL; |
| } |
| else |
| { |
| ssl->hostname = mbedtls_calloc( 1, hostname_len + 1 ); |
| if( ssl->hostname == NULL ) |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| |
| memcpy( ssl->hostname, hostname, hostname_len ); |
| |
| ssl->hostname[hostname_len] = '\0'; |
| } |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) |
| void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, |
| int (*f_sni)(void *, mbedtls_ssl_context *, |
| const unsigned char *, size_t), |
| void *p_sni ) |
| { |
| conf->f_sni = f_sni; |
| conf->p_sni = p_sni; |
| } |
| #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ |
| |
| #if defined(MBEDTLS_SSL_ALPN) |
| int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ) |
| { |
| size_t cur_len, tot_len; |
| const char **p; |
| |
| /* |
| * RFC 7301 3.1: "Empty strings MUST NOT be included and byte strings |
| * MUST NOT be truncated." |
| * We check lengths now rather than later. |
| */ |
| tot_len = 0; |
| for( p = protos; *p != NULL; p++ ) |
| { |
| cur_len = strlen( *p ); |
| tot_len += cur_len; |
| |
| if( ( cur_len == 0 ) || |
| ( cur_len > MBEDTLS_SSL_MAX_ALPN_NAME_LEN ) || |
| ( tot_len > MBEDTLS_SSL_MAX_ALPN_LIST_LEN ) ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| conf->alpn_list = protos; |
| |
| return( 0 ); |
| } |
| |
| const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ) |
| { |
| return( ssl->alpn_chosen ); |
| } |
| #endif /* MBEDTLS_SSL_ALPN */ |
| |
| #if defined(MBEDTLS_SSL_DTLS_SRTP) |
| void mbedtls_ssl_conf_srtp_mki_value_supported( mbedtls_ssl_config *conf, |
| int support_mki_value ) |
| { |
| conf->dtls_srtp_mki_support = support_mki_value; |
| } |
| |
| int mbedtls_ssl_dtls_srtp_set_mki_value( mbedtls_ssl_context *ssl, |
| unsigned char *mki_value, |
| uint16_t mki_len ) |
| { |
| if( mki_len > MBEDTLS_TLS_SRTP_MAX_MKI_LENGTH ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| if( ssl->conf->dtls_srtp_mki_support == MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED ) |
| { |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| memcpy( ssl->dtls_srtp_info.mki_value, mki_value, mki_len ); |
| ssl->dtls_srtp_info.mki_len = mki_len; |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_conf_dtls_srtp_protection_profiles( mbedtls_ssl_config *conf, |
| const mbedtls_ssl_srtp_profile *profiles ) |
| { |
| const mbedtls_ssl_srtp_profile *p; |
| size_t list_size = 0; |
| |
| /* check the profiles list: all entry must be valid, |
| * its size cannot be more than the total number of supported profiles, currently 4 */ |
| for( p = profiles; *p != MBEDTLS_TLS_SRTP_UNSET && |
| list_size <= MBEDTLS_TLS_SRTP_MAX_PROFILE_LIST_LENGTH; |
| p++ ) |
| { |
| if( mbedtls_ssl_check_srtp_profile_value( *p ) != MBEDTLS_TLS_SRTP_UNSET ) |
| { |
| list_size++; |
| } |
| else |
| { |
| /* unsupported value, stop parsing and set the size to an error value */ |
| list_size = MBEDTLS_TLS_SRTP_MAX_PROFILE_LIST_LENGTH + 1; |
| } |
| } |
| |
| if( list_size > MBEDTLS_TLS_SRTP_MAX_PROFILE_LIST_LENGTH ) |
| { |
| conf->dtls_srtp_profile_list = NULL; |
| conf->dtls_srtp_profile_list_len = 0; |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| conf->dtls_srtp_profile_list = profiles; |
| conf->dtls_srtp_profile_list_len = list_size; |
| |
| return( 0 ); |
| } |
| |
| void mbedtls_ssl_get_dtls_srtp_negotiation_result( const mbedtls_ssl_context *ssl, |
| mbedtls_dtls_srtp_info *dtls_srtp_info ) |
| { |
| dtls_srtp_info->chosen_dtls_srtp_profile = ssl->dtls_srtp_info.chosen_dtls_srtp_profile; |
| /* do not copy the mki value if there is no chosen profile */ |
| if( dtls_srtp_info->chosen_dtls_srtp_profile == MBEDTLS_TLS_SRTP_UNSET ) |
| { |
| dtls_srtp_info->mki_len = 0; |
| } |
| else |
| { |
| dtls_srtp_info->mki_len = ssl->dtls_srtp_info.mki_len; |
| memcpy( dtls_srtp_info->mki_value, ssl->dtls_srtp_info.mki_value, |
| ssl->dtls_srtp_info.mki_len ); |
| } |
| } |
| #endif /* MBEDTLS_SSL_DTLS_SRTP */ |
| |
| void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ) |
| { |
| conf->max_tls_version = (major << 8) | minor; |
| } |
| |
| void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ) |
| { |
| conf->min_tls_version = (major << 8) | minor; |
| } |
| |
| #if defined(MBEDTLS_SSL_SRV_C) |
| void mbedtls_ssl_conf_cert_req_ca_list( mbedtls_ssl_config *conf, |
| char cert_req_ca_list ) |
| { |
| conf->cert_req_ca_list = cert_req_ca_list; |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ) |
| { |
| conf->encrypt_then_mac = etm; |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) |
| void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ) |
| { |
| conf->extended_ms = ems; |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ) |
| { |
| if( mfl_code >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID || |
| ssl_mfl_code_to_length( mfl_code ) > MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| conf->mfl_code = mfl_code; |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ |
| |
| void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ) |
| { |
| conf->allow_legacy_renegotiation = allow_legacy; |
| } |
| |
| #if defined(MBEDTLS_SSL_RENEGOTIATION) |
| void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ) |
| { |
| conf->disable_renegotiation = renegotiation; |
| } |
| |
| void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ) |
| { |
| conf->renego_max_records = max_records; |
| } |
| |
| void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, |
| const unsigned char period[8] ) |
| { |
| memcpy( conf->renego_period, period, 8 ); |
| } |
| #endif /* MBEDTLS_SSL_RENEGOTIATION */ |
| |
| #if defined(MBEDTLS_SSL_SESSION_TICKETS) |
| #if defined(MBEDTLS_SSL_CLI_C) |
| void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) |
| { |
| conf->session_tickets = use_tickets; |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_SRV_C) |
| void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, |
| mbedtls_ssl_ticket_write_t *f_ticket_write, |
| mbedtls_ssl_ticket_parse_t *f_ticket_parse, |
| void *p_ticket ) |
| { |
| conf->f_ticket_write = f_ticket_write; |
| conf->f_ticket_parse = f_ticket_parse; |
| conf->p_ticket = p_ticket; |
| } |
| #endif |
| #endif /* MBEDTLS_SSL_SESSION_TICKETS */ |
| |
| void mbedtls_ssl_set_export_keys_cb( mbedtls_ssl_context *ssl, |
| mbedtls_ssl_export_keys_t *f_export_keys, |
| void *p_export_keys ) |
| { |
| ssl->f_export_keys = f_export_keys; |
| ssl->p_export_keys = p_export_keys; |
| } |
| |
| #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) |
| void mbedtls_ssl_conf_async_private_cb( |
| mbedtls_ssl_config *conf, |
| mbedtls_ssl_async_sign_t *f_async_sign, |
| mbedtls_ssl_async_decrypt_t *f_async_decrypt, |
| mbedtls_ssl_async_resume_t *f_async_resume, |
| mbedtls_ssl_async_cancel_t *f_async_cancel, |
| void *async_config_data ) |
| { |
| conf->f_async_sign_start = f_async_sign; |
| conf->f_async_decrypt_start = f_async_decrypt; |
| conf->f_async_resume = f_async_resume; |
| conf->f_async_cancel = f_async_cancel; |
| conf->p_async_config_data = async_config_data; |
| } |
| |
| void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ) |
| { |
| return( conf->p_async_config_data ); |
| } |
| |
| void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ) |
| { |
| if( ssl->handshake == NULL ) |
| return( NULL ); |
| else |
| return( ssl->handshake->user_async_ctx ); |
| } |
| |
| void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, |
| void *ctx ) |
| { |
| if( ssl->handshake != NULL ) |
| ssl->handshake->user_async_ctx = ctx; |
| } |
| #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ |
| |
| /* |
| * SSL get accessors |
| */ |
| uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ) |
| { |
| if( ssl->session != NULL ) |
| return( ssl->session->verify_result ); |
| |
| if( ssl->session_negotiate != NULL ) |
| return( ssl->session_negotiate->verify_result ); |
| |
| return( 0xFFFFFFFF ); |
| } |
| |
| int mbedtls_ssl_get_ciphersuite_id_from_ssl( const mbedtls_ssl_context *ssl ) |
| { |
| if( ssl == NULL || ssl->session == NULL ) |
| return( 0 ); |
| |
| return( ssl->session->ciphersuite ); |
| } |
| |
| const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ) |
| { |
| if( ssl == NULL || ssl->session == NULL ) |
| return( NULL ); |
| |
| return mbedtls_ssl_get_ciphersuite_name( ssl->session->ciphersuite ); |
| } |
| |
| const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| switch( ssl->tls_version ) |
| { |
| case MBEDTLS_SSL_VERSION_TLS1_2: |
| return( "DTLSv1.2" ); |
| default: |
| return( "unknown (DTLS)" ); |
| } |
| } |
| #endif |
| |
| switch( ssl->tls_version ) |
| { |
| case MBEDTLS_SSL_VERSION_TLS1_2: |
| return( "TLSv1.2" ); |
| case MBEDTLS_SSL_VERSION_TLS1_3: |
| return( "TLSv1.3" ); |
| default: |
| return( "unknown" ); |
| } |
| } |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| size_t mbedtls_ssl_get_input_max_frag_len( const mbedtls_ssl_context *ssl ) |
| { |
| size_t max_len = MBEDTLS_SSL_IN_CONTENT_LEN; |
| size_t read_mfl; |
| |
| /* Use the configured MFL for the client if we're past SERVER_HELLO_DONE */ |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && |
| ssl->state >= MBEDTLS_SSL_SERVER_HELLO_DONE ) |
| { |
| return ssl_mfl_code_to_length( ssl->conf->mfl_code ); |
| } |
| |
| /* Check if a smaller max length was negotiated */ |
| if( ssl->session_out != NULL ) |
| { |
| read_mfl = ssl_mfl_code_to_length( ssl->session_out->mfl_code ); |
| if( read_mfl < max_len ) |
| { |
| max_len = read_mfl; |
| } |
| } |
| |
| // During a handshake, use the value being negotiated |
| if( ssl->session_negotiate != NULL ) |
| { |
| read_mfl = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ); |
| if( read_mfl < max_len ) |
| { |
| max_len = read_mfl; |
| } |
| } |
| |
| return( max_len ); |
| } |
| |
| size_t mbedtls_ssl_get_output_max_frag_len( const mbedtls_ssl_context *ssl ) |
| { |
| size_t max_len; |
| |
| /* |
| * Assume mfl_code is correct since it was checked when set |
| */ |
| max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code ); |
| |
| /* Check if a smaller max length was negotiated */ |
| if( ssl->session_out != NULL && |
| ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len ) |
| { |
| max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code ); |
| } |
| |
| /* During a handshake, use the value being negotiated */ |
| if( ssl->session_negotiate != NULL && |
| ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ) < max_len ) |
| { |
| max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ); |
| } |
| |
| return( max_len ); |
| } |
| #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| size_t mbedtls_ssl_get_current_mtu( const mbedtls_ssl_context *ssl ) |
| { |
| /* Return unlimited mtu for client hello messages to avoid fragmentation. */ |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && |
| ( ssl->state == MBEDTLS_SSL_CLIENT_HELLO || |
| ssl->state == MBEDTLS_SSL_SERVER_HELLO ) ) |
| return ( 0 ); |
| |
| if( ssl->handshake == NULL || ssl->handshake->mtu == 0 ) |
| return( ssl->mtu ); |
| |
| if( ssl->mtu == 0 ) |
| return( ssl->handshake->mtu ); |
| |
| return( ssl->mtu < ssl->handshake->mtu ? |
| ssl->mtu : ssl->handshake->mtu ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ) |
| { |
| size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; |
| |
| #if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \ |
| !defined(MBEDTLS_SSL_PROTO_DTLS) |
| (void) ssl; |
| #endif |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| const size_t mfl = mbedtls_ssl_get_output_max_frag_len( ssl ); |
| |
| if( max_len > mfl ) |
| max_len = mfl; |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( mbedtls_ssl_get_current_mtu( ssl ) != 0 ) |
| { |
| const size_t mtu = mbedtls_ssl_get_current_mtu( ssl ); |
| const int ret = mbedtls_ssl_get_record_expansion( ssl ); |
| const size_t overhead = (size_t) ret; |
| |
| if( ret < 0 ) |
| return( ret ); |
| |
| if( mtu <= overhead ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "MTU too low for record expansion" ) ); |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| if( max_len > mtu - overhead ) |
| max_len = mtu - overhead; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| #if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \ |
| !defined(MBEDTLS_SSL_PROTO_DTLS) |
| ((void) ssl); |
| #endif |
| |
| return( (int) max_len ); |
| } |
| |
| int mbedtls_ssl_get_max_in_record_payload( const mbedtls_ssl_context *ssl ) |
| { |
| size_t max_len = MBEDTLS_SSL_IN_CONTENT_LEN; |
| |
| #if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| (void) ssl; |
| #endif |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| const size_t mfl = mbedtls_ssl_get_input_max_frag_len( ssl ); |
| |
| if( max_len > mfl ) |
| max_len = mfl; |
| #endif |
| |
| return( (int) max_len ); |
| } |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ) |
| { |
| if( ssl == NULL || ssl->session == NULL ) |
| return( NULL ); |
| |
| #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) |
| return( ssl->session->peer_cert ); |
| #else |
| return( NULL ); |
| #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ |
| } |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| #if defined(MBEDTLS_SSL_CLI_C) |
| int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, |
| mbedtls_ssl_session *dst ) |
| { |
| int ret; |
| |
| if( ssl == NULL || |
| dst == NULL || |
| ssl->session == NULL || |
| ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| /* Since Mbed TLS 3.0, mbedtls_ssl_get_session() is no longer |
| * idempotent: Each session can only be exported once. |
| * |
| * (This is in preparation for TLS 1.3 support where we will |
| * need the ability to export multiple sessions (aka tickets), |
| * which will be achieved by calling mbedtls_ssl_get_session() |
| * multiple times until it fails.) |
| * |
| * Check whether we have already exported the current session, |
| * and fail if so. |
| */ |
| if( ssl->session->exported == 1 ) |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| |
| ret = mbedtls_ssl_session_copy( dst, ssl->session ); |
| if( ret != 0 ) |
| return( ret ); |
| |
| /* Remember that we've exported the session. */ |
| ssl->session->exported = 1; |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_CLI_C */ |
| |
| /* |
| * Define ticket header determining Mbed TLS version |
| * and structure of the ticket. |
| */ |
| |
| /* |
| * Define bitflag determining compile-time settings influencing |
| * structure of serialized SSL sessions. |
| */ |
| |
| #if defined(MBEDTLS_HAVE_TIME) |
| #define SSL_SERIALIZED_SESSION_CONFIG_TIME 1 |
| #else |
| #define SSL_SERIALIZED_SESSION_CONFIG_TIME 0 |
| #endif /* MBEDTLS_HAVE_TIME */ |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) |
| #define SSL_SERIALIZED_SESSION_CONFIG_CRT 1 |
| #else |
| #define SSL_SERIALIZED_SESSION_CONFIG_CRT 0 |
| #endif /* MBEDTLS_X509_CRT_PARSE_C */ |
| |
| #if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SESSION_TICKETS) |
| #define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET 1 |
| #else |
| #define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET 0 |
| #endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_SESSION_TICKETS */ |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| #define SSL_SERIALIZED_SESSION_CONFIG_MFL 1 |
| #else |
| #define SSL_SERIALIZED_SESSION_CONFIG_MFL 0 |
| #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ |
| |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| #define SSL_SERIALIZED_SESSION_CONFIG_ETM 1 |
| #else |
| #define SSL_SERIALIZED_SESSION_CONFIG_ETM 0 |
| #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ |
| |
| #if defined(MBEDTLS_SSL_SESSION_TICKETS) |
| #define SSL_SERIALIZED_SESSION_CONFIG_TICKET 1 |
| #else |
| #define SSL_SERIALIZED_SESSION_CONFIG_TICKET 0 |
| #endif /* MBEDTLS_SSL_SESSION_TICKETS */ |
| |
| #define SSL_SERIALIZED_SESSION_CONFIG_TIME_BIT 0 |
| #define SSL_SERIALIZED_SESSION_CONFIG_CRT_BIT 1 |
| #define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT 2 |
| #define SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT 3 |
| #define SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT 4 |
| #define SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT 5 |
| |
| #define SSL_SERIALIZED_SESSION_CONFIG_BITFLAG \ |
| ( (uint16_t) ( \ |
| ( SSL_SERIALIZED_SESSION_CONFIG_TIME << SSL_SERIALIZED_SESSION_CONFIG_TIME_BIT ) | \ |
| ( SSL_SERIALIZED_SESSION_CONFIG_CRT << SSL_SERIALIZED_SESSION_CONFIG_CRT_BIT ) | \ |
| ( SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET << SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT ) | \ |
| ( SSL_SERIALIZED_SESSION_CONFIG_MFL << SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT ) | \ |
| ( SSL_SERIALIZED_SESSION_CONFIG_ETM << SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT ) | \ |
| ( SSL_SERIALIZED_SESSION_CONFIG_TICKET << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT ) ) ) |
| |
| static unsigned char ssl_serialized_session_header[] = { |
| MBEDTLS_VERSION_MAJOR, |
| MBEDTLS_VERSION_MINOR, |
| MBEDTLS_VERSION_PATCH, |
| MBEDTLS_BYTE_1( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG ), |
| MBEDTLS_BYTE_0( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG ), |
| }; |
| |
| /* |
| * Serialize a session in the following format: |
| * (in the presentation language of TLS, RFC 8446 section 3) |
| * |
| * struct { |
| * |
| * opaque mbedtls_version[3]; // library version: major, minor, patch |
| * opaque session_format[2]; // library-version specific 16-bit field |
| * // determining the format of the remaining |
| * // serialized data. |
| * |
| * Note: When updating the format, remember to keep |
| * these version+format bytes. |
| * |
| * // In this version, `session_format` determines |
| * // the setting of those compile-time |
| * // configuration options which influence |
| * // the structure of mbedtls_ssl_session. |
| * |
| * uint8_t minor_ver; // Protocol minor version. Possible values: |
| * // - TLS 1.2 (3) |
| * |
| * select (serialized_session.tls_version) { |
| * |
| * case MBEDTLS_SSL_VERSION_TLS1_2: |
| * serialized_session_tls12 data; |
| * |
| * }; |
| * |
| * } serialized_session; |
| * |
| */ |
| |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_session_save( const mbedtls_ssl_session *session, |
| unsigned char omit_header, |
| unsigned char *buf, |
| size_t buf_len, |
| size_t *olen ) |
| { |
| unsigned char *p = buf; |
| size_t used = 0; |
| |
| if( !omit_header ) |
| { |
| /* |
| * Add Mbed TLS version identifier |
| */ |
| |
| used += sizeof( ssl_serialized_session_header ); |
| |
| if( used <= buf_len ) |
| { |
| memcpy( p, ssl_serialized_session_header, |
| sizeof( ssl_serialized_session_header ) ); |
| p += sizeof( ssl_serialized_session_header ); |
| } |
| } |
| |
| /* |
| * TLS version identifier |
| */ |
| used += 1; |
| if( used <= buf_len ) |
| { |
| *p++ = MBEDTLS_BYTE_0( session->tls_version ); |
| } |
| |
| /* Forward to version-specific serialization routine. */ |
| switch( session->tls_version ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| case MBEDTLS_SSL_VERSION_TLS1_2: |
| { |
| size_t remaining_len = used <= buf_len ? buf_len - used : 0; |
| used += ssl_session_save_tls12( session, p, remaining_len ); |
| break; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| default: |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| *olen = used; |
| if( used > buf_len ) |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Public wrapper for ssl_session_save() |
| */ |
| int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, |
| unsigned char *buf, |
| size_t buf_len, |
| size_t *olen ) |
| { |
| return( ssl_session_save( session, 0, buf, buf_len, olen ) ); |
| } |
| |
| /* |
| * Deserialize session, see mbedtls_ssl_session_save() for format. |
| * |
| * This internal version is wrapped by a public function that cleans up in |
| * case of error, and has an extra option omit_header. |
| */ |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_session_load( mbedtls_ssl_session *session, |
| unsigned char omit_header, |
| const unsigned char *buf, |
| size_t len ) |
| { |
| const unsigned char *p = buf; |
| const unsigned char * const end = buf + len; |
| |
| if( !omit_header ) |
| { |
| /* |
| * Check Mbed TLS version identifier |
| */ |
| |
| if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| if( memcmp( p, ssl_serialized_session_header, |
| sizeof( ssl_serialized_session_header ) ) != 0 ) |
| { |
| return( MBEDTLS_ERR_SSL_VERSION_MISMATCH ); |
| } |
| p += sizeof( ssl_serialized_session_header ); |
| } |
| |
| /* |
| * TLS version identifier |
| */ |
| if( 1 > (size_t)( end - p ) ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| session->tls_version = 0x0300 | *p++; |
| |
| /* Dispatch according to TLS version. */ |
| switch( session->tls_version ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| case MBEDTLS_SSL_VERSION_TLS1_2: |
| { |
| size_t remaining_len = ( end - p ); |
| return( ssl_session_load_tls12( session, p, remaining_len ) ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| default: |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| } |
| |
| /* |
| * Deserialize session: public wrapper for error cleaning |
| */ |
| int mbedtls_ssl_session_load( mbedtls_ssl_session *session, |
| const unsigned char *buf, |
| size_t len ) |
| { |
| int ret = ssl_session_load( session, 0, buf, len ); |
| |
| if( ret != 0 ) |
| mbedtls_ssl_session_free( session ); |
| |
| return( ret ); |
| } |
| |
| /* |
| * Perform a single step of the SSL handshake |
| */ |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_prepare_handshake_step( mbedtls_ssl_context *ssl ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| /* |
| * We may have not been able to send to the peer all the handshake data |
| * that were written into the output buffer by the previous handshake step, |
| * if the write to the network callback returned with the |
| * #MBEDTLS_ERR_SSL_WANT_WRITE error code. |
| * We proceed to the next handshake step only when all data from the |
| * previous one have been sent to the peer, thus we make sure that this is |
| * the case here by calling `mbedtls_ssl_flush_output()`. The function may |
| * return with the #MBEDTLS_ERR_SSL_WANT_WRITE error code in which case |
| * we have to wait before to go ahead. |
| * In the case of TLS 1.3, handshake step handlers do not send data to the |
| * peer. Data are only sent here and through |
| * `mbedtls_ssl_handle_pending_alert` in case an error that triggered an |
| * alert occurred. |
| */ |
| if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) |
| return( ret ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && |
| ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) |
| { |
| if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) |
| return( ret ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| return( ret ); |
| } |
| |
| int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| if( ssl == NULL || |
| ssl->conf == NULL || |
| ssl->handshake == NULL || |
| mbedtls_ssl_is_handshake_over( ssl ) == 1 ) |
| { |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| ret = ssl_prepare_handshake_step( ssl ); |
| if( ret != 0 ) |
| return( ret ); |
| |
| ret = mbedtls_ssl_handle_pending_alert( ssl ); |
| if( ret != 0 ) |
| goto cleanup; |
| |
| #if defined(MBEDTLS_SSL_CLI_C) |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %s", |
| mbedtls_ssl_states_str( ssl->state ) ) ); |
| |
| switch( ssl->state ) |
| { |
| case MBEDTLS_SSL_HELLO_REQUEST: |
| ssl->state = MBEDTLS_SSL_CLIENT_HELLO; |
| break; |
| |
| case MBEDTLS_SSL_CLIENT_HELLO: |
| ret = mbedtls_ssl_write_client_hello( ssl ); |
| break; |
| |
| default: |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| if( ssl->tls_version == MBEDTLS_SSL_VERSION_TLS1_3 ) |
| ret = mbedtls_ssl_tls13_handshake_client_step( ssl ); |
| else |
| ret = mbedtls_ssl_handshake_client_step( ssl ); |
| #elif defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| ret = mbedtls_ssl_handshake_client_step( ssl ); |
| #else |
| ret = mbedtls_ssl_tls13_handshake_client_step( ssl ); |
| #endif |
| } |
| } |
| #endif |
| #if defined(MBEDTLS_SSL_SRV_C) |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_3) |
| if( mbedtls_ssl_conf_is_tls13_only( ssl->conf ) ) |
| ret = mbedtls_ssl_tls13_handshake_server_step( ssl ); |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( mbedtls_ssl_conf_is_tls12_only( ssl->conf ) ) |
| ret = mbedtls_ssl_handshake_server_step( ssl ); |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| } |
| #endif |
| |
| if( ret != 0 ) |
| { |
| /* handshake_step return error. And it is same |
| * with alert_reason. |
| */ |
| if( ssl->send_alert ) |
| { |
| ret = mbedtls_ssl_handle_pending_alert( ssl ); |
| goto cleanup; |
| } |
| } |
| |
| cleanup: |
| return( ret ); |
| } |
| |
| /* |
| * Perform the SSL handshake |
| */ |
| int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ) |
| { |
| int ret = 0; |
| |
| /* Sanity checks */ |
| |
| if( ssl == NULL || ssl->conf == NULL ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && |
| ( ssl->f_set_timer == NULL || ssl->f_get_timer == NULL ) ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "You must use " |
| "mbedtls_ssl_set_timer_cb() for DTLS" ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); |
| |
| /* Main handshake loop */ |
| while( mbedtls_ssl_is_handshake_over( ssl ) == 0 ) |
| { |
| ret = mbedtls_ssl_handshake_step( ssl ); |
| |
| if( ret != 0 ) |
| break; |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); |
| |
| return( ret ); |
| } |
| |
| #if defined(MBEDTLS_SSL_RENEGOTIATION) |
| #if defined(MBEDTLS_SSL_SRV_C) |
| /* |
| * Write HelloRequest to request renegotiation on server |
| */ |
| MBEDTLS_CHECK_RETURN_CRITICAL |
| static int ssl_write_hello_request( mbedtls_ssl_context *ssl ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello request" ) ); |
| |
| ssl->out_msglen = 4; |
| ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; |
| ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST; |
| |
| if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); |
| return( ret ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello request" ) ); |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_SRV_C */ |
| |
| /* |
| * Actually renegotiate current connection, triggered by either: |
| * - any side: calling mbedtls_ssl_renegotiate(), |
| * - client: receiving a HelloRequest during mbedtls_ssl_read(), |
| * - server: receiving any handshake message on server during mbedtls_ssl_read() after |
| * the initial handshake is completed. |
| * If the handshake doesn't complete due to waiting for I/O, it will continue |
| * during the next calls to mbedtls_ssl_renegotiate() or mbedtls_ssl_read() respectively. |
| */ |
| int mbedtls_ssl_start_renegotiation( mbedtls_ssl_context *ssl ) |
| { |
| int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> renegotiate" ) ); |
| |
| if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) |
| return( ret ); |
| |
| /* RFC 6347 4.2.2: "[...] the HelloRequest will have message_seq = 0 and |
| * the ServerHello will have message_seq = 1" */ |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && |
| ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) |
| { |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) |
| ssl->handshake->out_msg_seq = 1; |
| else |
| ssl->handshake->in_msg_seq = 1; |
| } |
| #endif |
| |
| ssl->state = MBEDTLS_SSL_HELLO_REQUEST; |
| ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS; |
| |
| if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); |
| return( ret ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= renegotiate" ) ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Renegotiate current connection on client, |
| * or request renegotiation on server |
| */ |
| int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ) |
| { |
| int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; |
| |
| if( ssl == NULL || ssl->conf == NULL ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| #if defined(MBEDTLS_SSL_SRV_C) |
| /* On server, just send the request */ |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) |
| { |
| if( mbedtls_ssl_is_handshake_over( ssl ) == 0 ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; |
| |
| /* Did we already try/start sending HelloRequest? */ |
| if( ssl->out_left != 0 ) |
| return( mbedtls_ssl_flush_output( ssl ) ); |
| |
| return( ssl_write_hello_request( ssl ) ); |
| } |
| #endif /* MBEDTLS_SSL_SRV_C */ |
| |
| #if defined(MBEDTLS_SSL_CLI_C) |
| /* |
| * On client, either start the renegotiation process or, |
| * if already in progress, continue the handshake |
| */ |
| if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) |
|