You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by st...@apache.org on 2016/09/28 00:43:45 UTC
[19/51] [abbrv] [partial] incubator-mynewt-core git commit: directory
re-org, part 1
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/0216c73e/crypto/mbedtls/src/ssl_tls.c
----------------------------------------------------------------------
diff --git a/crypto/mbedtls/src/ssl_tls.c b/crypto/mbedtls/src/ssl_tls.c
new file mode 100644
index 0000000..4424f56
--- /dev/null
+++ b/crypto/mbedtls/src/ssl_tls.c
@@ -0,0 +1,7602 @@
+/*
+ * 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 )
+ 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
+ */
+ *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 )
+ 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
+ */
+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 &&
+
<TRUNCATED>