| /* |
| * SSLv3/TLSv1 shared functions |
| * |
| * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved |
| * 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. |
| * |
| * This file is part of mbed TLS (https://tls.mbed.org) |
| */ |
| /* |
| * The SSL 3.0 specification was drafted by Netscape in 1996, |
| * and became an IETF standard in 1999. |
| * |
| * http://wp.netscape.com/eng/ssl3/ |
| * http://www.ietf.org/rfc/rfc2246.txt |
| * http://www.ietf.org/rfc/rfc4346.txt |
| */ |
| |
| #if !defined(MBEDTLS_CONFIG_FILE) |
| #include "mbedtls/config.h" |
| #else |
| #include MBEDTLS_CONFIG_FILE |
| #endif |
| |
| #if defined(MBEDTLS_SSL_TLS_C) |
| |
| #if defined(MBEDTLS_PLATFORM_C) |
| #include "mbedtls/platform.h" |
| #else |
| #include <stdlib.h> |
| #define mbedtls_calloc calloc |
| #define mbedtls_free free |
| #endif |
| |
| #include "mbedtls/debug.h" |
| #include "mbedtls/ssl.h" |
| #include "mbedtls/ssl_internal.h" |
| #include "mbedtls/platform_util.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 |
| |
| static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ); |
| static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); |
| |
| /* Length of the "epoch" field in the record header */ |
| static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| return( 2 ); |
| #else |
| ((void) ssl); |
| #endif |
| return( 0 ); |
| } |
| |
| /* |
| * Start a timer. |
| * Passing millisecs = 0 cancels a running timer. |
| */ |
| static void ssl_set_timer( mbedtls_ssl_context *ssl, uint32_t millisecs ) |
| { |
| if( ssl->f_set_timer == NULL ) |
| return; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "set_timer to %d ms", (int) millisecs ) ); |
| ssl->f_set_timer( ssl->p_timer, millisecs / 4, millisecs ); |
| } |
| |
| /* |
| * Return -1 is timer is expired, 0 if it isn't. |
| */ |
| static int ssl_check_timer( mbedtls_ssl_context *ssl ) |
| { |
| if( ssl->f_get_timer == NULL ) |
| return( 0 ); |
| |
| if( ssl->f_get_timer( ssl->p_timer ) == 2 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "timer expired" ) ); |
| return( -1 ); |
| } |
| |
| return( 0 ); |
| } |
| |
| static void ssl_update_out_pointers( mbedtls_ssl_context *ssl, |
| mbedtls_ssl_transform *transform ); |
| static void ssl_update_in_pointers( mbedtls_ssl_context *ssl ); |
| |
| #if defined(MBEDTLS_SSL_RECORD_CHECKING) |
| static int ssl_parse_record_header( mbedtls_ssl_context const *ssl, |
| unsigned char *buf, |
| size_t len, |
| mbedtls_record *rec ); |
| |
| int mbedtls_ssl_check_record( mbedtls_ssl_context const *ssl, |
| unsigned char *buf, |
| size_t buflen ) |
| { |
| int ret = 0; |
| mbedtls_record rec; |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "=> mbedtls_ssl_check_record" ) ); |
| MBEDTLS_SSL_DEBUG_BUF( 3, "record buffer", buf, buflen ); |
| |
| /* We don't support record checking in TLS because |
| * (a) there doesn't seem to be a usecase for it, and |
| * (b) In SSLv3 and TLS 1.0, CBC record decryption has state |
| * and we'd need to backup the transform here. |
| */ |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM ) |
| { |
| ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; |
| goto exit; |
| } |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| else |
| { |
| ret = ssl_parse_record_header( ssl, buf, buflen, &rec ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 3, "ssl_parse_record_header", ret ); |
| goto exit; |
| } |
| |
| if( ssl->transform_in != NULL ) |
| { |
| ret = mbedtls_ssl_decrypt_buf( ssl, ssl->transform_in, &rec ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 3, "mbedtls_ssl_decrypt_buf", ret ); |
| goto exit; |
| } |
| } |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| exit: |
| /* On success, we have decrypted the buffer in-place, so make |
| * sure we don't leak any plaintext data. */ |
| mbedtls_platform_zeroize( buf, buflen ); |
| |
| /* For the purpose of this API, treat messages with unexpected CID |
| * as well as such from future epochs as unexpected. */ |
| if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_CID || |
| ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE ) |
| { |
| ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD; |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "<= mbedtls_ssl_check_record" ) ); |
| return( ret ); |
| } |
| #endif /* MBEDTLS_SSL_RECORD_CHECKING */ |
| |
| #define SSL_DONT_FORCE_FLUSH 0 |
| #define SSL_FORCE_FLUSH 1 |
| |
| #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_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 || |
| ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) |
| { |
| 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 */ |
| |
| /* Forward declarations for functions related to message buffering. */ |
| static void ssl_buffering_free( mbedtls_ssl_context *ssl ); |
| static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, |
| uint8_t slot ); |
| static void ssl_free_buffered_record( mbedtls_ssl_context *ssl ); |
| static int ssl_load_buffered_message( mbedtls_ssl_context *ssl ); |
| static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ); |
| static int ssl_buffer_message( mbedtls_ssl_context *ssl ); |
| static int ssl_buffer_future_record( mbedtls_ssl_context *ssl, |
| mbedtls_record const *rec ); |
| static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl ); |
| |
| static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl ); |
| static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl ) |
| { |
| size_t mtu = ssl_get_current_mtu( ssl ); |
| |
| if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN ) |
| return( mtu ); |
| |
| return( MBEDTLS_SSL_OUT_BUFFER_LEN ); |
| } |
| |
| static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl ) |
| { |
| size_t const bytes_written = ssl->out_left; |
| size_t const mtu = ssl_get_maximum_datagram_size( ssl ); |
| |
| /* Double-check that the write-index hasn't gone |
| * past what we can transmit in a single datagram. */ |
| if( bytes_written > mtu ) |
| { |
| /* Should never happen... */ |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| return( (int) ( mtu - bytes_written ) ); |
| } |
| |
| static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl ) |
| { |
| int ret; |
| size_t remaining, expansion; |
| size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; |
| |
| #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) |
| const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); |
| |
| if( max_len > mfl ) |
| max_len = mfl; |
| |
| /* By the standard (RFC 6066 Sect. 4), the MFL extension |
| * only limits the maximum record payload size, so in theory |
| * we would be allowed to pack multiple records of payload size |
| * MFL into a single datagram. However, this would mean that there's |
| * no way to explicitly communicate MTU restrictions to the peer. |
| * |
| * The following reduction of max_len makes sure that we never |
| * write datagrams larger than MFL + Record Expansion Overhead. |
| */ |
| if( max_len <= ssl->out_left ) |
| return( 0 ); |
| |
| max_len -= ssl->out_left; |
| #endif |
| |
| ret = ssl_get_remaining_space_in_datagram( ssl ); |
| if( ret < 0 ) |
| return( ret ); |
| remaining = (size_t) ret; |
| |
| ret = mbedtls_ssl_get_record_expansion( ssl ); |
| if( ret < 0 ) |
| return( ret ); |
| expansion = (size_t) ret; |
| |
| if( remaining <= expansion ) |
| return( 0 ); |
| |
| remaining -= expansion; |
| if( remaining >= max_len ) |
| remaining = max_len; |
| |
| return( (int) remaining ); |
| } |
| |
| /* |
| * Double the retransmit timeout value, within the allowed range, |
| * returning -1 if the maximum value has already been reached. |
| */ |
| static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) |
| { |
| uint32_t new_timeout; |
| |
| if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max ) |
| return( -1 ); |
| |
| /* Implement the final paragraph of RFC 6347 section 4.1.1.1 |
| * in the following way: after the initial transmission and a first |
| * retransmission, back off to a temporary estimated MTU of 508 bytes. |
| * This value is guaranteed to be deliverable (if not guaranteed to be |
| * delivered) of any compliant IPv4 (and IPv6) network, and should work |
| * on most non-IP stacks too. */ |
| if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min ) |
| { |
| ssl->handshake->mtu = 508; |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "mtu autoreduction to %d bytes", ssl->handshake->mtu ) ); |
| } |
| |
| new_timeout = 2 * ssl->handshake->retransmit_timeout; |
| |
| /* Avoid arithmetic overflow and range overflow */ |
| if( new_timeout < ssl->handshake->retransmit_timeout || |
| new_timeout > ssl->conf->hs_timeout_max ) |
| { |
| new_timeout = ssl->conf->hs_timeout_max; |
| } |
| |
| ssl->handshake->retransmit_timeout = new_timeout; |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", |
| ssl->handshake->retransmit_timeout ) ); |
| |
| return( 0 ); |
| } |
| |
| static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) |
| { |
| ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min; |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", |
| ssl->handshake->retransmit_timeout ) ); |
| } |
| #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_X509_CRT_PARSE_C) |
| |
| #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) |
| if( src->peer_cert != NULL ) |
| { |
| int ret; |
| |
| 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_HW_RECORD_ACCEL) |
| int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, |
| const unsigned char *key_enc, const unsigned char *key_dec, |
| size_t keylen, |
| const unsigned char *iv_enc, const unsigned char *iv_dec, |
| size_t ivlen, |
| const unsigned char *mac_enc, const unsigned char *mac_dec, |
| size_t maclen ) = NULL; |
| int (*mbedtls_ssl_hw_record_activate)( mbedtls_ssl_context *ssl, int direction) = NULL; |
| int (*mbedtls_ssl_hw_record_reset)( mbedtls_ssl_context *ssl ) = NULL; |
| int (*mbedtls_ssl_hw_record_write)( mbedtls_ssl_context *ssl ) = NULL; |
| int (*mbedtls_ssl_hw_record_read)( mbedtls_ssl_context *ssl ) = NULL; |
| int (*mbedtls_ssl_hw_record_finish)( mbedtls_ssl_context *ssl ) = NULL; |
| #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ |
| |
| /* |
| * Key material generation |
| */ |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| static int ssl3_prf( const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ) |
| { |
| int ret = 0; |
| size_t i; |
| mbedtls_md5_context md5; |
| mbedtls_sha1_context sha1; |
| unsigned char padding[16]; |
| unsigned char sha1sum[20]; |
| ((void)label); |
| |
| mbedtls_md5_init( &md5 ); |
| mbedtls_sha1_init( &sha1 ); |
| |
| /* |
| * SSLv3: |
| * block = |
| * MD5( secret + SHA1( 'A' + secret + random ) ) + |
| * MD5( secret + SHA1( 'BB' + secret + random ) ) + |
| * MD5( secret + SHA1( 'CCC' + secret + random ) ) + |
| * ... |
| */ |
| for( i = 0; i < dlen / 16; i++ ) |
| { |
| memset( padding, (unsigned char) ('A' + i), 1 + i ); |
| |
| if( ( ret = mbedtls_sha1_starts_ret( &sha1 ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_sha1_update_ret( &sha1, padding, 1 + i ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_sha1_update_ret( &sha1, secret, slen ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_sha1_update_ret( &sha1, random, rlen ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_sha1_finish_ret( &sha1, sha1sum ) ) != 0 ) |
| goto exit; |
| |
| if( ( ret = mbedtls_md5_starts_ret( &md5 ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_md5_update_ret( &md5, secret, slen ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_md5_update_ret( &md5, sha1sum, 20 ) ) != 0 ) |
| goto exit; |
| if( ( ret = mbedtls_md5_finish_ret( &md5, dstbuf + i * 16 ) ) != 0 ) |
| goto exit; |
| } |
| |
| exit: |
| mbedtls_md5_free( &md5 ); |
| mbedtls_sha1_free( &sha1 ); |
| |
| mbedtls_platform_zeroize( padding, sizeof( padding ) ); |
| mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) ); |
| |
| return( ret ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_SSL3 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| static int tls1_prf( const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ) |
| { |
| size_t nb, hs; |
| size_t i, j, k; |
| const unsigned char *S1, *S2; |
| unsigned char *tmp; |
| size_t tmp_len = 0; |
| unsigned char h_i[20]; |
| const mbedtls_md_info_t *md_info; |
| mbedtls_md_context_t md_ctx; |
| int ret; |
| |
| mbedtls_md_init( &md_ctx ); |
| |
| tmp_len = 20 + strlen( label ) + rlen; |
| tmp = mbedtls_calloc( 1, tmp_len ); |
| if( tmp == NULL ) |
| { |
| ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; |
| goto exit; |
| } |
| |
| hs = ( slen + 1 ) / 2; |
| S1 = secret; |
| S2 = secret + slen - hs; |
| |
| nb = strlen( label ); |
| memcpy( tmp + 20, label, nb ); |
| memcpy( tmp + 20 + nb, random, rlen ); |
| nb += rlen; |
| |
| /* |
| * First compute P_md5(secret,label+random)[0..dlen] |
| */ |
| if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ) ) == NULL ) |
| { |
| ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; |
| goto exit; |
| } |
| |
| if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) |
| { |
| goto exit; |
| } |
| |
| mbedtls_md_hmac_starts( &md_ctx, S1, hs ); |
| mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); |
| mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); |
| |
| for( i = 0; i < dlen; i += 16 ) |
| { |
| mbedtls_md_hmac_reset ( &md_ctx ); |
| mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 + nb ); |
| mbedtls_md_hmac_finish( &md_ctx, h_i ); |
| |
| mbedtls_md_hmac_reset ( &md_ctx ); |
| mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 ); |
| mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); |
| |
| k = ( i + 16 > dlen ) ? dlen % 16 : 16; |
| |
| for( j = 0; j < k; j++ ) |
| dstbuf[i + j] = h_i[j]; |
| } |
| |
| mbedtls_md_free( &md_ctx ); |
| |
| /* |
| * XOR out with P_sha1(secret,label+random)[0..dlen] |
| */ |
| if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ) ) == NULL ) |
| { |
| ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; |
| goto exit; |
| } |
| |
| if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) |
| { |
| goto exit; |
| } |
| |
| mbedtls_md_hmac_starts( &md_ctx, S2, hs ); |
| mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); |
| mbedtls_md_hmac_finish( &md_ctx, tmp ); |
| |
| for( i = 0; i < dlen; i += 20 ) |
| { |
| mbedtls_md_hmac_reset ( &md_ctx ); |
| mbedtls_md_hmac_update( &md_ctx, tmp, 20 + nb ); |
| mbedtls_md_hmac_finish( &md_ctx, h_i ); |
| |
| mbedtls_md_hmac_reset ( &md_ctx ); |
| mbedtls_md_hmac_update( &md_ctx, tmp, 20 ); |
| mbedtls_md_hmac_finish( &md_ctx, tmp ); |
| |
| k = ( i + 20 > dlen ) ? dlen % 20 : 20; |
| |
| for( j = 0; j < k; j++ ) |
| dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] ); |
| } |
| |
| exit: |
| mbedtls_md_free( &md_ctx ); |
| |
| mbedtls_platform_zeroize( tmp, tmp_len ); |
| mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); |
| |
| mbedtls_free( tmp ); |
| return( ret ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| static int tls_prf_generic( mbedtls_md_type_t md_type, |
| const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ) |
| { |
| psa_status_t status; |
| psa_algorithm_t alg; |
| psa_key_attributes_t key_attributes; |
| psa_key_handle_t master_slot; |
| psa_key_derivation_operation_t derivation = |
| PSA_KEY_DERIVATION_OPERATION_INIT; |
| |
| if( md_type == MBEDTLS_MD_SHA384 ) |
| alg = PSA_ALG_TLS12_PRF(PSA_ALG_SHA_384); |
| else |
| alg = PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256); |
| |
| key_attributes = psa_key_attributes_init(); |
| 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, secret, slen, &master_slot ); |
| if( status != PSA_SUCCESS ) |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| |
| status = psa_key_derivation( &derivation, |
| master_slot, alg, |
| random, rlen, |
| (unsigned char const *) label, |
| (size_t) strlen( label ), |
| dlen ); |
| if( status != PSA_SUCCESS ) |
| { |
| psa_key_derivation_abort( &derivation ); |
| psa_destroy_key( master_slot ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| |
| status = psa_key_derivation_output_bytes( &derivation, dstbuf, dlen ); |
| if( status != PSA_SUCCESS ) |
| { |
| psa_key_derivation_abort( &derivation ); |
| psa_destroy_key( master_slot ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| |
| status = psa_key_derivation_abort( &derivation ); |
| if( status != PSA_SUCCESS ) |
| { |
| psa_destroy_key( master_slot ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| |
| status = psa_destroy_key( master_slot ); |
| if( status != PSA_SUCCESS ) |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| |
| return( 0 ); |
| } |
| |
| #else /* MBEDTLS_USE_PSA_CRYPTO */ |
| |
| static int tls_prf_generic( mbedtls_md_type_t md_type, |
| const unsigned char *secret, size_t slen, |
| const char *label, |
| const unsigned char *random, size_t rlen, |
| unsigned char *dstbuf, size_t dlen ) |
| { |
| size_t nb; |
| size_t i, j, k, md_len; |
| unsigned char *tmp; |
| size_t tmp_len = 0; |
| unsigned char h_i[MBEDTLS_MD_MAX_SIZE]; |
| const mbedtls_md_info_t *md_info; |
| mbedtls_md_context_t md_ctx; |
| int ret; |
| |
| mbedtls_md_init( &md_ctx ); |
| |
| if( ( md_info = mbedtls_md_info_from_type( md_type ) ) == NULL ) |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| |
| md_len = mbedtls_md_get_size( md_info ); |
| |
| tmp_len = md_len + strlen( label ) + rlen; |
| tmp = mbedtls_calloc( 1, tmp_len ); |
| if( tmp == NULL ) |
| { |
| ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; |
| goto exit; |
| } |
| |
| nb = strlen( label ); |
| memcpy( tmp + md_len, label, nb ); |
| memcpy( tmp + md_len + nb, random, rlen ); |
| nb += rlen; |
| |
| /* |
| * Compute P_<hash>(secret, label + random)[0..dlen] |
| */ |
| if ( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) |
| goto exit; |
| |
| mbedtls_md_hmac_starts( &md_ctx, secret, slen ); |
| mbedtls_md_hmac_update( &md_ctx, tmp + md_len, nb ); |
| mbedtls_md_hmac_finish( &md_ctx, tmp ); |
| |
| for( i = 0; i < dlen; i += md_len ) |
| { |
| mbedtls_md_hmac_reset ( &md_ctx ); |
| mbedtls_md_hmac_update( &md_ctx, tmp, md_len + nb ); |
| mbedtls_md_hmac_finish( &md_ctx, h_i ); |
| |
| mbedtls_md_hmac_reset ( &md_ctx ); |
| mbedtls_md_hmac_update( &md_ctx, tmp, md_len ); |
| mbedtls_md_hmac_finish( &md_ctx, tmp ); |
| |
| k = ( i + md_len > dlen ) ? dlen % md_len : md_len; |
| |
| for( j = 0; j < k; j++ ) |
| dstbuf[i + j] = h_i[j]; |
| } |
| |
| exit: |
| mbedtls_md_free( &md_ctx ); |
| |
| mbedtls_platform_zeroize( tmp, tmp_len ); |
| mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); |
| |
| mbedtls_free( tmp ); |
| |
| return( ret ); |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| #if defined(MBEDTLS_SHA256_C) |
| 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 ) |
| { |
| return( tls_prf_generic( MBEDTLS_MD_SHA256, secret, slen, |
| label, random, rlen, dstbuf, dlen ) ); |
| } |
| #endif /* MBEDTLS_SHA256_C */ |
| |
| #if defined(MBEDTLS_SHA512_C) |
| 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 ) |
| { |
| return( tls_prf_generic( MBEDTLS_MD_SHA384, secret, slen, |
| label, random, rlen, dstbuf, dlen ) ); |
| } |
| #endif /* MBEDTLS_SHA512_C */ |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| static void ssl_update_checksum_start( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ |
| defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| static void ssl_calc_verify_ssl( const mbedtls_ssl_context *, unsigned char * ); |
| static void ssl_calc_finished_ssl( mbedtls_ssl_context *, unsigned char *, int ); |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| static void ssl_calc_verify_tls( const mbedtls_ssl_context *, unsigned char * ); |
| static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int ); |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_SHA256_C) |
| static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| static void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *,unsigned char * ); |
| static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int ); |
| #endif |
| |
| #if defined(MBEDTLS_SHA512_C) |
| static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); |
| static void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *, unsigned char * ); |
| static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int ); |
| #endif |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \ |
| defined(MBEDTLS_USE_PSA_CRYPTO) |
| static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl ) |
| { |
| if( ssl->conf->f_psk != NULL ) |
| { |
| /* If we've used a callback to select the PSK, |
| * the static configuration is irrelevant. */ |
| if( ssl->handshake->psk_opaque != 0 ) |
| return( 1 ); |
| |
| return( 0 ); |
| } |
| |
| if( ssl->conf->psk_opaque != 0 ) |
| return( 1 ); |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_USE_PSA_CRYPTO && |
| MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ |
| |
| #if defined(MBEDTLS_SSL_EXPORT_KEYS) |
| static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( tls_prf == ssl3_prf ) |
| { |
| return( MBEDTLS_SSL_TLS_PRF_SSL3 ); |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| if( tls_prf == tls1_prf ) |
| { |
| return( MBEDTLS_SSL_TLS_PRF_TLS1 ); |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_SHA512_C) |
| if( tls_prf == tls_prf_sha384 ) |
| { |
| return( MBEDTLS_SSL_TLS_PRF_SHA384 ); |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SHA256_C) |
| if( tls_prf == tls_prf_sha256 ) |
| { |
| return( MBEDTLS_SSL_TLS_PRF_SHA256 ); |
| } |
| else |
| #endif |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| return( MBEDTLS_SSL_TLS_PRF_NONE ); |
| } |
| #endif /* MBEDTLS_SSL_EXPORT_KEYS */ |
| |
| 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_SSL3) |
| case MBEDTLS_SSL_TLS_PRF_SSL3: |
| tls_prf = ssl3_prf; |
| break; |
| #endif /* MBEDTLS_SSL_PROTO_SSL3 */ |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| case MBEDTLS_SSL_TLS_PRF_TLS1: |
| tls_prf = tls1_prf; |
| break; |
| #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_SHA512_C) |
| case MBEDTLS_SSL_TLS_PRF_SHA384: |
| tls_prf = tls_prf_sha384; |
| break; |
| #endif /* MBEDTLS_SHA512_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 ) ); |
| } |
| |
| /* |
| * This function will ultimetaly only be responsible for populating a |
| * transform structure from data passed as explicit parameters. |
| * |
| * For now however it's doing rather more in a rather less explicit way. |
| */ |
| static int ssl_populate_transform( mbedtls_ssl_context *ssl ) |
| { |
| int ret = 0; |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| int psa_fallthrough; |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| unsigned char tmp[64]; |
| unsigned char keyblk[256]; |
| unsigned char *key1; |
| unsigned char *key2; |
| unsigned char *mac_enc; |
| unsigned char *mac_dec; |
| size_t mac_key_len; |
| size_t iv_copy_len; |
| unsigned keylen; |
| const mbedtls_ssl_ciphersuite_t *ciphersuite_info; |
| const mbedtls_cipher_info_t *cipher_info; |
| const mbedtls_md_info_t *md_info; |
| |
| mbedtls_ssl_session *session = ssl->session_negotiate; |
| mbedtls_ssl_transform *transform = ssl->transform_negotiate; |
| mbedtls_ssl_handshake_params *handshake = ssl->handshake; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); |
| |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ |
| defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) |
| transform->encrypt_then_mac = session->encrypt_then_mac; |
| #endif |
| transform->minor_ver = ssl->minor_ver; |
| |
| ciphersuite_info = handshake->ciphersuite_info; |
| cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher ); |
| if( cipher_info == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", |
| ciphersuite_info->cipher ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| md_info = mbedtls_md_info_from_type( ciphersuite_info->mac ); |
| if( md_info == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found", |
| ciphersuite_info->mac ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| /* Copy own and peer's CID if the use of the CID |
| * extension has been negotiated. */ |
| if( ssl->handshake->cid_in_use == MBEDTLS_SSL_CID_ENABLED ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Copy CIDs into SSL transform" ) ); |
| |
| transform->in_cid_len = ssl->own_cid_len; |
| memcpy( transform->in_cid, ssl->own_cid, ssl->own_cid_len ); |
| MBEDTLS_SSL_DEBUG_BUF( 3, "Incoming CID", transform->in_cid, |
| transform->in_cid_len ); |
| |
| transform->out_cid_len = ssl->handshake->peer_cid_len; |
| memcpy( transform->out_cid, ssl->handshake->peer_cid, |
| ssl->handshake->peer_cid_len ); |
| MBEDTLS_SSL_DEBUG_BUF( 3, "Outgoing CID", transform->out_cid, |
| transform->out_cid_len ); |
| } |
| #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ |
| |
| /* |
| * Swap the client and server random values. |
| */ |
| memcpy( tmp, handshake->randbytes, 64 ); |
| memcpy( handshake->randbytes, tmp + 32, 32 ); |
| memcpy( handshake->randbytes + 32, tmp, 32 ); |
| mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); |
| |
| /* |
| * SSLv3: |
| * key block = |
| * MD5( master + SHA1( 'A' + master + randbytes ) ) + |
| * MD5( master + SHA1( 'BB' + master + randbytes ) ) + |
| * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + |
| * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + |
| * ... |
| * |
| * TLSv1: |
| * key block = PRF( master, "key expansion", randbytes ) |
| */ |
| ret = handshake->tls_prf( session->master, 48, "key expansion", |
| handshake->randbytes, 64, keyblk, 256 ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); |
| return( ret ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite = %s", |
| mbedtls_ssl_get_ciphersuite_name( session->ciphersuite ) ) ); |
| MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", session->master, 48 ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); |
| |
| /* |
| * Determine the appropriate key, IV and MAC length. |
| */ |
| |
| keylen = cipher_info->key_bitlen / 8; |
| |
| #if defined(MBEDTLS_GCM_C) || \ |
| defined(MBEDTLS_CCM_C) || \ |
| defined(MBEDTLS_CHACHAPOLY_C) |
| if( cipher_info->mode == MBEDTLS_MODE_GCM || |
| cipher_info->mode == MBEDTLS_MODE_CCM || |
| cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY ) |
| { |
| size_t explicit_ivlen; |
| |
| transform->maclen = 0; |
| mac_key_len = 0; |
| transform->taglen = |
| ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; |
| |
| /* All modes haves 96-bit IVs; |
| * GCM and CCM has 4 implicit and 8 explicit bytes |
| * ChachaPoly has all 12 bytes implicit |
| */ |
| transform->ivlen = 12; |
| if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY ) |
| transform->fixed_ivlen = 12; |
| else |
| transform->fixed_ivlen = 4; |
| |
| /* Minimum length of encrypted record */ |
| explicit_ivlen = transform->ivlen - transform->fixed_ivlen; |
| transform->minlen = explicit_ivlen + transform->taglen; |
| } |
| else |
| #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */ |
| #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) |
| if( cipher_info->mode == MBEDTLS_MODE_STREAM || |
| cipher_info->mode == MBEDTLS_MODE_CBC ) |
| { |
| /* Initialize HMAC contexts */ |
| if( ( ret = mbedtls_md_setup( &transform->md_ctx_enc, md_info, 1 ) ) != 0 || |
| ( ret = mbedtls_md_setup( &transform->md_ctx_dec, md_info, 1 ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); |
| goto end; |
| } |
| |
| /* Get MAC length */ |
| mac_key_len = mbedtls_md_get_size( md_info ); |
| transform->maclen = mac_key_len; |
| |
| #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) |
| /* |
| * If HMAC is to be truncated, we shall keep the leftmost bytes, |
| * (rfc 6066 page 13 or rfc 2104 section 4), |
| * so we only need to adjust the length here. |
| */ |
| if( session->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) |
| { |
| transform->maclen = MBEDTLS_SSL_TRUNCATED_HMAC_LEN; |
| |
| #if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) |
| /* Fall back to old, non-compliant version of the truncated |
| * HMAC implementation which also truncates the key |
| * (Mbed TLS versions from 1.3 to 2.6.0) */ |
| mac_key_len = transform->maclen; |
| #endif |
| } |
| #endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ |
| |
| /* IV length */ |
| transform->ivlen = cipher_info->iv_size; |
| |
| /* Minimum length */ |
| if( cipher_info->mode == MBEDTLS_MODE_STREAM ) |
| transform->minlen = transform->maclen; |
| else |
| { |
| /* |
| * GenericBlockCipher: |
| * 1. if EtM is in use: one block plus MAC |
| * otherwise: * first multiple of blocklen greater than maclen |
| * 2. IV except for SSL3 and TLS 1.0 |
| */ |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| if( session->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) |
| { |
| transform->minlen = transform->maclen |
| + cipher_info->block_size; |
| } |
| else |
| #endif |
| { |
| transform->minlen = transform->maclen |
| + cipher_info->block_size |
| - transform->maclen % cipher_info->block_size; |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || |
| ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 ) |
| ; /* No need to adjust minlen */ |
| else |
| #endif |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 || |
| ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) |
| { |
| transform->minlen += transform->ivlen; |
| } |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; |
| goto end; |
| } |
| } |
| } |
| else |
| #endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %u, minlen: %u, ivlen: %u, maclen: %u", |
| (unsigned) keylen, |
| (unsigned) transform->minlen, |
| (unsigned) transform->ivlen, |
| (unsigned) transform->maclen ) ); |
| |
| /* |
| * Finally setup the cipher contexts, IVs and MAC secrets. |
| */ |
| #if defined(MBEDTLS_SSL_CLI_C) |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) |
| { |
| key1 = keyblk + mac_key_len * 2; |
| key2 = keyblk + mac_key_len * 2 + keylen; |
| |
| mac_enc = keyblk; |
| mac_dec = keyblk + mac_key_len; |
| |
| /* |
| * This is not used in TLS v1.1. |
| */ |
| iv_copy_len = ( transform->fixed_ivlen ) ? |
| transform->fixed_ivlen : transform->ivlen; |
| memcpy( transform->iv_enc, key2 + keylen, iv_copy_len ); |
| memcpy( transform->iv_dec, key2 + keylen + iv_copy_len, |
| iv_copy_len ); |
| } |
| else |
| #endif /* MBEDTLS_SSL_CLI_C */ |
| #if defined(MBEDTLS_SSL_SRV_C) |
| if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) |
| { |
| key1 = keyblk + mac_key_len * 2 + keylen; |
| key2 = keyblk + mac_key_len * 2; |
| |
| mac_enc = keyblk + mac_key_len; |
| mac_dec = keyblk; |
| |
| /* |
| * This is not used in TLS v1.1. |
| */ |
| iv_copy_len = ( transform->fixed_ivlen ) ? |
| transform->fixed_ivlen : transform->ivlen; |
| memcpy( transform->iv_dec, key1 + keylen, iv_copy_len ); |
| memcpy( transform->iv_enc, key1 + keylen + iv_copy_len, |
| iv_copy_len ); |
| } |
| else |
| #endif /* MBEDTLS_SSL_SRV_C */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; |
| goto end; |
| } |
| |
| #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| if( mac_key_len > sizeof( transform->mac_enc ) ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; |
| goto end; |
| } |
| |
| memcpy( transform->mac_enc, mac_enc, mac_key_len ); |
| memcpy( transform->mac_dec, mac_dec, mac_key_len ); |
| } |
| else |
| #endif /* MBEDTLS_SSL_PROTO_SSL3 */ |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ |
| defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) |
| { |
| /* For HMAC-based ciphersuites, initialize the HMAC transforms. |
| For AEAD-based ciphersuites, there is nothing to do here. */ |
| if( mac_key_len != 0 ) |
| { |
| mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, mac_key_len ); |
| mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, mac_key_len ); |
| } |
| } |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; |
| goto end; |
| } |
| #endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ |
| |
| #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) |
| if( mbedtls_ssl_hw_record_init != NULL ) |
| { |
| int ret = 0; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_init()" ) ); |
| |
| if( ( ret = mbedtls_ssl_hw_record_init( ssl, key1, key2, keylen, |
| transform->iv_enc, transform->iv_dec, |
| iv_copy_len, |
| mac_enc, mac_dec, |
| mac_key_len ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); |
| ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; |
| goto end; |
| } |
| } |
| #else |
| ((void) mac_dec); |
| ((void) mac_enc); |
| #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ |
| |
| #if defined(MBEDTLS_SSL_EXPORT_KEYS) |
| if( ssl->conf->f_export_keys != NULL ) |
| { |
| ssl->conf->f_export_keys( ssl->conf->p_export_keys, |
| session->master, keyblk, |
| mac_key_len, keylen, |
| iv_copy_len ); |
| } |
| |
| if( ssl->conf->f_export_keys_ext != NULL ) |
| { |
| ssl->conf->f_export_keys_ext( ssl->conf->p_export_keys, |
| session->master, keyblk, |
| mac_key_len, keylen, |
| iv_copy_len, |
| handshake->randbytes + 32, |
| handshake->randbytes, |
| tls_prf_get_type( handshake->tls_prf ) ); |
| } |
| #endif |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| |
| /* Only use PSA-based ciphers for TLS-1.2. |
| * That's relevant at least for TLS-1.0, where |
| * we assume that mbedtls_cipher_crypt() updates |
| * the structure field for the IV, which the PSA-based |
| * implementation currently doesn't. */ |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) |
| { |
| ret = mbedtls_cipher_setup_psa( &transform->cipher_ctx_enc, |
| cipher_info, transform->taglen ); |
| if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret ); |
| goto end; |
| } |
| |
| if( ret == 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Successfully setup PSA-based encryption cipher context" ) ); |
| psa_fallthrough = 0; |
| } |
| else |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to setup PSA-based cipher context for record encryption - fall through to default setup." ) ); |
| psa_fallthrough = 1; |
| } |
| } |
| else |
| psa_fallthrough = 1; |
| #else |
| psa_fallthrough = 1; |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| if( psa_fallthrough == 1 ) |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, |
| cipher_info ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); |
| goto end; |
| } |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| /* Only use PSA-based ciphers for TLS-1.2. |
| * That's relevant at least for TLS-1.0, where |
| * we assume that mbedtls_cipher_crypt() updates |
| * the structure field for the IV, which the PSA-based |
| * implementation currently doesn't. */ |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) |
| { |
| ret = mbedtls_cipher_setup_psa( &transform->cipher_ctx_dec, |
| cipher_info, transform->taglen ); |
| if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret ); |
| goto end; |
| } |
| |
| if( ret == 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Successfully setup PSA-based decryption cipher context" ) ); |
| psa_fallthrough = 0; |
| } |
| else |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to setup PSA-based cipher context for record decryption - fall through to default setup." ) ); |
| psa_fallthrough = 1; |
| } |
| } |
| else |
| psa_fallthrough = 1; |
| #else |
| psa_fallthrough = 1; |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| if( psa_fallthrough == 1 ) |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, |
| cipher_info ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); |
| goto end; |
| } |
| |
| if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, key1, |
| cipher_info->key_bitlen, |
| MBEDTLS_ENCRYPT ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); |
| goto end; |
| } |
| |
| if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, key2, |
| cipher_info->key_bitlen, |
| MBEDTLS_DECRYPT ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); |
| goto end; |
| } |
| |
| #if defined(MBEDTLS_CIPHER_MODE_CBC) |
| if( cipher_info->mode == MBEDTLS_MODE_CBC ) |
| { |
| if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_enc, |
| MBEDTLS_PADDING_NONE ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); |
| goto end; |
| } |
| |
| if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_dec, |
| MBEDTLS_PADDING_NONE ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); |
| goto end; |
| } |
| } |
| #endif /* MBEDTLS_CIPHER_MODE_CBC */ |
| |
| |
| #if defined(MBEDTLS_ZLIB_SUPPORT) |
| // Initialize compression |
| // |
| if( session->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) |
| { |
| if( ssl->compress_buf == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) ); |
| ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_COMPRESS_BUFFER_LEN ); |
| if( ssl->compress_buf == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", |
| MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) ); |
| ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; |
| goto end; |
| } |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) ); |
| |
| memset( &transform->ctx_deflate, 0, sizeof( transform->ctx_deflate ) ); |
| memset( &transform->ctx_inflate, 0, sizeof( transform->ctx_inflate ) ); |
| |
| if( deflateInit( &transform->ctx_deflate, |
| Z_DEFAULT_COMPRESSION ) != Z_OK || |
| inflateInit( &transform->ctx_inflate ) != Z_OK ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); |
| ret = MBEDTLS_ERR_SSL_COMPRESSION_FAILED; |
| goto end; |
| } |
| } |
| #endif /* MBEDTLS_ZLIB_SUPPORT */ |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); |
| end: |
| mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) ); |
| mbedtls_platform_zeroize( handshake->randbytes, |
| sizeof( handshake->randbytes ) ); |
| return( ret ); |
| } |
| |
| /* |
| * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions |
| * |
| * Inputs: |
| * - SSL/TLS minor version |
| * - hash associated with the ciphersuite (only used by TLS 1.2) |
| * |
| * Ouputs: |
| * - the tls_prf, calc_verify and calc_finished members of handshake structure |
| */ |
| static int ssl_set_handshake_prfs( mbedtls_ssl_handshake_params *handshake, |
| int minor_ver, |
| mbedtls_md_type_t hash ) |
| { |
| #if !defined(MBEDTLS_SSL_PROTO_TLS1_2) || !defined(MBEDTLS_SHA512_C) |
| (void) hash; |
| #endif |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| handshake->tls_prf = ssl3_prf; |
| handshake->calc_verify = ssl_calc_verify_ssl; |
| handshake->calc_finished = ssl_calc_finished_ssl; |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| if( minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) |
| { |
| handshake->tls_prf = tls1_prf; |
| handshake->calc_verify = ssl_calc_verify_tls; |
| handshake->calc_finished = ssl_calc_finished_tls; |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_SHA512_C) |
| if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && |
| hash == MBEDTLS_MD_SHA384 ) |
| { |
| handshake->tls_prf = tls_prf_sha384; |
| handshake->calc_verify = ssl_calc_verify_tls_sha384; |
| handshake->calc_finished = ssl_calc_finished_tls_sha384; |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SHA256_C) |
| if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) |
| { |
| handshake->tls_prf = tls_prf_sha256; |
| handshake->calc_verify = ssl_calc_verify_tls_sha256; |
| handshake->calc_finished = ssl_calc_finished_tls_sha256; |
| } |
| else |
| #endif |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| { |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Compute master secret if needed |
| * |
| * Parameters: |
| * [in/out] handshake |
| * [in] resume, premaster, extended_ms, calc_verify, tls_prf |
| * (PSA-PSK) ciphersuite_info |
| * [out] premaster (cleared) |
| * [in] minor_ver (to compute hash_len) |
| * [in] hash_alg (to compute hash_len) |
| * [out] master |
| * [in] ssl: optionally used for debugging, EMS and PSA-PSK |
| * debug: conf->f_dbg, conf->p_dbg |
| * EMS: passed to calc_verify (debug + (SSL3) session_negotiate) |
| * PSA-PSA: conf |
| */ |
| static int ssl_compute_master( mbedtls_ssl_handshake_params *handshake, |
| int minor_ver, |
| mbedtls_md_type_t hash_alg, |
| unsigned char *master, |
| const mbedtls_ssl_context *ssl ) |
| { |
| int ret; |
| |
| /* cf. RFC 5246, Section 8.1: |
| * "The master secret is always exactly 48 bytes in length." */ |
| size_t const master_secret_len = 48; |
| |
| #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) |
| unsigned char session_hash[48]; |
| #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ |
| |
| /* The label for the KDF used for key expansion. |
| * This is either "master secret" or "extended master secret" |
| * depending on whether the Extended Master Secret extension |
| * is used. */ |
| char const *lbl = "master secret"; |
| |
| /* The salt for the KDF used for key expansion. |
| * - If the Extended Master Secret extension is not used, |
| * this is ClientHello.Random + ServerHello.Random |
| * (see Sect. 8.1 in RFC 5246). |
| * - If the Extended Master Secret extension is used, |
| * this is the transcript of the handshake so far. |
| * (see Sect. 4 in RFC 7627). */ |
| unsigned char const *salt = handshake->randbytes; |
| size_t salt_len = 64; |
| |
| #if !defined(MBEDTLS_DEBUG_C) && \ |
| !defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ |
| !(defined(MBEDTLS_USE_PSA_CRYPTO) && \ |
| defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)) |
| (void) ssl; |
| #endif |
| #if !defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) || !defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| (void) minor_ver; |
| #if defined(MBEDTLS_SHA512_C) |
| (void) hash_alg; |
| #endif |
| #endif |
| |
| if( handshake->resume != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); |
| return( 0 ); |
| } |
| |
| #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) |
| if( handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); |
| |
| lbl = "extended master secret"; |
| salt = session_hash; |
| handshake->calc_verify( ssl, session_hash ); |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) |
| { |
| #if defined(MBEDTLS_SHA512_C) |
| if( hash_alg == MBEDTLS_MD_SHA384 ) |
| { |
| salt_len = 48; |
| } |
| else |
| #endif /* MBEDTLS_SHA512_C */ |
| salt_len = 32; |
| } |
| else |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| salt_len = 36; |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, salt_len ); |
| } |
| #endif /* MBEDTLS_SSL_EXTENDED_MS_ENABLED */ |
| |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) && \ |
| defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) |
| if( handshake->ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK && |
| minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && |
| ssl_use_opaque_psk( ssl ) == 1 ) |
| { |
| /* Perform PSK-to-MS expansion in a single step. */ |
| psa_status_t status; |
| psa_algorithm_t alg; |
| psa_key_handle_t psk; |
| psa_key_derivation_operation_t derivation = |
| PSA_KEY_DERIVATION_OPERATION_INIT; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) ); |
| |
| psk = ssl->conf->psk_opaque; |
| if( handshake->psk_opaque != 0 ) |
| psk = handshake->psk_opaque; |
| |
| if( hash_alg == 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); |
| |
| status = psa_key_derivation( &derivation, psk, alg, |
| salt, salt_len, |
| (unsigned char const *) lbl, |
| (size_t) strlen( lbl ), |
| master_secret_len ); |
| if( status != PSA_SUCCESS ) |
| { |
| psa_key_derivation_abort( &derivation ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| |
| status = psa_key_derivation_output_bytes( &derivation, |
| master, |
| master_secret_len ); |
| if( status != PSA_SUCCESS ) |
| { |
| psa_key_derivation_abort( &derivation ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| |
| status = psa_key_derivation_abort( &derivation ); |
| if( status != PSA_SUCCESS ) |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| else |
| #endif |
| { |
| ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, |
| lbl, salt, salt_len, |
| master, |
| master_secret_len ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); |
| return( ret ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret", |
| handshake->premaster, |
| handshake->pmslen ); |
| |
| mbedtls_platform_zeroize( handshake->premaster, |
| sizeof(handshake->premaster) ); |
| } |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) |
| { |
| int ret; |
| const mbedtls_ssl_ciphersuite_t * const ciphersuite_info = |
| ssl->handshake->ciphersuite_info; |
| |
| ret = ssl_set_handshake_prfs( ssl->handshake, |
| ssl->minor_ver, |
| ciphersuite_info->mac ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "ssl_set_handshake_prfs", ret ); |
| return( ret ); |
| } |
| |
| ret = ssl_compute_master( ssl->handshake, |
| ssl->minor_ver, |
| ciphersuite_info->mac, |
| ssl->session_negotiate->master, |
| ssl ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compute_master", ret ); |
| return( ret ); |
| } |
| |
| return( ssl_populate_transform( ssl ) ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| void ssl_calc_verify_ssl( const mbedtls_ssl_context *ssl, unsigned char hash[36] ) |
| { |
| mbedtls_md5_context md5; |
| mbedtls_sha1_context sha1; |
| unsigned char pad_1[48]; |
| unsigned char pad_2[48]; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify ssl" ) ); |
| |
| mbedtls_md5_init( &md5 ); |
| mbedtls_sha1_init( &sha1 ); |
| |
| mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); |
| mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); |
| |
| memset( pad_1, 0x36, 48 ); |
| memset( pad_2, 0x5C, 48 ); |
| |
| mbedtls_md5_update_ret( &md5, ssl->session_negotiate->master, 48 ); |
| mbedtls_md5_update_ret( &md5, pad_1, 48 ); |
| mbedtls_md5_finish_ret( &md5, hash ); |
| |
| mbedtls_md5_starts_ret( &md5 ); |
| mbedtls_md5_update_ret( &md5, ssl->session_negotiate->master, 48 ); |
| mbedtls_md5_update_ret( &md5, pad_2, 48 ); |
| mbedtls_md5_update_ret( &md5, hash, 16 ); |
| mbedtls_md5_finish_ret( &md5, hash ); |
| |
| mbedtls_sha1_update_ret( &sha1, ssl->session_negotiate->master, 48 ); |
| mbedtls_sha1_update_ret( &sha1, pad_1, 40 ); |
| mbedtls_sha1_finish_ret( &sha1, hash + 16 ); |
| |
| mbedtls_sha1_starts_ret( &sha1 ); |
| mbedtls_sha1_update_ret( &sha1, ssl->session_negotiate->master, 48 ); |
| mbedtls_sha1_update_ret( &sha1, pad_2, 40 ); |
| mbedtls_sha1_update_ret( &sha1, hash + 16, 20 ); |
| mbedtls_sha1_finish_ret( &sha1, hash + 16 ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); |
| |
| mbedtls_md5_free( &md5 ); |
| mbedtls_sha1_free( &sha1 ); |
| |
| return; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_SSL3 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) |
| void ssl_calc_verify_tls( const mbedtls_ssl_context *ssl, unsigned char hash[36] ) |
| { |
| mbedtls_md5_context md5; |
| mbedtls_sha1_context sha1; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify tls" ) ); |
| |
| mbedtls_md5_init( &md5 ); |
| mbedtls_sha1_init( &sha1 ); |
| |
| mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); |
| mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); |
| |
| mbedtls_md5_finish_ret( &md5, hash ); |
| mbedtls_sha1_finish_ret( &sha1, hash + 16 ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); |
| |
| mbedtls_md5_free( &md5 ); |
| mbedtls_sha1_free( &sha1 ); |
| |
| return; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| #if defined(MBEDTLS_SHA256_C) |
| void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *ssl, unsigned char hash[32] ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| size_t hash_size; |
| psa_status_t status; |
| psa_hash_operation_t sha256_psa = psa_hash_operation_init(); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> PSA calc verify sha256" ) ); |
| status = psa_hash_clone( &ssl->handshake->fin_sha256_psa, &sha256_psa ); |
| if( status != PSA_SUCCESS ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) ); |
| return; |
| } |
| |
| status = psa_hash_finish( &sha256_psa, hash, 32, &hash_size ); |
| if( status != PSA_SUCCESS ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) ); |
| return; |
| } |
| MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, 32 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) ); |
| #else |
| mbedtls_sha256_context sha256; |
| |
| mbedtls_sha256_init( &sha256 ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha256" ) ); |
| |
| mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); |
| mbedtls_sha256_finish_ret( &sha256, hash ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); |
| |
| mbedtls_sha256_free( &sha256 ); |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| return; |
| } |
| #endif /* MBEDTLS_SHA256_C */ |
| |
| #if defined(MBEDTLS_SHA512_C) |
| void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *ssl, unsigned char hash[48] ) |
| { |
| #if defined(MBEDTLS_USE_PSA_CRYPTO) |
| size_t hash_size; |
| psa_status_t status; |
| psa_hash_operation_t sha384_psa = psa_hash_operation_init(); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> PSA calc verify sha384" ) ); |
| status = psa_hash_clone( &ssl->handshake->fin_sha384_psa, &sha384_psa ); |
| if( status != PSA_SUCCESS ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) ); |
| return; |
| } |
| |
| status = psa_hash_finish( &sha384_psa, hash, 48, &hash_size ); |
| if( status != PSA_SUCCESS ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) ); |
| return; |
| } |
| MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, 48 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) ); |
| #else |
| mbedtls_sha512_context sha512; |
| |
| mbedtls_sha512_init( &sha512 ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha384" ) ); |
| |
| mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); |
| mbedtls_sha512_finish_ret( &sha512, hash ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); |
| |
| mbedtls_sha512_free( &sha512 ); |
| #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
| return; |
| } |
| #endif /* MBEDTLS_SHA512_C */ |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) |
| int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ) |
| { |
| unsigned char *p = ssl->handshake->premaster; |
| unsigned char *end = p + sizeof( ssl->handshake->premaster ); |
| const unsigned char *psk = ssl->conf->psk; |
| size_t psk_len = ssl->conf->psk_len; |
| |
| /* If the psk callback was called, use its result */ |
| if( ssl->handshake->psk != NULL ) |
| { |
| psk = ssl->handshake->psk; |
| psk_len = ssl->handshake->psk_len; |
| } |
| |
| /* |
| * PMS = struct { |
| * opaque other_secret<0..2^16-1>; |
| * opaque psk<0..2^16-1>; |
| * }; |
| * with "other_secret" depending on the particular key exchange |
| */ |
| #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) |
| if( key_ex == MBEDTLS_KEY_EXCHANGE_PSK ) |
| { |
| if( end - p < 2 ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| *(p++) = (unsigned char)( psk_len >> 8 ); |
| *(p++) = (unsigned char)( psk_len ); |
| |
| if( end < p || (size_t)( end - p ) < psk_len ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| memset( p, 0, psk_len ); |
| p += psk_len; |
| } |
| else |
| #endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ |
| #if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) |
| if( key_ex == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) |
| { |
| /* |
| * other_secret already set by the ClientKeyExchange message, |
| * and is 48 bytes long |
| */ |
| if( end - p < 2 ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| *p++ = 0; |
| *p++ = 48; |
| p += 48; |
| } |
| else |
| #endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ |
| #if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) |
| if( key_ex == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) |
| { |
| int ret; |
| size_t len; |
| |
| /* Write length only when we know the actual value */ |
| if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, |
| p + 2, end - ( p + 2 ), &len, |
| ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); |
| return( ret ); |
| } |
| *(p++) = (unsigned char)( len >> 8 ); |
| *(p++) = (unsigned char)( len ); |
| p += len; |
| |
| MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); |
| } |
| else |
| #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ |
| #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) |
| if( key_ex == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) |
| { |
| int ret; |
| size_t zlen; |
| |
| if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen, |
| p + 2, end - ( p + 2 ), |
| ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); |
| return( ret ); |
| } |
| |
| *(p++) = (unsigned char)( zlen >> 8 ); |
| *(p++) = (unsigned char)( zlen ); |
| p += zlen; |
| |
| MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, |
| MBEDTLS_DEBUG_ECDH_Z ); |
| } |
| else |
| #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| /* opaque psk<0..2^16-1>; */ |
| if( end - p < 2 ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| *(p++) = (unsigned char)( psk_len >> 8 ); |
| *(p++) = (unsigned char)( psk_len ); |
| |
| if( end < p || (size_t)( end - p ) < psk_len ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| memcpy( p, psk, psk_len ); |
| p += psk_len; |
| |
| ssl->handshake->pmslen = p - ssl->handshake->premaster; |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| /* |
| * SSLv3.0 MAC functions |
| */ |
| #define SSL_MAC_MAX_BYTES 20 /* MD-5 or SHA-1 */ |
| static void ssl_mac( mbedtls_md_context_t *md_ctx, |
| const unsigned char *secret, |
| const unsigned char *buf, size_t len, |
| const unsigned char *ctr, int type, |
| unsigned char out[SSL_MAC_MAX_BYTES] ) |
| { |
| unsigned char header[11]; |
| unsigned char padding[48]; |
| int padlen; |
| int md_size = mbedtls_md_get_size( md_ctx->md_info ); |
| int md_type = mbedtls_md_get_type( md_ctx->md_info ); |
| |
| /* Only MD5 and SHA-1 supported */ |
| if( md_type == MBEDTLS_MD_MD5 ) |
| padlen = 48; |
| else |
| padlen = 40; |
| |
| memcpy( header, ctr, 8 ); |
| header[ 8] = (unsigned char) type; |
| header[ 9] = (unsigned char)( len >> 8 ); |
| header[10] = (unsigned char)( len ); |
| |
| memset( padding, 0x36, padlen ); |
| mbedtls_md_starts( md_ctx ); |
| mbedtls_md_update( md_ctx, secret, md_size ); |
| mbedtls_md_update( md_ctx, padding, padlen ); |
| mbedtls_md_update( md_ctx, header, 11 ); |
| mbedtls_md_update( md_ctx, buf, len ); |
| mbedtls_md_finish( md_ctx, out ); |
| |
| memset( padding, 0x5C, padlen ); |
| mbedtls_md_starts( md_ctx ); |
| mbedtls_md_update( md_ctx, secret, md_size ); |
| mbedtls_md_update( md_ctx, padding, padlen ); |
| mbedtls_md_update( md_ctx, out, md_size ); |
| mbedtls_md_finish( md_ctx, out ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_SSL3 */ |
| |
| /* The function below is only used in the Lucky 13 counter-measure in |
| * mbedtls_ssl_decrypt_buf(). These are the defines that guard the call site. */ |
| #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) && \ |
| ( defined(MBEDTLS_SSL_PROTO_TLS1) || \ |
| defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ |
| defined(MBEDTLS_SSL_PROTO_TLS1_2) ) |
| /* This function makes sure every byte in the memory region is accessed |
| * (in ascending addresses order) */ |
| static void ssl_read_memory( unsigned char *p, size_t len ) |
| { |
| unsigned char acc = 0; |
| volatile unsigned char force; |
| |
| for( ; len != 0; p++, len-- ) |
| acc ^= *p; |
| |
| force = acc; |
| (void) force; |
| } |
| #endif /* SSL_SOME_MODES_USE_MAC && ( TLS1 || TLS1_1 || TLS1_2 ) */ |
| |
| /* |
| * Encryption/decryption functions |
| */ |
| |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| /* This functions transforms a DTLS plaintext fragment and a record content |
| * type into an instance of the DTLSInnerPlaintext structure: |
| * |
| * struct { |
| * opaque content[DTLSPlaintext.length]; |
| * ContentType real_type; |
| * uint8 zeros[length_of_padding]; |
| * } DTLSInnerPlaintext; |
| * |
| * Input: |
| * - `content`: The beginning of the buffer holding the |
| * plaintext to be wrapped. |
| * - `*content_size`: The length of the plaintext in Bytes. |
| * - `max_len`: The number of Bytes available starting from |
| * `content`. This must be `>= *content_size`. |
| * - `rec_type`: The desired record content type. |
| * |
| * Output: |
| * - `content`: The beginning of the resulting DTLSInnerPlaintext structure. |
| * - `*content_size`: The length of the resulting DTLSInnerPlaintext structure. |
| * |
| * Returns: |
| * - `0` on success. |
| * - A negative error code if `max_len` didn't offer enough space |
| * for the expansion. |
| */ |
| static int ssl_cid_build_inner_plaintext( unsigned char *content, |
| size_t *content_size, |
| size_t remaining, |
| uint8_t rec_type ) |
| { |
| size_t len = *content_size; |
| size_t pad = ( MBEDTLS_SSL_CID_PADDING_GRANULARITY - |
| ( len + 1 ) % MBEDTLS_SSL_CID_PADDING_GRANULARITY ) % |
| MBEDTLS_SSL_CID_PADDING_GRANULARITY; |
| |
| /* Write real content type */ |
| if( remaining == 0 ) |
| return( -1 ); |
| content[ len ] = rec_type; |
| len++; |
| remaining--; |
| |
| if( remaining < pad ) |
| return( -1 ); |
| memset( content + len, 0, pad ); |
| len += pad; |
| remaining -= pad; |
| |
| *content_size = len; |
| return( 0 ); |
| } |
| |
| /* This function parses a DTLSInnerPlaintext structure. |
| * See ssl_cid_build_inner_plaintext() for details. */ |
| static int ssl_cid_parse_inner_plaintext( unsigned char const *content, |
| size_t *content_size, |
| uint8_t *rec_type ) |
| { |
| size_t remaining = *content_size; |
| |
| /* Determine length of padding by skipping zeroes from the back. */ |
| do |
| { |
| if( remaining == 0 ) |
| return( -1 ); |
| remaining--; |
| } while( content[ remaining ] == 0 ); |
| |
| *content_size = remaining; |
| *rec_type = content[ remaining ]; |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ |
| |
| /* `add_data` must have size 13 Bytes if the CID extension is disabled, |
| * and 13 + 1 + CID-length Bytes if the CID extension is enabled. */ |
| static void ssl_extract_add_data_from_record( unsigned char* add_data, |
| size_t *add_data_len, |
| mbedtls_record *rec ) |
| { |
| /* Quoting RFC 5246 (TLS 1.2): |
| * |
| * additional_data = seq_num + TLSCompressed.type + |
| * TLSCompressed.version + TLSCompressed.length; |
| * |
| * For the CID extension, this is extended as follows |
| * (quoting draft-ietf-tls-dtls-connection-id-05, |
| * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05): |
| * |
| * additional_data = seq_num + DTLSPlaintext.type + |
| * DTLSPlaintext.version + |
| * cid + |
| * cid_length + |
| * length_of_DTLSInnerPlaintext; |
| */ |
| |
| memcpy( add_data, rec->ctr, sizeof( rec->ctr ) ); |
| add_data[8] = rec->type; |
| memcpy( add_data + 9, rec->ver, sizeof( rec->ver ) ); |
| |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| if( rec->cid_len != 0 ) |
| { |
| memcpy( add_data + 11, rec->cid, rec->cid_len ); |
| add_data[11 + rec->cid_len + 0] = rec->cid_len; |
| add_data[11 + rec->cid_len + 1] = ( rec->data_len >> 8 ) & 0xFF; |
| add_data[11 + rec->cid_len + 2] = ( rec->data_len >> 0 ) & 0xFF; |
| *add_data_len = 13 + 1 + rec->cid_len; |
| } |
| else |
| #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ |
| { |
| add_data[11 + 0] = ( rec->data_len >> 8 ) & 0xFF; |
| add_data[11 + 1] = ( rec->data_len >> 0 ) & 0xFF; |
| *add_data_len = 13; |
| } |
| } |
| |
| int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, |
| mbedtls_ssl_transform *transform, |
| mbedtls_record *rec, |
| int (*f_rng)(void *, unsigned char *, size_t), |
| void *p_rng ) |
| { |
| mbedtls_cipher_mode_t mode; |
| int auth_done = 0; |
| unsigned char * data; |
| unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_OUT_LEN_MAX ]; |
| size_t add_data_len; |
| size_t post_avail; |
| |
| /* The SSL context is only used for debugging purposes! */ |
| #if !defined(MBEDTLS_DEBUG_C) |
| ((void) ssl); |
| #endif |
| |
| /* The PRNG is used for dynamic IV generation that's used |
| * for CBC transformations in TLS 1.1 and TLS 1.2. */ |
| #if !( defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
| ( defined(MBEDTLS_AES_C) || \ |
| defined(MBEDTLS_ARIA_C) || \ |
| defined(MBEDTLS_CAMELLIA_C) ) && \ |
| ( defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) ) ) |
| ((void) f_rng); |
| ((void) p_rng); |
| #endif |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); |
| |
| if( transform == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "no transform provided to encrypt_buf" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| if( rec == NULL |
| || rec->buf == NULL |
| || rec->buf_len < rec->data_offset |
| || rec->buf_len - rec->data_offset < rec->data_len |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| || rec->cid_len != 0 |
| #endif |
| ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad record structure provided to encrypt_buf" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| data = rec->buf + rec->data_offset; |
| post_avail = rec->buf_len - ( rec->data_len + rec->data_offset ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", |
| data, rec->data_len ); |
| |
| mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ); |
| |
| if( rec->data_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d", |
| (unsigned) rec->data_len, |
| MBEDTLS_SSL_OUT_CONTENT_LEN ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| /* |
| * Add CID information |
| */ |
| rec->cid_len = transform->out_cid_len; |
| memcpy( rec->cid, transform->out_cid, transform->out_cid_len ); |
| MBEDTLS_SSL_DEBUG_BUF( 3, "CID", rec->cid, rec->cid_len ); |
| |
| if( rec->cid_len != 0 ) |
| { |
| /* |
| * Wrap plaintext into DTLSInnerPlaintext structure. |
| * See ssl_cid_build_inner_plaintext() for more information. |
| * |
| * Note that this changes `rec->data_len`, and hence |
| * `post_avail` needs to be recalculated afterwards. |
| */ |
| if( ssl_cid_build_inner_plaintext( data, |
| &rec->data_len, |
| post_avail, |
| rec->type ) != 0 ) |
| { |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| } |
| |
| rec->type = MBEDTLS_SSL_MSG_CID; |
| } |
| #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ |
| |
| post_avail = rec->buf_len - ( rec->data_len + rec->data_offset ); |
| |
| /* |
| * Add MAC before if needed |
| */ |
| #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) |
| if( mode == MBEDTLS_MODE_STREAM || |
| ( mode == MBEDTLS_MODE_CBC |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| && transform->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED |
| #endif |
| ) ) |
| { |
| if( post_avail < transform->maclen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| unsigned char mac[SSL_MAC_MAX_BYTES]; |
| ssl_mac( &transform->md_ctx_enc, transform->mac_enc, |
| data, rec->data_len, rec->ctr, rec->type, mac ); |
| memcpy( data + rec->data_len, mac, transform->maclen ); |
| } |
| else |
| #endif |
| #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ |
| defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) |
| { |
| unsigned char mac[MBEDTLS_SSL_MAC_ADD]; |
| |
| ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); |
| |
| mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, |
| add_data_len ); |
| mbedtls_md_hmac_update( &transform->md_ctx_enc, |
| data, rec->data_len ); |
| mbedtls_md_hmac_finish( &transform->md_ctx_enc, mac ); |
| mbedtls_md_hmac_reset( &transform->md_ctx_enc ); |
| |
| memcpy( data + rec->data_len, mac, transform->maclen ); |
| } |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", data + rec->data_len, |
| transform->maclen ); |
| |
| rec->data_len += transform->maclen; |
| post_avail -= transform->maclen; |
| auth_done++; |
| } |
| #endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ |
| |
| /* |
| * Encrypt |
| */ |
| #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) |
| if( mode == MBEDTLS_MODE_STREAM ) |
| { |
| int ret; |
| size_t olen; |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " |
| "including %d bytes of padding", |
| rec->data_len, 0 ) ); |
| |
| if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_enc, |
| transform->iv_enc, transform->ivlen, |
| data, rec->data_len, |
| data, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( rec->data_len != olen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| } |
| else |
| #endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ |
| |
| #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 ) |
| { |
| int ret; |
| unsigned char iv[12]; |
| size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen; |
| |
| /* Check that there's space for both the authentication tag |
| * and the explicit IV before and after the record content. */ |
| if( post_avail < transform->taglen || |
| rec->data_offset < explicit_iv_len ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| } |
| |
| /* |
| * Generate IV |
| */ |
| if( transform->ivlen == 12 && transform->fixed_ivlen == 4 ) |
| { |
| /* GCM and CCM: fixed || explicit (=seqnum) */ |
| memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); |
| memcpy( iv + transform->fixed_ivlen, rec->ctr, |
| explicit_iv_len ); |
| /* Prefix record content with explicit IV. */ |
| memcpy( data - explicit_iv_len, rec->ctr, explicit_iv_len ); |
| } |
| else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) |
| { |
| /* ChachaPoly: fixed XOR sequence number */ |
| unsigned char i; |
| |
| memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); |
| |
| for( i = 0; i < 8; i++ ) |
| iv[i+4] ^= rec->ctr[i]; |
| } |
| else |
| { |
| /* Reminder if we ever add an AEAD mode with a different size */ |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)", |
| iv, transform->ivlen ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (transmitted)", |
| data - explicit_iv_len, explicit_iv_len ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", |
| add_data, add_data_len ); |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " |
| "including 0 bytes of padding", |
| rec->data_len ) ); |
| |
| /* |
| * Encrypt and authenticate |
| */ |
| |
| if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc, |
| iv, transform->ivlen, |
| add_data, add_data_len, /* add data */ |
| data, rec->data_len, /* source */ |
| data, &rec->data_len, /* destination */ |
| data + rec->data_len, transform->taglen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); |
| return( ret ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", |
| data + rec->data_len, transform->taglen ); |
| |
| rec->data_len += transform->taglen + explicit_iv_len; |
| rec->data_offset -= explicit_iv_len; |
| post_avail -= transform->taglen; |
| auth_done++; |
| } |
| else |
| #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ |
| #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
| ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) ) |
| if( mode == MBEDTLS_MODE_CBC ) |
| { |
| int ret; |
| size_t padlen, i; |
| size_t olen; |
| |
| /* Currently we're always using minimal padding |
| * (up to 255 bytes would be allowed). */ |
| padlen = transform->ivlen - ( rec->data_len + 1 ) % transform->ivlen; |
| if( padlen == transform->ivlen ) |
| padlen = 0; |
| |
| /* Check there's enough space in the buffer for the padding. */ |
| if( post_avail < padlen + 1 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| } |
| |
| for( i = 0; i <= padlen; i++ ) |
| data[rec->data_len + i] = (unsigned char) padlen; |
| |
| rec->data_len += padlen + 1; |
| post_avail -= padlen + 1; |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| /* |
| * Prepend per-record IV for block cipher in TLS v1.1 and up as per |
| * Method 1 (6.2.3.2. in RFC4346 and RFC5246) |
| */ |
| if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| if( f_rng == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "No PRNG provided to encrypt_record routine" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| if( rec->data_offset < transform->ivlen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| } |
| |
| /* |
| * Generate IV |
| */ |
| ret = f_rng( p_rng, transform->iv_enc, transform->ivlen ); |
| if( ret != 0 ) |
| return( ret ); |
| |
| memcpy( data - transform->ivlen, transform->iv_enc, |
| transform->ivlen ); |
| |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " |
| "including %d bytes of IV and %d bytes of padding", |
| rec->data_len, transform->ivlen, |
| padlen + 1 ) ); |
| |
| if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_enc, |
| transform->iv_enc, |
| transform->ivlen, |
| data, rec->data_len, |
| data, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( rec->data_len != olen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) |
| if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* |
| * Save IV in SSL3 and TLS1 |
| */ |
| memcpy( transform->iv_enc, transform->cipher_ctx_enc.iv, |
| transform->ivlen ); |
| } |
| else |
| #endif |
| { |
| data -= transform->ivlen; |
| rec->data_offset -= transform->ivlen; |
| rec->data_len += transform->ivlen; |
| } |
| |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| if( auth_done == 0 ) |
| { |
| unsigned char mac[MBEDTLS_SSL_MAC_ADD]; |
| |
| /* |
| * MAC(MAC_write_key, seq_num + |
| * TLSCipherText.type + |
| * TLSCipherText.version + |
| * length_of( (IV +) ENC(...) ) + |
| * IV + // except for TLS 1.0 |
| * ENC(content + padding + padding_length)); |
| */ |
| |
| if( post_avail < transform->maclen) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); |
| return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); |
| } |
| |
| ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, |
| add_data_len ); |
| |
| mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, |
| add_data_len ); |
| mbedtls_md_hmac_update( &transform->md_ctx_enc, |
| data, rec->data_len ); |
| mbedtls_md_hmac_finish( &transform->md_ctx_enc, mac ); |
| mbedtls_md_hmac_reset( &transform->md_ctx_enc ); |
| |
| memcpy( data + rec->data_len, mac, transform->maclen ); |
| |
| rec->data_len += transform->maclen; |
| post_avail -= transform->maclen; |
| auth_done++; |
| } |
| #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ |
| } |
| else |
| #endif /* MBEDTLS_CIPHER_MODE_CBC && |
| ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| /* Make extra sure authentication was performed, exactly once */ |
| if( auth_done != 1 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) ); |
| |
| return( 0 ); |
| } |
| |
| int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, |
| mbedtls_ssl_transform *transform, |
| mbedtls_record *rec ) |
| { |
| size_t olen; |
| mbedtls_cipher_mode_t mode; |
| int ret, auth_done = 0; |
| #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) |
| size_t padlen = 0, correct = 1; |
| #endif |
| unsigned char* data; |
| unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_IN_LEN_MAX ]; |
| size_t add_data_len; |
| |
| #if !defined(MBEDTLS_DEBUG_C) |
| ((void) ssl); |
| #endif |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); |
| if( rec == NULL || |
| rec->buf == NULL || |
| rec->buf_len < rec->data_offset || |
| rec->buf_len - rec->data_offset < rec->data_len ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad record structure provided to decrypt_buf" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| data = rec->buf + rec->data_offset; |
| mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_dec ); |
| |
| #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) |
| /* |
| * Match record's CID with incoming CID. |
| */ |
| if( rec->cid_len != transform->in_cid_len || |
| memcmp( rec->cid, transform->in_cid, rec->cid_len ) != 0 ) |
| { |
| return( MBEDTLS_ERR_SSL_UNEXPECTED_CID ); |
| } |
| #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ |
| |
| #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) |
| if( mode == MBEDTLS_MODE_STREAM ) |
| { |
| padlen = 0; |
| if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_dec, |
| transform->iv_dec, |
| transform->ivlen, |
| data, rec->data_len, |
| data, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( rec->data_len != olen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| } |
| else |
| #endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ |
| #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 ) |
| { |
| unsigned char iv[12]; |
| size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen; |
| |
| /* |
| * Prepare IV from explicit and implicit data. |
| */ |
| |
| /* Check that there's enough space for the explicit IV |
| * (at the beginning of the record) and the MAC (at the |
| * end of the record). */ |
| if( rec->data_len < explicit_iv_len + transform->taglen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " |
| "+ taglen (%d)", rec->data_len, |
| explicit_iv_len, transform->taglen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| |
| #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) |
| if( transform->ivlen == 12 && transform->fixed_ivlen == 4 ) |
| { |
| /* GCM and CCM: fixed || explicit */ |
| |
| /* Fixed */ |
| memcpy( iv, transform->iv_dec, transform->fixed_ivlen ); |
| /* Explicit */ |
| memcpy( iv + transform->fixed_ivlen, data, 8 ); |
| } |
| else |
| #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ |
| #if defined(MBEDTLS_CHACHAPOLY_C) |
| if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) |
| { |
| /* ChachaPoly: fixed XOR sequence number */ |
| unsigned char i; |
| |
| memcpy( iv, transform->iv_dec, transform->fixed_ivlen ); |
| |
| for( i = 0; i < 8; i++ ) |
| iv[i+4] ^= rec->ctr[i]; |
| } |
| else |
| #endif /* MBEDTLS_CHACHAPOLY_C */ |
| { |
| /* Reminder if we ever add an AEAD mode with a different size */ |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| /* Group changes to data, data_len, and add_data, because |
| * add_data depends on data_len. */ |
| data += explicit_iv_len; |
| rec->data_offset += explicit_iv_len; |
| rec->data_len -= explicit_iv_len + transform->taglen; |
| |
| ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", |
| add_data, add_data_len ); |
| |
| /* Because of the check above, we know that there are |
| * explicit_iv_len Bytes preceeding data, and taglen |
| * bytes following data + data_len. This justifies |
| * the debug message and the invocation of |
| * mbedtls_cipher_auth_decrypt() below. */ |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", iv, transform->ivlen ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", data + rec->data_len, |
| transform->taglen ); |
| |
| /* |
| * Decrypt and authenticate |
| */ |
| if( ( ret = mbedtls_cipher_auth_decrypt( &transform->cipher_ctx_dec, |
| iv, transform->ivlen, |
| add_data, add_data_len, |
| data, rec->data_len, |
| data, &olen, |
| data + rec->data_len, |
| transform->taglen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_decrypt", ret ); |
| |
| if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| |
| return( ret ); |
| } |
| auth_done++; |
| |
| /* Double-check that AEAD decryption doesn't change content length. */ |
| if( olen != rec->data_len ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| } |
| else |
| #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ |
| #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
| ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) ) |
| if( mode == MBEDTLS_MODE_CBC ) |
| { |
| size_t minlen = 0; |
| |
| /* |
| * Check immediate ciphertext sanity |
| */ |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* The ciphertext is prefixed with the CBC IV. */ |
| minlen += transform->ivlen; |
| } |
| #endif |
| |
| /* Size considerations: |
| * |
| * - The CBC cipher text must not be empty and hence |
| * at least of size transform->ivlen. |
| * |
| * Together with the potential IV-prefix, this explains |
| * the first of the two checks below. |
| * |
| * - The record must contain a MAC, either in plain or |
| * encrypted, depending on whether Encrypt-then-MAC |
| * is used or not. |
| * - If it is, the message contains the IV-prefix, |
| * the CBC ciphertext, and the MAC. |
| * - If it is not, the padded plaintext, and hence |
| * the CBC ciphertext, has at least length maclen + 1 |
| * because there is at least the padding length byte. |
| * |
| * As the CBC ciphertext is not empty, both cases give the |
| * lower bound minlen + maclen + 1 on the record size, which |
| * we test for in the second check below. |
| */ |
| if( rec->data_len < minlen + transform->ivlen || |
| rec->data_len < minlen + transform->maclen + 1 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) " |
| "+ 1 ) ( + expl IV )", rec->data_len, |
| transform->ivlen, |
| transform->maclen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| |
| /* |
| * Authenticate before decrypt if enabled |
| */ |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| if( transform->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) |
| { |
| unsigned char mac_expect[MBEDTLS_SSL_MAC_ADD]; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); |
| |
| /* Update data_len in tandem with add_data. |
| * |
| * The subtraction is safe because of the previous check |
| * data_len >= minlen + maclen + 1. |
| * |
| * Afterwards, we know that data + data_len is followed by at |
| * least maclen Bytes, which justifies the call to |
| * mbedtls_ssl_safer_memcmp() below. |
| * |
| * Further, we still know that data_len > minlen */ |
| rec->data_len -= transform->maclen; |
| ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); |
| |
| /* Calculate expected MAC. */ |
| MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, |
| add_data_len ); |
| mbedtls_md_hmac_update( &transform->md_ctx_dec, add_data, |
| add_data_len ); |
| mbedtls_md_hmac_update( &transform->md_ctx_dec, |
| data, rec->data_len ); |
| mbedtls_md_hmac_finish( &transform->md_ctx_dec, mac_expect ); |
| mbedtls_md_hmac_reset( &transform->md_ctx_dec ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", data + rec->data_len, |
| transform->maclen ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "expected mac", mac_expect, |
| transform->maclen ); |
| |
| /* Compare expected MAC with MAC at the end of the record. */ |
| if( mbedtls_ssl_safer_memcmp( data + rec->data_len, mac_expect, |
| transform->maclen ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| auth_done++; |
| } |
| #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ |
| |
| /* |
| * Check length sanity |
| */ |
| |
| /* We know from above that data_len > minlen >= 0, |
| * so the following check in particular implies that |
| * data_len >= minlen + ivlen ( = minlen or 2 * minlen ). */ |
| if( rec->data_len % transform->ivlen != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", |
| rec->data_len, transform->ivlen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| /* |
| * Initialize for prepended IV for block cipher in TLS v1.1 and up |
| */ |
| if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* Safe because data_len >= minlen + ivlen = 2 * ivlen. */ |
| memcpy( transform->iv_dec, data, transform->ivlen ); |
| |
| data += transform->ivlen; |
| rec->data_offset += transform->ivlen; |
| rec->data_len -= transform->ivlen; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| /* We still have data_len % ivlen == 0 and data_len >= ivlen here. */ |
| |
| if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_dec, |
| transform->iv_dec, transform->ivlen, |
| data, rec->data_len, data, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| /* Double-check that length hasn't changed during decryption. */ |
| if( rec->data_len != olen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) |
| if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* |
| * Save IV in SSL3 and TLS1, where CBC decryption of consecutive |
| * records is equivalent to CBC decryption of the concatenation |
| * of the records; in other words, IVs are maintained across |
| * record decryptions. |
| */ |
| memcpy( transform->iv_dec, transform->cipher_ctx_dec.iv, |
| transform->ivlen ); |
| } |
| #endif |
| |
| /* Safe since data_len >= minlen + maclen + 1, so after having |
| * subtracted at most minlen and maclen up to this point, |
| * data_len > 0 (because of data_len % ivlen == 0, it's actually |
| * >= ivlen ). */ |
| padlen = data[rec->data_len - 1]; |
| |
| if( auth_done == 1 ) |
| { |
| correct *= ( rec->data_len >= padlen + 1 ); |
| padlen *= ( rec->data_len >= padlen + 1 ); |
| } |
| else |
| { |
| #if defined(MBEDTLS_SSL_DEBUG_ALL) |
| if( rec->data_len < transform->maclen + padlen + 1 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", |
| rec->data_len, |
| transform->maclen, |
| padlen + 1 ) ); |
| } |
| #endif |
| |
| correct *= ( rec->data_len >= transform->maclen + padlen + 1 ); |
| padlen *= ( rec->data_len >= transform->maclen + padlen + 1 ); |
| } |
| |
| padlen++; |
| |
| /* Regardless of the validity of the padding, |
| * we have data_len >= padlen here. */ |
| |
|