/* | |
* 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 | |
#if defined(MBEDTLS_USE_PSA_CRYPTO) | |
#include "mbedtls/psa_util.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 ); | |
#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 ); | |
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_policy_t policy; | |
psa_key_handle_t master_slot; | |
psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; | |
if( ( status = psa_allocate_key( &master_slot ) ) != PSA_SUCCESS ) | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
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); | |
policy = psa_key_policy_init(); | |
psa_key_policy_set_usage( &policy, | |
PSA_KEY_USAGE_DERIVE, | |
alg ); | |
status = psa_set_key_policy( master_slot, &policy ); | |
if( status != PSA_SUCCESS ) | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
status = psa_import_key( master_slot, PSA_KEY_TYPE_DERIVE, secret, slen ); | |
if( status != PSA_SUCCESS ) | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
status = psa_key_derivation( &generator, | |
master_slot, alg, | |
random, rlen, | |
(unsigned char const *) label, | |
(size_t) strlen( label ), | |
dlen ); | |
if( status != PSA_SUCCESS ) | |
{ | |
psa_generator_abort( &generator ); | |
psa_destroy_key( master_slot ); | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
} | |
status = psa_generator_read( &generator, dstbuf, dlen ); | |
if( status != PSA_SUCCESS ) | |
{ | |
psa_generator_abort( &generator ); | |
psa_destroy_key( master_slot ); | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
} | |
status = psa_generator_abort( &generator ); | |
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( 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( 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( 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( 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 ) ); | |
} | |
int mbedtls_ssl_derive_keys( 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; | |
/* 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 */ | |
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 */ | |
/* | |
* Set appropriate PRF function and other SSL / TLS / TLS1.2 functions | |
*/ | |
#if defined(MBEDTLS_SSL_PROTO_SSL3) | |
if( ssl->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( ssl->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( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && | |
ciphersuite_info->mac == 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( ssl->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 */ | |
{ | |
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); | |
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); | |
} | |
/* | |
* SSLv3: | |
* master = | |
* MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + | |
* MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + | |
* MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) | |
* | |
* TLSv1+: | |
* master = PRF( premaster, "master secret", randbytes )[0..47] | |
*/ | |
if( handshake->resume != 0 ) | |
{ | |
MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); | |
} | |
else | |
{ | |
/* 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_SSL_EXTENDED_MASTER_SECRET) | |
if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) | |
{ | |
MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); | |
lbl = "extended master secret"; | |
salt = session_hash; | |
ssl->handshake->calc_verify( ssl, session_hash ); | |
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) | |
if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) | |
{ | |
#if defined(MBEDTLS_SHA512_C) | |
if( ciphersuite_info->mac == 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( 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_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; | |
psa_key_handle_t psk; | |
MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) ); | |
psk = ssl->conf->psk_opaque; | |
if( ssl->handshake->psk_opaque != 0 ) | |
psk = ssl->handshake->psk_opaque; | |
if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) | |
alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384); | |
else | |
alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256); | |
status = psa_key_derivation( &generator, psk, alg, | |
salt, salt_len, | |
(unsigned char const *) lbl, | |
(size_t) strlen( lbl ), | |
master_secret_len ); | |
if( status != PSA_SUCCESS ) | |
{ | |
psa_generator_abort( &generator ); | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
} | |
status = psa_generator_read( &generator, session->master, | |
master_secret_len ); | |
if( status != PSA_SUCCESS ) | |
{ | |
psa_generator_abort( &generator ); | |
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); | |
} | |
status = psa_generator_abort( &generator ); | |
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, | |
session->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) ); | |
} | |
} | |
/* | |
* 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 ); | |
} | |
#if defined(MBEDTLS_SSL_PROTO_SSL3) | |
void ssl_calc_verify_ssl( 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( 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( 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( 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 *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 ]; | |