blob: 03d84e370d2fa7f376f062ac021d5d6416fd2e90 [file] [log] [blame]
/*
* 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/ssl.h"
#include "mbedtls/ssl_internal.h"
#include "mbedtls/debug.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/version.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 uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl );
/*
* Start a timer.
* Passing millisecs = 0 cancels a running timer.
*/
void mbedtls_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.
*/
int mbedtls_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 );
}
#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_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
{
mbedtls_record rec;
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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) );
if( dst->peer_cert == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
mbedtls_x509_crt_init( dst->peer_cert );
if( ( ret = mbedtls_x509_crt_parse_der( dst->peer_cert, src->peer_cert->raw.p,
src->peer_cert->raw.len ) ) != 0 )
{
mbedtls_free( dst->peer_cert );
dst->peer_cert = NULL;
return( ret );
}
}
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( src->peer_cert_digest != NULL )
{
dst->peer_cert_digest =
mbedtls_calloc( 1, src->peer_cert_digest_len );
if( dst->peer_cert_digest == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
memcpy( dst->peer_cert_digest, src->peer_cert_digest,
src->peer_cert_digest_len );
dst->peer_cert_digest_type = src->peer_cert_digest_type;
dst->peer_cert_digest_len = src->peer_cert_digest_len;
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
if( src->ticket != NULL )
{
dst->ticket = mbedtls_calloc( 1, src->ticket_len );
if( dst->ticket == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
memcpy( dst->ticket, src->ticket, src->ticket_len );
}
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
return( 0 );
}
#if defined(MBEDTLS_SSL_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_ERR_ERROR_CORRUPTION_DETECTED;
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 psa_status_t setup_psa_key_derivation( psa_key_derivation_operation_t* derivation,
psa_key_handle_t slot,
psa_algorithm_t alg,
const unsigned char* seed, size_t seed_length,
const unsigned char* label, size_t label_length,
size_t capacity )
{
psa_status_t status;
status = psa_key_derivation_setup( derivation, alg );
if( status != PSA_SUCCESS )
return( status );
if( PSA_ALG_IS_TLS12_PRF( alg ) || PSA_ALG_IS_TLS12_PSK_TO_MS( alg ) )
{
status = psa_key_derivation_input_bytes( derivation,
PSA_KEY_DERIVATION_INPUT_SEED,
seed, seed_length );
if( status != PSA_SUCCESS )
return( status );
if( slot == 0 )
{
status = psa_key_derivation_input_bytes(
derivation, PSA_KEY_DERIVATION_INPUT_SECRET,
NULL, 0 );
}
else
{
status = psa_key_derivation_input_key(
derivation, PSA_KEY_DERIVATION_INPUT_SECRET,
slot );
}
if( status != PSA_SUCCESS )
return( status );
status = psa_key_derivation_input_bytes( derivation,
PSA_KEY_DERIVATION_INPUT_LABEL,
label, label_length );
if( status != PSA_SUCCESS )
return( status );
}
else
{
return( PSA_ERROR_NOT_SUPPORTED );
}
status = psa_key_derivation_set_capacity( derivation, capacity );
if( status != PSA_SUCCESS )
return( status );
return( PSA_SUCCESS );
}
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_handle_t master_slot = 0;
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);
/* Normally a "secret" should be long enough to be impossible to
* find by brute force, and in particular should not be empty. But
* this PRF is also used to derive an IV, in particular in EAP-TLS,
* and for this use case it makes sense to have a 0-length "secret".
* Since the key API doesn't allow importing a key of length 0,
* keep master_slot=0, which setup_psa_key_derivation() understands
* to mean a 0-length "secret" input. */
if( slen != 0 )
{
psa_key_attributes_t 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 = setup_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 );
}
if( master_slot != 0 )
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_ERR_ERROR_CORRUPTION_DETECTED;
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 *, size_t * );
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 *, size_t * );
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 *, size_t * );
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 *, size_t * );
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 ) );
}
/* Type for the TLS PRF */
typedef int ssl_tls_prf_t(const unsigned char *, size_t, const char *,
const unsigned char *, size_t,
unsigned char *, size_t);
/*
* Populate a transform structure with session keys and all the other
* necessary information.
*
* Parameters:
* - [in/out]: transform: structure to populate
* [in] must be just initialised with mbedtls_ssl_transform_init()
* [out] fully populated, ready for use by mbedtls_ssl_{en,de}crypt_buf()
* - [in] ciphersuite
* - [in] master
* - [in] encrypt_then_mac
* - [in] trunc_hmac
* - [in] compression
* - [in] tls_prf: pointer to PRF to use for key derivation
* - [in] randbytes: buffer holding ServerHello.random + ClientHello.random
* - [in] minor_ver: SSL/TLS minor version
* - [in] endpoint: client or server
* - [in] ssl: optionally used for:
* - MBEDTLS_SSL_HW_RECORD_ACCEL: whole context
* - MBEDTLS_SSL_EXPORT_KEYS: ssl->conf->{f,p}_export_keys
* - MBEDTLS_DEBUG_C: ssl->conf->{f,p}_dbg
*/
static int ssl_populate_transform( mbedtls_ssl_transform *transform,
int ciphersuite,
const unsigned char master[48],
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
int encrypt_then_mac,
#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
int trunc_hmac,
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_ZLIB_SUPPORT)
int compression,
#endif
ssl_tls_prf_t tls_prf,
const unsigned char randbytes[64],
int minor_ver,
unsigned endpoint,
const mbedtls_ssl_context *ssl )
{
int ret = 0;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
int psa_fallthrough;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
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;
#if !defined(MBEDTLS_SSL_HW_RECORD_ACCEL) && \
!defined(MBEDTLS_SSL_EXPORT_KEYS) && \
!defined(MBEDTLS_DEBUG_C)
ssl = NULL; /* make sure we don't use it except for those cases */
(void) ssl;
#endif
/*
* Some data just needs copying into the structure
*/
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
transform->encrypt_then_mac = encrypt_then_mac;
#endif
transform->minor_ver = minor_ver;
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
memcpy( transform->randbytes, randbytes, sizeof( transform->randbytes ) );
#endif
/*
* Get various info structures
*/
ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite );
if( ciphersuite_info == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %d not found",
ciphersuite ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
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 */
/*
* Compute key block using the PRF
*/
ret = tls_prf( master, 48, "key expansion", 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( ciphersuite ) ) );
MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", master, 48 );
MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", 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( 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( 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( minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ||
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( minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 ||
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( 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( 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( 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( 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,
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,
master, keyblk,
mac_key_len, keylen,
iv_copy_len,
randbytes + 32,
randbytes,
tls_prf_get_type( 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 */
/* Initialize Zlib contexts */
#if defined(MBEDTLS_ZLIB_SUPPORT)
if( compression == MBEDTLS_SSL_COMPRESS_DEFLATE )
{
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 */
end:
mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) );
return( ret );
}
/*
* Set appropriate PRF function and other SSL / TLS 1.0/1.1 / TLS1.2 functions
*
* Inputs:
* - SSL/TLS minor version
* - hash associated with the ciphersuite (only used by TLS 1.2)
*
* Outputs:
* - 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, psk_opaque
* [out] premaster (cleared)
* [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: minor_ver, conf
*/
static int ssl_compute_master( mbedtls_ssl_handshake_params *handshake,
unsigned char *master,
const mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* 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))
ssl = NULL; /* make sure we don't use it except for those cases */
(void) ssl;
#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 )
{
lbl = "extended master secret";
salt = session_hash;
handshake->calc_verify( ssl, session_hash, &salt_len );
MBEDTLS_SSL_DEBUG_BUF( 3, "session hash for extended master secret",
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 &&
ssl->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_md_type_t hash_alg = handshake->ciphersuite_info->mac;
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 = setup_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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
ssl->handshake->ciphersuite_info;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
/* Set PRF, calc_verify and calc_finished function pointers */
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 );
}
/* Compute master secret if needed */
ret = ssl_compute_master( ssl->handshake,
ssl->session_negotiate->master,
ssl );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compute_master", ret );
return( ret );
}
/* Swap the client and server random values:
* - MS derivation wanted client+server (RFC 5246 8.1)
* - key derivation wants server+client (RFC 5246 6.3) */
{
unsigned char tmp[64];
memcpy( tmp, ssl->handshake->randbytes, 64 );
memcpy( ssl->handshake->randbytes, tmp + 32, 32 );
memcpy( ssl->handshake->randbytes + 32, tmp, 32 );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
}
/* Populate transform structure */
ret = ssl_populate_transform( ssl->transform_negotiate,
ssl->session_negotiate->ciphersuite,
ssl->session_negotiate->master,
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
ssl->session_negotiate->encrypt_then_mac,
#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
ssl->session_negotiate->trunc_hmac,
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_ZLIB_SUPPORT)
ssl->session_negotiate->compression,
#endif
ssl->handshake->tls_prf,
ssl->handshake->randbytes,
ssl->minor_ver,
ssl->conf->endpoint,
ssl );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_populate_transform", ret );
return( ret );
}
/* We no longer need Server/ClientHello.random values */
mbedtls_platform_zeroize( ssl->handshake->randbytes,
sizeof( ssl->handshake->randbytes ) );
/* Allocate compression buffer */
#if defined(MBEDTLS_ZLIB_SUPPORT)
if( ssl->session_negotiate->compression == MBEDTLS_SSL_COMPRESS_DEFLATE &&
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 ) );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}
}
#endif
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) );
return( 0 );
}
#if defined(MBEDTLS_SSL_PROTO_SSL3)
void ssl_calc_verify_ssl( const mbedtls_ssl_context *ssl,
unsigned char hash[36],
size_t *hlen )
{
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 );
*hlen = 36;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
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],
size_t *hlen )
{
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 );
*hlen = 36;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
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],
size_t *hlen )
{
#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;
}
*hlen = 32;
MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, *hlen );
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 );
*hlen = 32;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
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],
size_t *hlen )
{
#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;
}
*hlen = 48;
MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, *hlen );
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 );
*hlen = 48;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
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)
ssl = NULL; /* make sure we don't use it except for debug */
((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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
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)
ssl = NULL; /* make sure we don't use it except for debug */
((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.
*