| /* |
| * 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) |
| |
| #include "mbedtls/debug.h" |
| #include "mbedtls/ssl.h" |
| #include "mbedtls/ssl_internal.h" |
| |
| #include <string.h> |
| |
| #if defined(MBEDTLS_X509_CRT_PARSE_C) && \ |
| defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) |
| #include "mbedtls/oid.h" |
| #endif |
| |
| #if defined(MBEDTLS_PLATFORM_C) |
| #include "mbedtls/platform.h" |
| #else |
| #include <stdlib.h> |
| #define mbedtls_calloc calloc |
| #define mbedtls_free free |
| #endif |
| |
| /* Implementation that should never be optimized out by the compiler */ |
| static void mbedtls_zeroize( void *v, size_t n ) { |
| volatile unsigned char *p = v; while( n-- ) *p++ = 0; |
| } |
| |
| /* 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 ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| /* |
| * 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 ); |
| |
| 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 mfl_code_to_length[MBEDTLS_SSL_MAX_FRAG_LEN_INVALID] = |
| { |
| MBEDTLS_SSL_MAX_CONTENT_LEN, /* MBEDTLS_SSL_MAX_FRAG_LEN_NONE */ |
| 512, /* MBEDTLS_SSL_MAX_FRAG_LEN_512 */ |
| 1024, /* MBEDTLS_SSL_MAX_FRAG_LEN_1024 */ |
| 2048, /* MBEDTLS_SSL_MAX_FRAG_LEN_2048 */ |
| 4096, /* MBEDTLS_SSL_MAX_FRAG_LEN_4096 */ |
| }; |
| #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ |
| |
| #if defined(MBEDTLS_SSL_CLI_C) |
| static int 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( 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 ); |
| } |
| } |
| #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 ); |
| } |
| #endif /* MBEDTLS_SSL_CLI_C */ |
| |
| #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 ) |
| { |
| 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 ); |
| |
| mbedtls_sha1_starts( &sha1 ); |
| mbedtls_sha1_update( &sha1, padding, 1 + i ); |
| mbedtls_sha1_update( &sha1, secret, slen ); |
| mbedtls_sha1_update( &sha1, random, rlen ); |
| mbedtls_sha1_finish( &sha1, sha1sum ); |
| |
| mbedtls_md5_starts( &md5 ); |
| mbedtls_md5_update( &md5, secret, slen ); |
| mbedtls_md5_update( &md5, sha1sum, 20 ); |
| mbedtls_md5_finish( &md5, dstbuf + i * 16 ); |
| } |
| |
| mbedtls_md5_free( &md5 ); |
| mbedtls_sha1_free( &sha1 ); |
| |
| mbedtls_zeroize( padding, sizeof( padding ) ); |
| mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); |
| |
| return( 0 ); |
| } |
| #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[128]; |
| 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 ); |
| |
| if( sizeof( tmp ) < 20 + strlen( label ) + rlen ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| 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 ) |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| |
| if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) |
| return( ret ); |
| |
| 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 ) |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| |
| if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) |
| return( ret ); |
| |
| 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] ); |
| } |
| |
| mbedtls_md_free( &md_ctx ); |
| |
| mbedtls_zeroize( tmp, sizeof( tmp ) ); |
| mbedtls_zeroize( h_i, sizeof( h_i ) ); |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| 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[128]; |
| 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 ); |
| |
| if( sizeof( tmp ) < md_len + strlen( label ) + rlen ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| 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 ) |
| return( ret ); |
| |
| 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]; |
| } |
| |
| mbedtls_md_free( &md_ctx ); |
| |
| mbedtls_zeroize( tmp, sizeof( tmp ) ); |
| mbedtls_zeroize( h_i, sizeof( h_i ) ); |
| |
| return( 0 ); |
| } |
| |
| #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 */ |
| |
| int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) |
| { |
| int ret = 0; |
| unsigned char tmp[64]; |
| unsigned char keyblk[256]; |
| unsigned char *key1; |
| unsigned char *key2; |
| unsigned char *mac_enc; |
| unsigned char *mac_dec; |
| size_t iv_copy_len; |
| const mbedtls_cipher_info_t *cipher_info; |
| const mbedtls_md_info_t *md_info; |
| |
| mbedtls_ssl_session *session = ssl->session_negotiate; |
| mbedtls_ssl_transform *transform = ssl->transform_negotiate; |
| mbedtls_ssl_handshake_params *handshake = ssl->handshake; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); |
| |
| cipher_info = mbedtls_cipher_info_from_type( transform->ciphersuite_info->cipher ); |
| if( cipher_info == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", |
| transform->ciphersuite_info->cipher ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| md_info = mbedtls_md_info_from_type( transform->ciphersuite_info->mac ); |
| if( md_info == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found", |
| transform->ciphersuite_info->mac ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| /* |
| * 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 && |
| transform->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_BUF( 3, "premaster secret", handshake->premaster, |
| handshake->pmslen ); |
| |
| #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) |
| if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) |
| { |
| unsigned char session_hash[48]; |
| size_t hash_len; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); |
| |
| 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( ssl->transform_negotiate->ciphersuite_info->mac == |
| MBEDTLS_MD_SHA384 ) |
| { |
| hash_len = 48; |
| } |
| else |
| #endif |
| hash_len = 32; |
| } |
| else |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ |
| hash_len = 36; |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, hash_len ); |
| |
| ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, |
| "extended master secret", |
| session_hash, hash_len, |
| session->master, 48 ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); |
| return( ret ); |
| } |
| |
| } |
| else |
| #endif |
| ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, |
| "master secret", |
| handshake->randbytes, 64, |
| session->master, 48 ); |
| if( ret != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); |
| return( ret ); |
| } |
| |
| mbedtls_zeroize( handshake->premaster, sizeof(handshake->premaster) ); |
| } |
| else |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); |
| |
| /* |
| * 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_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 ); |
| |
| mbedtls_zeroize( handshake->randbytes, sizeof( handshake->randbytes ) ); |
| |
| /* |
| * Determine the appropriate key, IV and MAC length. |
| */ |
| |
| transform->keylen = cipher_info->key_bitlen / 8; |
| |
| if( cipher_info->mode == MBEDTLS_MODE_GCM || |
| cipher_info->mode == MBEDTLS_MODE_CCM ) |
| { |
| transform->maclen = 0; |
| |
| transform->ivlen = 12; |
| transform->fixed_ivlen = 4; |
| |
| /* Minimum length is expicit IV + tag */ |
| transform->minlen = transform->ivlen - transform->fixed_ivlen |
| + ( transform->ciphersuite_info->flags & |
| MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16 ); |
| } |
| else |
| { |
| /* 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 ); |
| return( ret ); |
| } |
| |
| /* Get MAC length */ |
| transform->maclen = mbedtls_md_get_size( md_info ); |
| |
| #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; |
| #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" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| } |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d", |
| transform->keylen, transform->minlen, transform->ivlen, |
| 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 + transform->maclen * 2; |
| key2 = keyblk + transform->maclen * 2 + transform->keylen; |
| |
| mac_enc = keyblk; |
| mac_dec = keyblk + transform->maclen; |
| |
| /* |
| * This is not used in TLS v1.1. |
| */ |
| iv_copy_len = ( transform->fixed_ivlen ) ? |
| transform->fixed_ivlen : transform->ivlen; |
| memcpy( transform->iv_enc, key2 + transform->keylen, iv_copy_len ); |
| memcpy( transform->iv_dec, key2 + transform->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 + transform->maclen * 2 + transform->keylen; |
| key2 = keyblk + transform->maclen * 2; |
| |
| mac_enc = keyblk + transform->maclen; |
| 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 + transform->keylen, iv_copy_len ); |
| memcpy( transform->iv_enc, key1 + transform->keylen + iv_copy_len, |
| iv_copy_len ); |
| } |
| else |
| #endif /* MBEDTLS_SSL_SRV_C */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| if( transform->maclen > sizeof transform->mac_enc ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| memcpy( transform->mac_enc, mac_enc, transform->maclen ); |
| memcpy( transform->mac_dec, mac_dec, transform->maclen ); |
| } |
| 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 ) |
| { |
| mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, transform->maclen ); |
| mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, transform->maclen ); |
| } |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| #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, transform->keylen, |
| transform->iv_enc, transform->iv_dec, |
| iv_copy_len, |
| mac_enc, mac_dec, |
| transform->maclen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| } |
| #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, |
| transform->maclen, transform->keylen, |
| iv_copy_len ); |
| } |
| #endif |
| |
| if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, |
| cipher_info ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); |
| return( ret ); |
| } |
| |
| if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, |
| cipher_info ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); |
| return( ret ); |
| } |
| |
| 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 ); |
| return( ret ); |
| } |
| |
| 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 ); |
| return( ret ); |
| } |
| |
| #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 ); |
| return( ret ); |
| } |
| |
| 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 ); |
| return( ret ); |
| } |
| } |
| #endif /* MBEDTLS_CIPHER_MODE_CBC */ |
| |
| mbedtls_zeroize( keyblk, sizeof( keyblk ) ); |
| |
| #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_BUFFER_LEN ); |
| if( ssl->compress_buf == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", |
| MBEDTLS_SSL_BUFFER_LEN ) ); |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| } |
| } |
| |
| 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" ) ); |
| return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); |
| } |
| } |
| #endif /* MBEDTLS_ZLIB_SUPPORT */ |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); |
| |
| return( 0 ); |
| } |
| |
| #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( &md5, ssl->session_negotiate->master, 48 ); |
| mbedtls_md5_update( &md5, pad_1, 48 ); |
| mbedtls_md5_finish( &md5, hash ); |
| |
| mbedtls_md5_starts( &md5 ); |
| mbedtls_md5_update( &md5, ssl->session_negotiate->master, 48 ); |
| mbedtls_md5_update( &md5, pad_2, 48 ); |
| mbedtls_md5_update( &md5, hash, 16 ); |
| mbedtls_md5_finish( &md5, hash ); |
| |
| mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); |
| mbedtls_sha1_update( &sha1, pad_1, 40 ); |
| mbedtls_sha1_finish( &sha1, hash + 16 ); |
| |
| mbedtls_sha1_starts( &sha1 ); |
| mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); |
| mbedtls_sha1_update( &sha1, pad_2, 40 ); |
| mbedtls_sha1_update( &sha1, hash + 16, 20 ); |
| mbedtls_sha1_finish( &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( &md5, hash ); |
| mbedtls_sha1_finish( &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] ) |
| { |
| 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( &sha256, hash ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); |
| |
| mbedtls_sha256_free( &sha256 ); |
| |
| return; |
| } |
| #endif /* MBEDTLS_SHA256_C */ |
| |
| #if defined(MBEDTLS_SHA512_C) |
| void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] ) |
| { |
| 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( &sha512, hash ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); |
| |
| mbedtls_sha512_free( &sha512 ); |
| |
| 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 + (int) psk_len ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| *(p++) = (unsigned char)( psk_len >> 8 ); |
| *(p++) = (unsigned char)( 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 |
| */ |
| *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_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.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 + (int) psk_len ) |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| |
| *(p++) = (unsigned char)( psk_len >> 8 ); |
| *(p++) = (unsigned char)( psk_len ); |
| 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 |
| */ |
| static void ssl_mac( mbedtls_md_context_t *md_ctx, unsigned char *secret, |
| unsigned char *buf, size_t len, |
| unsigned char *ctr, int type ) |
| { |
| 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, buf + len ); |
| |
| 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, buf + len, md_size ); |
| mbedtls_md_finish( md_ctx, buf + len ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_SSL3 */ |
| |
| #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ |
| ( defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
| ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) ) |
| #define SSL_SOME_MODES_USE_MAC |
| #endif |
| |
| /* |
| * Encryption/decryption functions |
| */ |
| static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) |
| { |
| mbedtls_cipher_mode_t mode; |
| int auth_done = 0; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); |
| |
| if( ssl->session_out == NULL || ssl->transform_out == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", |
| ssl->out_msg, ssl->out_msglen ); |
| |
| /* |
| * Add MAC before if needed |
| */ |
| #if defined(SSL_SOME_MODES_USE_MAC) |
| if( mode == MBEDTLS_MODE_STREAM || |
| ( mode == MBEDTLS_MODE_CBC |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| && ssl->session_out->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED |
| #endif |
| ) ) |
| { |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| ssl_mac( &ssl->transform_out->md_ctx_enc, |
| ssl->transform_out->mac_enc, |
| ssl->out_msg, ssl->out_msglen, |
| ssl->out_ctr, ssl->out_msgtype ); |
| } |
| else |
| #endif |
| #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 ) |
| { |
| mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 ); |
| mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 ); |
| mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 ); |
| mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, |
| ssl->out_msg, ssl->out_msglen ); |
| mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, |
| ssl->out_msg + ssl->out_msglen ); |
| mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); |
| } |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", |
| ssl->out_msg + ssl->out_msglen, |
| ssl->transform_out->maclen ); |
| |
| ssl->out_msglen += ssl->transform_out->maclen; |
| auth_done++; |
| } |
| #endif /* AEAD not the only option */ |
| |
| /* |
| * Encrypt |
| */ |
| #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) |
| if( mode == MBEDTLS_MODE_STREAM ) |
| { |
| int ret; |
| size_t olen = 0; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " |
| "including %d bytes of padding", |
| ssl->out_msglen, 0 ) ); |
| |
| if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, |
| ssl->transform_out->iv_enc, |
| ssl->transform_out->ivlen, |
| ssl->out_msg, ssl->out_msglen, |
| ssl->out_msg, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( ssl->out_msglen != 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) |
| if( mode == MBEDTLS_MODE_GCM || |
| mode == MBEDTLS_MODE_CCM ) |
| { |
| int ret; |
| size_t enc_msglen, olen; |
| unsigned char *enc_msg; |
| unsigned char add_data[13]; |
| unsigned char taglen = ssl->transform_out->ciphersuite_info->flags & |
| MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; |
| |
| memcpy( add_data, ssl->out_ctr, 8 ); |
| add_data[8] = ssl->out_msgtype; |
| mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, |
| ssl->conf->transport, add_data + 9 ); |
| add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; |
| add_data[12] = ssl->out_msglen & 0xFF; |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", |
| add_data, 13 ); |
| |
| /* |
| * Generate IV |
| */ |
| #if defined(MBEDTLS_SSL_AEAD_RANDOM_IV) |
| ret = ssl->conf->f_rng( ssl->conf->p_rng, |
| ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, |
| ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); |
| if( ret != 0 ) |
| return( ret ); |
| |
| memcpy( ssl->out_iv, |
| ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, |
| ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); |
| #else |
| if( ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen != 8 ) |
| { |
| /* 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 ); |
| } |
| |
| memcpy( ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, |
| ssl->out_ctr, 8 ); |
| memcpy( ssl->out_iv, ssl->out_ctr, 8 ); |
| #endif |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->out_iv, |
| ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); |
| |
| /* |
| * Fix pointer positions and message length with added IV |
| */ |
| enc_msg = ssl->out_msg; |
| enc_msglen = ssl->out_msglen; |
| ssl->out_msglen += ssl->transform_out->ivlen - |
| ssl->transform_out->fixed_ivlen; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " |
| "including %d bytes of padding", |
| ssl->out_msglen, 0 ) ); |
| |
| /* |
| * Encrypt and authenticate |
| */ |
| if( ( ret = mbedtls_cipher_auth_encrypt( &ssl->transform_out->cipher_ctx_enc, |
| ssl->transform_out->iv_enc, |
| ssl->transform_out->ivlen, |
| add_data, 13, |
| enc_msg, enc_msglen, |
| enc_msg, &olen, |
| enc_msg + enc_msglen, taglen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); |
| return( ret ); |
| } |
| |
| if( olen != enc_msglen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| ssl->out_msglen += taglen; |
| auth_done++; |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", enc_msg + enc_msglen, taglen ); |
| } |
| else |
| #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ |
| #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
| ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) |
| if( mode == MBEDTLS_MODE_CBC ) |
| { |
| int ret; |
| unsigned char *enc_msg; |
| size_t enc_msglen, padlen, olen = 0, i; |
| |
| padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) % |
| ssl->transform_out->ivlen; |
| if( padlen == ssl->transform_out->ivlen ) |
| padlen = 0; |
| |
| for( i = 0; i <= padlen; i++ ) |
| ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen; |
| |
| ssl->out_msglen += padlen + 1; |
| |
| enc_msglen = ssl->out_msglen; |
| enc_msg = ssl->out_msg; |
| |
| #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( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* |
| * Generate IV |
| */ |
| ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->transform_out->iv_enc, |
| ssl->transform_out->ivlen ); |
| if( ret != 0 ) |
| return( ret ); |
| |
| memcpy( ssl->out_iv, ssl->transform_out->iv_enc, |
| ssl->transform_out->ivlen ); |
| |
| /* |
| * Fix pointer positions and message length with added IV |
| */ |
| enc_msg = ssl->out_msg; |
| enc_msglen = ssl->out_msglen; |
| ssl->out_msglen += ssl->transform_out->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", |
| ssl->out_msglen, ssl->transform_out->ivlen, |
| padlen + 1 ) ); |
| |
| if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, |
| ssl->transform_out->iv_enc, |
| ssl->transform_out->ivlen, |
| enc_msg, enc_msglen, |
| enc_msg, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( enc_msglen != 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( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* |
| * Save IV in SSL3 and TLS1 |
| */ |
| memcpy( ssl->transform_out->iv_enc, |
| ssl->transform_out->cipher_ctx_enc.iv, |
| ssl->transform_out->ivlen ); |
| } |
| #endif |
| |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| if( auth_done == 0 ) |
| { |
| /* |
| * 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)); |
| */ |
| unsigned char pseudo_hdr[13]; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); |
| |
| memcpy( pseudo_hdr + 0, ssl->out_ctr, 8 ); |
| memcpy( pseudo_hdr + 8, ssl->out_hdr, 3 ); |
| pseudo_hdr[11] = (unsigned char)( ( ssl->out_msglen >> 8 ) & 0xFF ); |
| pseudo_hdr[12] = (unsigned char)( ( ssl->out_msglen ) & 0xFF ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); |
| |
| mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, pseudo_hdr, 13 ); |
| mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, |
| ssl->out_iv, ssl->out_msglen ); |
| mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, |
| ssl->out_iv + ssl->out_msglen ); |
| mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); |
| |
| ssl->out_msglen += ssl->transform_out->maclen; |
| auth_done++; |
| } |
| #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ |
| } |
| else |
| #endif /* MBEDTLS_CIPHER_MODE_CBC && |
| ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_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 ); |
| } |
| |
| #define SSL_MAX_MAC_SIZE 48 |
| |
| static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) |
| { |
| size_t i; |
| mbedtls_cipher_mode_t mode; |
| int auth_done = 0; |
| #if defined(SSL_SOME_MODES_USE_MAC) |
| size_t padlen = 0, correct = 1; |
| #endif |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); |
| |
| if( ssl->session_in == NULL || ssl->transform_in == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_in->cipher_ctx_dec ); |
| |
| if( ssl->in_msglen < ssl->transform_in->minlen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "in_msglen (%d) < minlen (%d)", |
| ssl->in_msglen, ssl->transform_in->minlen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| |
| #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) |
| if( mode == MBEDTLS_MODE_STREAM ) |
| { |
| int ret; |
| size_t olen = 0; |
| |
| padlen = 0; |
| |
| if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, |
| ssl->transform_in->iv_dec, |
| ssl->transform_in->ivlen, |
| ssl->in_msg, ssl->in_msglen, |
| ssl->in_msg, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( ssl->in_msglen != 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) |
| if( mode == MBEDTLS_MODE_GCM || |
| mode == MBEDTLS_MODE_CCM ) |
| { |
| int ret; |
| size_t dec_msglen, olen; |
| unsigned char *dec_msg; |
| unsigned char *dec_msg_result; |
| unsigned char add_data[13]; |
| unsigned char taglen = ssl->transform_in->ciphersuite_info->flags & |
| MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; |
| size_t explicit_iv_len = ssl->transform_in->ivlen - |
| ssl->transform_in->fixed_ivlen; |
| |
| if( ssl->in_msglen < explicit_iv_len + taglen ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " |
| "+ taglen (%d)", ssl->in_msglen, |
| explicit_iv_len, taglen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| dec_msglen = ssl->in_msglen - explicit_iv_len - taglen; |
| |
| dec_msg = ssl->in_msg; |
| dec_msg_result = ssl->in_msg; |
| ssl->in_msglen = dec_msglen; |
| |
| memcpy( add_data, ssl->in_ctr, 8 ); |
| add_data[8] = ssl->in_msgtype; |
| mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, |
| ssl->conf->transport, add_data + 9 ); |
| add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF; |
| add_data[12] = ssl->in_msglen & 0xFF; |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", |
| add_data, 13 ); |
| |
| memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, |
| ssl->in_iv, |
| ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec, |
| ssl->transform_in->ivlen ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, taglen ); |
| |
| /* |
| * Decrypt and authenticate |
| */ |
| if( ( ret = mbedtls_cipher_auth_decrypt( &ssl->transform_in->cipher_ctx_dec, |
| ssl->transform_in->iv_dec, |
| ssl->transform_in->ivlen, |
| add_data, 13, |
| dec_msg, dec_msglen, |
| dec_msg_result, &olen, |
| dec_msg + dec_msglen, 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++; |
| |
| if( olen != dec_msglen ) |
| { |
| 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) ) |
| if( mode == MBEDTLS_MODE_CBC ) |
| { |
| /* |
| * Decrypt and check the padding |
| */ |
| int ret; |
| unsigned char *dec_msg; |
| unsigned char *dec_msg_result; |
| size_t dec_msglen; |
| size_t minlen = 0; |
| size_t olen = 0; |
| |
| /* |
| * Check immediate ciphertext sanity |
| */ |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| minlen += ssl->transform_in->ivlen; |
| #endif |
| |
| if( ssl->in_msglen < minlen + ssl->transform_in->ivlen || |
| ssl->in_msglen < minlen + ssl->transform_in->maclen + 1 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) " |
| "+ 1 ) ( + expl IV )", ssl->in_msglen, |
| ssl->transform_in->ivlen, |
| ssl->transform_in->maclen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| |
| dec_msglen = ssl->in_msglen; |
| dec_msg = ssl->in_msg; |
| dec_msg_result = ssl->in_msg; |
| |
| /* |
| * Authenticate before decrypt if enabled |
| */ |
| #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) |
| if( ssl->session_in->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) |
| { |
| unsigned char computed_mac[SSL_MAX_MAC_SIZE]; |
| unsigned char pseudo_hdr[13]; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); |
| |
| dec_msglen -= ssl->transform_in->maclen; |
| ssl->in_msglen -= ssl->transform_in->maclen; |
| |
| memcpy( pseudo_hdr + 0, ssl->in_ctr, 8 ); |
| memcpy( pseudo_hdr + 8, ssl->in_hdr, 3 ); |
| pseudo_hdr[11] = (unsigned char)( ( ssl->in_msglen >> 8 ) & 0xFF ); |
| pseudo_hdr[12] = (unsigned char)( ( ssl->in_msglen ) & 0xFF ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); |
| |
| mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, pseudo_hdr, 13 ); |
| mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, |
| ssl->in_iv, ssl->in_msglen ); |
| mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, computed_mac ); |
| mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", ssl->in_iv + ssl->in_msglen, |
| ssl->transform_in->maclen ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", computed_mac, |
| ssl->transform_in->maclen ); |
| |
| if( mbedtls_ssl_safer_memcmp( ssl->in_iv + ssl->in_msglen, computed_mac, |
| ssl->transform_in->maclen ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); |
| |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| auth_done++; |
| } |
| #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ |
| |
| /* |
| * Check length sanity |
| */ |
| if( ssl->in_msglen % ssl->transform_in->ivlen != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", |
| ssl->in_msglen, ssl->transform_in->ivlen ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) |
| /* |
| * Initialize for prepended IV for block cipher in TLS v1.1 and up |
| */ |
| if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| dec_msglen -= ssl->transform_in->ivlen; |
| ssl->in_msglen -= ssl->transform_in->ivlen; |
| |
| for( i = 0; i < ssl->transform_in->ivlen; i++ ) |
| ssl->transform_in->iv_dec[i] = ssl->in_iv[i]; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ |
| |
| if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, |
| ssl->transform_in->iv_dec, |
| ssl->transform_in->ivlen, |
| dec_msg, dec_msglen, |
| dec_msg_result, &olen ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); |
| return( ret ); |
| } |
| |
| if( dec_msglen != 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( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| /* |
| * Save IV in SSL3 and TLS1 |
| */ |
| memcpy( ssl->transform_in->iv_dec, |
| ssl->transform_in->cipher_ctx_dec.iv, |
| ssl->transform_in->ivlen ); |
| } |
| #endif |
| |
| padlen = 1 + ssl->in_msg[ssl->in_msglen - 1]; |
| |
| if( ssl->in_msglen < ssl->transform_in->maclen + padlen && |
| auth_done == 0 ) |
| { |
| #if defined(MBEDTLS_SSL_DEBUG_ALL) |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", |
| ssl->in_msglen, ssl->transform_in->maclen, padlen ) ); |
| #endif |
| padlen = 0; |
| correct = 0; |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| if( padlen > ssl->transform_in->ivlen ) |
| { |
| #if defined(MBEDTLS_SSL_DEBUG_ALL) |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, " |
| "should be no more than %d", |
| padlen, ssl->transform_in->ivlen ) ); |
| #endif |
| correct = 0; |
| } |
| } |
| 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_0 ) |
| { |
| /* |
| * TLSv1+: always check the padding up to the first failure |
| * and fake check up to 256 bytes of padding |
| */ |
| size_t pad_count = 0, real_count = 1; |
| size_t padding_idx = ssl->in_msglen - padlen - 1; |
| |
| /* |
| * Padding is guaranteed to be incorrect if: |
| * 1. padlen >= ssl->in_msglen |
| * |
| * 2. padding_idx >= MBEDTLS_SSL_MAX_CONTENT_LEN + |
| * ssl->transform_in->maclen |
| * |
| * In both cases we reset padding_idx to a safe value (0) to |
| * prevent out-of-buffer reads. |
| */ |
| correct &= ( ssl->in_msglen >= padlen + 1 ); |
| correct &= ( padding_idx < MBEDTLS_SSL_MAX_CONTENT_LEN + |
| ssl->transform_in->maclen ); |
| |
| padding_idx *= correct; |
| |
| for( i = 1; i <= 256; i++ ) |
| { |
| real_count &= ( i <= padlen ); |
| pad_count += real_count * |
| ( ssl->in_msg[padding_idx + i] == padlen - 1 ); |
| } |
| |
| correct &= ( pad_count == padlen ); /* Only 1 on correct padding */ |
| |
| #if defined(MBEDTLS_SSL_DEBUG_ALL) |
| if( padlen > 0 && correct == 0 ) |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); |
| #endif |
| padlen &= correct * 0x1FF; |
| } |
| else |
| #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ |
| MBEDTLS_SSL_PROTO_TLS1_2 */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| ssl->in_msglen -= padlen; |
| } |
| else |
| #endif /* MBEDTLS_CIPHER_MODE_CBC && |
| ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "raw buffer after decryption", |
| ssl->in_msg, ssl->in_msglen ); |
| |
| /* |
| * Authenticate if not done yet. |
| * Compute the MAC regardless of the padding result (RFC4346, CBCTIME). |
| */ |
| #if defined(SSL_SOME_MODES_USE_MAC) |
| if( auth_done == 0 ) |
| { |
| unsigned char tmp[SSL_MAX_MAC_SIZE]; |
| |
| ssl->in_msglen -= ssl->transform_in->maclen; |
| |
| ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 ); |
| ssl->in_len[1] = (unsigned char)( ssl->in_msglen ); |
| |
| memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_SSL3) |
| if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) |
| { |
| ssl_mac( &ssl->transform_in->md_ctx_dec, |
| ssl->transform_in->mac_dec, |
| ssl->in_msg, ssl->in_msglen, |
| ssl->in_ctr, ssl->in_msgtype ); |
| } |
| 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_0 ) |
| { |
| /* |
| * Process MAC and always update for padlen afterwards to make |
| * total time independent of padlen |
| * |
| * extra_run compensates MAC check for padlen |
| * |
| * Known timing attacks: |
| * - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) |
| * |
| * We use ( ( Lx + 8 ) / 64 ) to handle 'negative Lx' values |
| * correctly. (We round down instead of up, so -56 is the correct |
| * value for our calculations instead of -55) |
| */ |
| size_t j, extra_run = 0; |
| extra_run = ( 13 + ssl->in_msglen + padlen + 8 ) / 64 - |
| ( 13 + ssl->in_msglen + 8 ) / 64; |
| |
| extra_run &= correct * 0xFF; |
| |
| mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 8 ); |
| mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_hdr, 3 ); |
| mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_len, 2 ); |
| mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg, |
| ssl->in_msglen ); |
| mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, |
| ssl->in_msg + ssl->in_msglen ); |
| /* Call mbedtls_md_process at least once due to cache attacks */ |
| for( j = 0; j < extra_run + 1; j++ ) |
| mbedtls_md_process( &ssl->transform_in->md_ctx_dec, ssl->in_msg ); |
| |
| mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); |
| } |
| else |
| #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ |
| MBEDTLS_SSL_PROTO_TLS1_2 */ |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", tmp, ssl->transform_in->maclen ); |
| MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen, |
| ssl->transform_in->maclen ); |
| |
| if( mbedtls_ssl_safer_memcmp( tmp, ssl->in_msg + ssl->in_msglen, |
| ssl->transform_in->maclen ) != 0 ) |
| { |
| #if defined(MBEDTLS_SSL_DEBUG_ALL) |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); |
| #endif |
| correct = 0; |
| } |
| auth_done++; |
| |
| /* |
| * Finally check the correct flag |
| */ |
| if( correct == 0 ) |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| #endif /* SSL_SOME_MODES_USE_MAC */ |
| |
| /* 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 ); |
| } |
| |
| if( ssl->in_msglen == 0 ) |
| { |
| ssl->nb_zero++; |
| |
| /* |
| * Three or more empty messages may be a DoS attack |
| * (excessive CPU consumption). |
| */ |
| if( ssl->nb_zero > 3 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "received four consecutive empty " |
| "messages, possible DoS attack" ) ); |
| return( MBEDTLS_ERR_SSL_INVALID_MAC ); |
| } |
| } |
| else |
| ssl->nb_zero = 0; |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| ; /* in_ctr read from peer, not maintained internally */ |
| } |
| else |
| #endif |
| { |
| for( i = 8; i > ssl_ep_len( ssl ); i-- ) |
| if( ++ssl->in_ctr[i - 1] != 0 ) |
| break; |
| |
| /* The loop goes to its end iff the counter is wrapping */ |
| if( i == ssl_ep_len( ssl ) ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) ); |
| return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); |
| } |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) ); |
| |
| return( 0 ); |
| } |
| |
| #undef MAC_NONE |
| #undef MAC_PLAINTEXT |
| #undef MAC_CIPHERTEXT |
| |
| #if defined(MBEDTLS_ZLIB_SUPPORT) |
| /* |
| * Compression/decompression functions |
| */ |
| static int ssl_compress_buf( mbedtls_ssl_context *ssl ) |
| { |
| int ret; |
| unsigned char *msg_post = ssl->out_msg; |
| size_t len_pre = ssl->out_msglen; |
| unsigned char *msg_pre = ssl->compress_buf; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); |
| |
| if( len_pre == 0 ) |
| return( 0 ); |
| |
| memcpy( msg_pre, ssl->out_msg, len_pre ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before compression: msglen = %d, ", |
| ssl->out_msglen ) ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "before compression: output payload", |
| ssl->out_msg, ssl->out_msglen ); |
| |
| ssl->transform_out->ctx_deflate.next_in = msg_pre; |
| ssl->transform_out->ctx_deflate.avail_in = len_pre; |
| ssl->transform_out->ctx_deflate.next_out = msg_post; |
| ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_BUFFER_LEN; |
| |
| ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); |
| if( ret != Z_OK ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform compression (%d)", ret ) ); |
| return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); |
| } |
| |
| ssl->out_msglen = MBEDTLS_SSL_BUFFER_LEN - |
| ssl->transform_out->ctx_deflate.avail_out; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", |
| ssl->out_msglen ) ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "after compression: output payload", |
| ssl->out_msg, ssl->out_msglen ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= compress buf" ) ); |
| |
| return( 0 ); |
| } |
| |
| static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) |
| { |
| int ret; |
| unsigned char *msg_post = ssl->in_msg; |
| size_t len_pre = ssl->in_msglen; |
| unsigned char *msg_pre = ssl->compress_buf; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); |
| |
| if( len_pre == 0 ) |
| return( 0 ); |
| |
| memcpy( msg_pre, ssl->in_msg, len_pre ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "before decompression: msglen = %d, ", |
| ssl->in_msglen ) ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "before decompression: input payload", |
| ssl->in_msg, ssl->in_msglen ); |
| |
| ssl->transform_in->ctx_inflate.next_in = msg_pre; |
| ssl->transform_in->ctx_inflate.avail_in = len_pre; |
| ssl->transform_in->ctx_inflate.next_out = msg_post; |
| ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_MAX_CONTENT_LEN; |
| |
| ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); |
| if( ret != Z_OK ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform decompression (%d)", ret ) ); |
| return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); |
| } |
| |
| ssl->in_msglen = MBEDTLS_SSL_MAX_CONTENT_LEN - |
| ssl->transform_in->ctx_inflate.avail_out; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", |
| ssl->in_msglen ) ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "after decompression: input payload", |
| ssl->in_msg, ssl->in_msglen ); |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decompress buf" ) ); |
| |
| return( 0 ); |
| } |
| #endif /* MBEDTLS_ZLIB_SUPPORT */ |
| |
| #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) |
| static int ssl_write_hello_request( mbedtls_ssl_context *ssl ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| static int ssl_resend_hello_request( mbedtls_ssl_context *ssl ) |
| { |
| /* If renegotiation is not enforced, retransmit until we would reach max |
| * timeout if we were using the usual handshake doubling scheme */ |
| if( ssl->conf->renego_max_records < 0 ) |
| { |
| uint32_t ratio = ssl->conf->hs_timeout_max / ssl->conf->hs_timeout_min + 1; |
| unsigned char doublings = 1; |
| |
| while( ratio != 0 ) |
| { |
| ++doublings; |
| ratio >>= 1; |
| } |
| |
| if( ++ssl->renego_records_seen > doublings ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "no longer retransmitting hello request" ) ); |
| return( 0 ); |
| } |
| } |
| |
| return( ssl_write_hello_request( ssl ) ); |
| } |
| #endif |
| #endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ |
| |
| /* |
| * Fill the input message buffer by appending data to it. |
| * The amount of data already fetched is in ssl->in_left. |
| * |
| * If we return 0, is it guaranteed that (at least) nb_want bytes are |
| * available (from this read and/or a previous one). Otherwise, an error code |
| * is returned (possibly EOF or WANT_READ). |
| * |
| * With stream transport (TLS) on success ssl->in_left == nb_want, but |
| * with datagram transport (DTLS) on success ssl->in_left >= nb_want, |
| * since we always read a whole datagram at once. |
| * |
| * For DTLS, it is up to the caller to set ssl->next_record_offset when |
| * they're done reading a record. |
| */ |
| int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) |
| { |
| int ret; |
| size_t len; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> fetch input" ) ); |
| |
| if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " |
| "or mbedtls_ssl_set_bio()" ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| if( nb_want > MBEDTLS_SSL_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| uint32_t timeout; |
| |
| /* Just to be sure */ |
| if( ssl->f_set_timer == NULL || ssl->f_get_timer == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "You must use " |
| "mbedtls_ssl_set_timer_cb() for DTLS" ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| /* |
| * The point is, we need to always read a full datagram at once, so we |
| * sometimes read more then requested, and handle the additional data. |
| * It could be the rest of the current record (while fetching the |
| * header) and/or some other records in the same datagram. |
| */ |
| |
| /* |
| * Move to the next record in the already read datagram if applicable |
| */ |
| if( ssl->next_record_offset != 0 ) |
| { |
| if( ssl->in_left < ssl->next_record_offset ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| ssl->in_left -= ssl->next_record_offset; |
| |
| if( ssl->in_left != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d", |
| ssl->next_record_offset ) ); |
| memmove( ssl->in_hdr, |
| ssl->in_hdr + ssl->next_record_offset, |
| ssl->in_left ); |
| } |
| |
| ssl->next_record_offset = 0; |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", |
| ssl->in_left, nb_want ) ); |
| |
| /* |
| * Done if we already have enough data. |
| */ |
| if( nb_want <= ssl->in_left) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); |
| return( 0 ); |
| } |
| |
| /* |
| * A record can't be split accross datagrams. If we need to read but |
| * are not at the beginning of a new record, the caller did something |
| * wrong. |
| */ |
| if( ssl->in_left != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| /* |
| * Don't even try to read if time's out already. |
| * This avoids by-passing the timer when repeatedly receiving messages |
| * that will end up being dropped. |
| */ |
| if( ssl_check_timer( ssl ) != 0 ) |
| ret = MBEDTLS_ERR_SSL_TIMEOUT; |
| else |
| { |
| len = MBEDTLS_SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); |
| |
| if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) |
| timeout = ssl->handshake->retransmit_timeout; |
| else |
| timeout = ssl->conf->read_timeout; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) ); |
| |
| if( ssl->f_recv_timeout != NULL ) |
| ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len, |
| timeout ); |
| else |
| ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len ); |
| |
| MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); |
| |
| if( ret == 0 ) |
| return( MBEDTLS_ERR_SSL_CONN_EOF ); |
| } |
| |
| if( ret == MBEDTLS_ERR_SSL_TIMEOUT ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "timeout" ) ); |
| ssl_set_timer( ssl, 0 ); |
| |
| if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) |
| { |
| if( ssl_double_retransmit_timeout( ssl ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake timeout" ) ); |
| return( MBEDTLS_ERR_SSL_TIMEOUT ); |
| } |
| |
| if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); |
| return( ret ); |
| } |
| |
| return( MBEDTLS_ERR_SSL_WANT_READ ); |
| } |
| #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) |
| else if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && |
| ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) |
| { |
| if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); |
| return( ret ); |
| } |
| |
| return( MBEDTLS_ERR_SSL_WANT_READ ); |
| } |
| #endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ |
| } |
| |
| if( ret < 0 ) |
| return( ret ); |
| |
| ssl->in_left = ret; |
| } |
| else |
| #endif |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", |
| ssl->in_left, nb_want ) ); |
| |
| while( ssl->in_left < nb_want ) |
| { |
| len = nb_want - ssl->in_left; |
| |
| if( ssl_check_timer( ssl ) != 0 ) |
| ret = MBEDTLS_ERR_SSL_TIMEOUT; |
| else |
| { |
| if( ssl->f_recv_timeout != NULL ) |
| { |
| ret = ssl->f_recv_timeout( ssl->p_bio, |
| ssl->in_hdr + ssl->in_left, len, |
| ssl->conf->read_timeout ); |
| } |
| else |
| { |
| ret = ssl->f_recv( ssl->p_bio, |
| ssl->in_hdr + ssl->in_left, len ); |
| } |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", |
| ssl->in_left, nb_want ) ); |
| MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); |
| |
| if( ret == 0 ) |
| return( MBEDTLS_ERR_SSL_CONN_EOF ); |
| |
| if( ret < 0 ) |
| return( ret ); |
| |
| ssl->in_left += ret; |
| } |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Flush any data not yet written |
| */ |
| int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) |
| { |
| int ret; |
| unsigned char *buf, i; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) ); |
| |
| if( ssl->f_send == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " |
| "or mbedtls_ssl_set_bio()" ) ); |
| return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); |
| } |
| |
| /* Avoid incrementing counter if data is flushed */ |
| if( ssl->out_left == 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); |
| return( 0 ); |
| } |
| |
| while( ssl->out_left > 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d", |
| mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) ); |
| |
| buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) + |
| ssl->out_msglen - ssl->out_left; |
| ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left ); |
| |
| MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret ); |
| |
| if( ret <= 0 ) |
| return( ret ); |
| |
| ssl->out_left -= ret; |
| } |
| |
| for( i = 8; i > ssl_ep_len( ssl ); i-- ) |
| if( ++ssl->out_ctr[i - 1] != 0 ) |
| break; |
| |
| /* The loop goes to its end iff the counter is wrapping */ |
| if( i == ssl_ep_len( ssl ) ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) ); |
| return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Functions to handle the DTLS retransmission state machine |
| */ |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| /* |
| * Append current handshake message to current outgoing flight |
| */ |
| static int ssl_flight_append( mbedtls_ssl_context *ssl ) |
| { |
| mbedtls_ssl_flight_item *msg; |
| |
| /* Allocate space for current message */ |
| if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", |
| sizeof( mbedtls_ssl_flight_item ) ) ); |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| } |
| |
| if( ( msg->p = mbedtls_calloc( 1, ssl->out_msglen ) ) == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", ssl->out_msglen ) ); |
| mbedtls_free( msg ); |
| return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); |
| } |
| |
| /* Copy current handshake message with headers */ |
| memcpy( msg->p, ssl->out_msg, ssl->out_msglen ); |
| msg->len = ssl->out_msglen; |
| msg->type = ssl->out_msgtype; |
| msg->next = NULL; |
| |
| /* Append to the current flight */ |
| if( ssl->handshake->flight == NULL ) |
| ssl->handshake->flight = msg; |
| else |
| { |
| mbedtls_ssl_flight_item *cur = ssl->handshake->flight; |
| while( cur->next != NULL ) |
| cur = cur->next; |
| cur->next = msg; |
| } |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Free the current flight of handshake messages |
| */ |
| static void ssl_flight_free( mbedtls_ssl_flight_item *flight ) |
| { |
| mbedtls_ssl_flight_item *cur = flight; |
| mbedtls_ssl_flight_item *next; |
| |
| while( cur != NULL ) |
| { |
| next = cur->next; |
| |
| mbedtls_free( cur->p ); |
| mbedtls_free( cur ); |
| |
| cur = next; |
| } |
| } |
| |
| #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) |
| static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ); |
| #endif |
| |
| /* |
| * Swap transform_out and out_ctr with the alternative ones |
| */ |
| static void ssl_swap_epochs( mbedtls_ssl_context *ssl ) |
| { |
| mbedtls_ssl_transform *tmp_transform; |
| unsigned char tmp_out_ctr[8]; |
| |
| if( ssl->transform_out == ssl->handshake->alt_transform_out ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip swap epochs" ) ); |
| return; |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "swap epochs" ) ); |
| |
| /* Swap transforms */ |
| tmp_transform = ssl->transform_out; |
| ssl->transform_out = ssl->handshake->alt_transform_out; |
| ssl->handshake->alt_transform_out = tmp_transform; |
| |
| /* Swap epoch + sequence_number */ |
| memcpy( tmp_out_ctr, ssl->out_ctr, 8 ); |
| memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 ); |
| memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 ); |
| |
| /* Adjust to the newly activated transform */ |
| if( ssl->transform_out != NULL && |
| ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) |
| { |
| ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen - |
| ssl->transform_out->fixed_ivlen; |
| } |
| else |
| ssl->out_msg = ssl->out_iv; |
| |
| #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) |
| if( mbedtls_ssl_hw_record_activate != NULL ) |
| { |
| if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| } |
| #endif |
| } |
| |
| /* |
| * Retransmit the current flight of messages. |
| * |
| * Need to remember the current message in case flush_output returns |
| * WANT_WRITE, causing us to exit this function and come back later. |
| * This function must be called until state is no longer SENDING. |
| */ |
| int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); |
| |
| if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) ); |
| |
| ssl->handshake->cur_msg = ssl->handshake->flight; |
| ssl_swap_epochs( ssl ); |
| |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; |
| } |
| |
| while( ssl->handshake->cur_msg != NULL ) |
| { |
| int ret; |
| mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg; |
| |
| /* Swap epochs before sending Finished: we can't do it after |
| * sending ChangeCipherSpec, in case write returns WANT_READ. |
| * Must be done before copying, may change out_msg pointer */ |
| if( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && |
| cur->p[0] == MBEDTLS_SSL_HS_FINISHED ) |
| { |
| ssl_swap_epochs( ssl ); |
| } |
| |
| memcpy( ssl->out_msg, cur->p, cur->len ); |
| ssl->out_msglen = cur->len; |
| ssl->out_msgtype = cur->type; |
| |
| ssl->handshake->cur_msg = cur->next; |
| |
| MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 ); |
| |
| if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); |
| return( ret ); |
| } |
| } |
| |
| if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; |
| else |
| { |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; |
| ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * To be called when the last message of an incoming flight is received. |
| */ |
| void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) |
| { |
| /* We won't need to resend that one any more */ |
| ssl_flight_free( ssl->handshake->flight ); |
| ssl->handshake->flight = NULL; |
| ssl->handshake->cur_msg = NULL; |
| |
| /* The next incoming flight will start with this msg_seq */ |
| ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq; |
| |
| /* Cancel timer */ |
| ssl_set_timer( ssl, 0 ); |
| |
| if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && |
| ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) |
| { |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; |
| } |
| else |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; |
| } |
| |
| /* |
| * To be called when the last message of an outgoing flight is send. |
| */ |
| void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) |
| { |
| ssl_reset_retransmit_timeout( ssl ); |
| ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); |
| |
| if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && |
| ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) |
| { |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; |
| } |
| else |
| ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| /* |
| * Record layer functions |
| */ |
| |
| /* |
| * Write current record. |
| * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg. |
| */ |
| int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) |
| { |
| int ret, done = 0; |
| size_t len = ssl->out_msglen; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && |
| ssl->handshake != NULL && |
| ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) |
| { |
| ; /* Skip special handshake treatment when resending */ |
| } |
| else |
| #endif |
| if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) |
| { |
| if( ssl->out_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST && |
| ssl->handshake == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); |
| return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); |
| } |
| |
| ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); |
| ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 ); |
| ssl->out_msg[3] = (unsigned char)( ( len - 4 ) ); |
| |
| /* |
| * DTLS has additional fields in the Handshake layer, |
| * between the length field and the actual payload: |
| * uint16 message_seq; |
| * uint24 fragment_offset; |
| * uint24 fragment_length; |
| */ |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) |
| { |
| /* Make room for the additional DTLS fields */ |
| memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 ); |
| ssl->out_msglen += 8; |
| len += 8; |
| |
| /* Write message_seq and update it, except for HelloRequest */ |
| if( ssl->out_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST ) |
| { |
| ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF; |
| ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF; |
| ++( ssl->handshake->out_msg_seq ); |
| } |
| else |
| { |
| ssl->out_msg[4] = 0; |
| ssl->out_msg[5] = 0; |
| } |
| |
| /* We don't fragment, so frag_offset = 0 and frag_len = len */ |
| memset( ssl->out_msg + 6, 0x00, 3 ); |
| memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 ); |
| } |
| #endif /* MBEDTLS_SSL_PROTO_DTLS */ |
| |
| if( ssl->out_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST ) |
| ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); |
| } |
| |
| /* Save handshake and CCS messages for resending */ |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && |
| ssl->handshake != NULL && |
| ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING && |
| ( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC || |
| ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) ) |
| { |
| if( ( ret = ssl_flight_append( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "ssl_flight_append", ret ); |
| return( ret ); |
| } |
| } |
| #endif |
| |
| #if defined(MBEDTLS_ZLIB_SUPPORT) |
| if( ssl->transform_out != NULL && |
| ssl->session_out->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) |
| { |
| if( ( ret = ssl_compress_buf( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compress_buf", ret ); |
| return( ret ); |
| } |
| |
| len = ssl->out_msglen; |
| } |
| #endif /*MBEDTLS_ZLIB_SUPPORT */ |
| |
| #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) |
| if( mbedtls_ssl_hw_record_write != NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_write()" ) ); |
| |
| ret = mbedtls_ssl_hw_record_write( ssl ); |
| if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_write", ret ); |
| return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); |
| } |
| |
| if( ret == 0 ) |
| done = 1; |
| } |
| #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ |
| if( !done ) |
| { |
| ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; |
| mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, |
| ssl->conf->transport, ssl->out_hdr + 1 ); |
| |
| ssl->out_len[0] = (unsigned char)( len >> 8 ); |
| ssl->out_len[1] = (unsigned char)( len ); |
| |
| if( ssl->transform_out != NULL ) |
| { |
| if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); |
| return( ret ); |
| } |
| |
| len = ssl->out_msglen; |
| ssl->out_len[0] = (unsigned char)( len >> 8 ); |
| ssl->out_len[1] = (unsigned char)( len ); |
| } |
| |
| ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen; |
| |
| MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " |
| "version = [%d:%d], msglen = %d", |
| ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2], |
| ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) ); |
| |
| MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network", |
| ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen ); |
| } |
| |
| if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) |
| { |
| MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); |
| return( ret ); |
| } |
| |
| MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write record" ) ); |
| |
| return( 0 ); |
| } |
| |
| #if defined(MBEDTLS_SSL_PROTO_DTLS) |
| /* |
| * Mark bits in bitmask (used for DTLS HS reassembly) |
| */ |
| static void ssl_bitmask_set( unsigned char *mask, size_t offset, size_t len ) |
| { |
| unsigned int start_bits, end_bits; |
| |
| start_bits = 8 - ( offset % 8 ); |
| if( start_bits != 8 ) |
| { |
| size_t first_byte_idx = offset / 8; |
| |
| /* Special case */ |
| if( len <= start_bits ) |
| { |
| for( ; len != 0; len-- ) |
| mask[first_byte_idx] |= 1 << ( start_bits - len ); |
| |
| /* Avoid potential issues with offset or len becoming invalid */ |
| return; |
| } |
| |
| offset += start_bits; /* Now offset % 8 == 0 */ |
| len -= start_bits; |
| |
| for( ; start_bits != 0; start_bits-- ) |
| mask[first_byte_idx] |= 1 << ( start_bits - 1 ); |
| } |
| |
| end_bits = len % 8; |
| if( end_bits != 0 ) |
| { |
| size_t last_byte_idx = ( offset + len ) / 8; |
| |
| len -= end_bits; /* Now len % 8 == 0 */ |
| |
| for( ; end_bits != 0; end_bits-- ) |
| mask[last_byte_idx] |= 1 << ( 8 - end_bits ); |
| } |
| |
| memset( mask + offset / 8, 0xFF, len / 8 ); |
| } |
| |
| /* |
| * Check that bitmask is full |
| */ |
| static int ssl_bitmask_check( unsigned char *mask, size_t len ) |
| { |
| size_t i; |
| |
| for( i = 0; i < len / 8; i++ ) |
| if( mask[i] != 0xFF ) |
| return( -1 ); |
| |
| for( i = 0; i < len % 8; i++ ) |
| if( ( mask[len / 8] & ( 1 << ( 7 - i ) ) ) == 0 ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| /* |
| * Reassemble fragmented DTLS handshake messages. |
| * |
| * Use a temporary buffer for reassembly, divided in two parts: |
| * - the first holds the reassembled message (including handshake header), |
| * - the second holds a bitmask indicating which parts of the message |
| * (excluding headers) have been received so far. |
| */ |
| static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl ) |
| { |
| unsigned char *msg, *bitmask; |
| size_t frag_len, frag_off; |
| size_t msg_len = ssl->in_hslen - 12; /* Without headers */ |
| |
| if( ssl->handshake == NULL ) |
| { |
| MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) ); |
| return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); |
| } |
| |
| /* |
|