diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index bd2c939c4..69e7a06e3 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -34,6 +34,7 @@ #include "rsa.h" #include "md5.h" #include "sha1.h" +#include "sha2.h" #include "x509.h" #include "config.h" @@ -90,6 +91,7 @@ #define SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ #define SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ #define SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ #define SSL_IS_CLIENT 0 #define SSL_IS_SERVER 1 @@ -130,6 +132,19 @@ #define SSL_RSA_CAMELLIA_256_SHA 0x84 #define SSL_EDH_RSA_CAMELLIA_256_SHA 0x88 +/* + * Supported Signature and Hash algorithms (For TLS 1.2) + */ +#define SSL_HASH_NONE 0 +#define SSL_HASH_MD5 1 +#define SSL_HASH_SHA1 2 +#define SSL_HASH_SHA224 3 +#define SSL_HASH_SHA256 4 +#define SSL_HASH_SHA384 5 +#define SSL_HASH_SHA512 6 + +#define SSL_SIG_RSA 1 + /* * Message, alert and handshake types */ @@ -310,6 +325,12 @@ struct _ssl_context dhm_context dhm_ctx; /*!< DHM key exchange */ md5_context fin_md5; /*!< Finished MD5 checksum */ sha1_context fin_sha1; /*!< Finished SHA-1 checksum */ + sha2_context fin_sha2; /*!< Finished SHA-256 checksum */ + + void (*calc_finished)(ssl_context *, unsigned char *, int); + int (*tls_prf)(unsigned char *, size_t, char *, + unsigned char *, size_t, + unsigned char *, size_t); int do_crypt; /*!< en(de)cryption flag */ int *ciphersuites; /*!< allowed ciphersuites */ @@ -578,7 +599,8 @@ int ssl_set_hostname( ssl_context *ssl, const char *hostname ); * \param ssl SSL context * \param major Major version number (only SSL_MAJOR_VERSION_3 supported) * \param minor Minor version number (SSL_MINOR_VERSION_0, - * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2 supported) + * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2, + * SSL_MINOR_VERSION_3 supported) */ void ssl_set_max_version( ssl_context *ssl, int major, int minor ); diff --git a/library/dhm.c b/library/dhm.c index bddd076d1..ef456afe9 100644 --- a/library/dhm.c +++ b/library/dhm.c @@ -113,12 +113,6 @@ int dhm_read_params( dhm_context *ctx, if( end - *p < 2 ) return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); - n = ( (*p)[0] << 8 ) | (*p)[1]; - (*p) += 2; - - if( end != *p + n ) - return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); - return( 0 ); } diff --git a/library/ssl_cli.c b/library/ssl_cli.c index fa476b927..18850c28d 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -54,7 +54,7 @@ static int ssl_write_client_hello( ssl_context *ssl ) if( ssl->max_major_ver == 0 && ssl->max_minor_ver == 0 ) { ssl->max_major_ver = SSL_MAJOR_VERSION_3; - ssl->max_minor_ver = SSL_MINOR_VERSION_2; + ssl->max_minor_ver = SSL_MINOR_VERSION_3; } /* @@ -335,9 +335,11 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl ) int ret; size_t n; unsigned char *p, *end; - unsigned char hash[36]; + unsigned char hash[64]; md5_context md5; sha1_context sha1; + int hash_id = SIG_RSA_RAW; + unsigned int hashlen; #endif SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) ); @@ -376,6 +378,8 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl ) return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); } + SSL_DEBUG_BUF( 3, "server key exchange", ssl->in_msg + 4, ssl->in_hslen - 4 ); + /* * Ephemeral DH parameters: * @@ -389,6 +393,63 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl ) end = ssl->in_msg + ssl->in_hslen; if( ( ret = dhm_read_params( &ssl->dhm_ctx, &p, end ) ) != 0 ) + { + SSL_DEBUG_MSG( 2, ( "DHM Read Params returned -0x%x", -ret ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + // TODO TLS 1.2 Check if valid hash and sig + if( p[1] != SSL_SIG_RSA ) + { + SSL_DEBUG_MSG( 2, ( "Server used unsupported SignatureAlgorithm %d", p[1] ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + switch( p[0] ) + { +#if defined(POLARSSL_MD5_C) + case SSL_HASH_MD5: + hash_id = SIG_RSA_MD5; + break; +#endif +#if defined(POLARSSL_SHA1_C) + case SSL_HASH_SHA1: + hash_id = SIG_RSA_SHA1; + break; +#endif +#if defined(POLARSSL_SHA2_C) + case SSL_HASH_SHA224: + hash_id = SIG_RSA_SHA224; + break; + case SSL_HASH_SHA256: + hash_id = SIG_RSA_SHA256; + break; +#endif +#if defined(POLARSSL_SHA4_C) + case SSL_HASH_SHA384: + hash_id = SIG_RSA_SHA384; + break; + case SSL_HASH_SHA512: + hash_id = SIG_RSA_SHA512; + break; +#endif + default: + SSL_DEBUG_MSG( 2, ( "Server used unsupported HashAlgorithm %d", p[1] ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + p += 2; + } + + n = ( p[0] << 8 ) | p[1]; + p += 2; + + if( end != p + n ) { SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); @@ -410,35 +471,61 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl ) SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->dhm_ctx.G ); SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->dhm_ctx.GY ); - /* - * digitally-signed struct { - * opaque md5_hash[16]; - * opaque sha_hash[20]; - * }; - * - * md5_hash - * MD5(ClientHello.random + ServerHello.random - * + ServerParams); - * sha_hash - * SHA(ClientHello.random + ServerHello.random - * + ServerParams); - */ - n = ssl->in_hslen - ( end - p ) - 6; + if( ssl->minor_ver != SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + n = ssl->in_hslen - ( end - p ) - 6; - md5_starts( &md5 ); - md5_update( &md5, ssl->randbytes, 64 ); - md5_update( &md5, ssl->in_msg + 4, n ); - md5_finish( &md5, hash ); + md5_starts( &md5 ); + md5_update( &md5, ssl->randbytes, 64 ); + md5_update( &md5, ssl->in_msg + 4, n ); + md5_finish( &md5, hash ); - sha1_starts( &sha1 ); - sha1_update( &sha1, ssl->randbytes, 64 ); - sha1_update( &sha1, ssl->in_msg + 4, n ); - sha1_finish( &sha1, hash + 16 ); + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->randbytes, 64 ); + sha1_update( &sha1, ssl->in_msg + 4, n ); + sha1_finish( &sha1, hash + 16 ); - SSL_DEBUG_BUF( 3, "parameters hash", hash, 36 ); + hash_id = SIG_RSA_RAW; + hashlen = 36; + } + else + { + n = ssl->in_hslen - ( end - p ) - 8; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + /* TODO TLS1.2 Get Hash algorithm from hash and signature extension! */ + + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->randbytes, 64 ); + sha1_update( &sha1, ssl->in_msg + 4, n ); + sha1_finish( &sha1, hash ); + + hashlen = 20; + } + + SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); if( ( ret = rsa_pkcs1_verify( &ssl->peer_cert->rsa, RSA_PUBLIC, - SIG_RSA_RAW, 36, hash, p ) ) != 0 ) + hash_id, hashlen, hash, p ) ) != 0 ) { SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret ); return( ret ); @@ -643,8 +730,10 @@ static int ssl_write_client_key_exchange( ssl_context *ssl ) static int ssl_write_certificate_verify( ssl_context *ssl ) { int ret = 0; - size_t n = 0; + size_t n = 0, offset = 0; unsigned char hash[36]; + int hash_id = SIG_RSA_RAW; + unsigned int hashlen = 36; SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); @@ -655,6 +744,12 @@ static int ssl_write_certificate_verify( ssl_context *ssl ) return( 0 ); } + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + hash_id = SIG_RSA_SHA256; + hashlen = 32; + } + if( ssl->rsa_key == NULL ) { #if defined(POLARSSL_PKCS11_C) @@ -680,18 +775,27 @@ static int ssl_write_certificate_verify( ssl_context *ssl ) n = ssl->pkcs11_key->len; #endif /* defined(POLARSSL_PKCS11_C) */ - ssl->out_msg[4] = (unsigned char)( n >> 8 ); - ssl->out_msg[5] = (unsigned char)( n ); + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + // TODO TLS1.2 Base on signature algorithm extension received + ssl->out_msg[4] = SSL_HASH_SHA1; + ssl->out_msg[5] = SSL_SIG_RSA; + + offset = 2; + } + + ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 ); + ssl->out_msg[5 + offset] = (unsigned char)( n ); if( ssl->rsa_key ) { ret = rsa_pkcs1_sign( ssl->rsa_key, ssl->f_rng, ssl->p_rng, - RSA_PRIVATE, SIG_RSA_RAW, - 36, hash, ssl->out_msg + 6 ); + RSA_PRIVATE, hash_id, + hashlen, hash, ssl->out_msg + 6 + offset ); } else { #if defined(POLARSSL_PKCS11_C) - ret = pkcs11_sign( ssl->pkcs11_key, RSA_PRIVATE, SIG_RSA_RAW, - 36, hash, ssl->out_msg + 6 ); + ret = pkcs11_sign( ssl->pkcs11_key, RSA_PRIVATE, hash_id, + hashlen, hash, ssl->out_msg + 6 + offset ); #endif /* defined(POLARSSL_PKCS11_C) */ } @@ -701,7 +805,7 @@ static int ssl_write_certificate_verify( ssl_context *ssl ) return( ret ); } - ssl->out_msglen = 6 + n; + ssl->out_msglen = 6 + n + offset; ssl->out_msgtype = SSL_MSG_HANDSHAKE; ssl->out_msg[0] = SSL_HS_CERTIFICATE_VERIFY; diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 70ca5bb84..9ef973162 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -97,8 +97,8 @@ static int ssl_parse_client_hello( ssl_context *ssl ) ssl->max_minor_ver = buf[4]; ssl->major_ver = SSL_MAJOR_VERSION_3; - ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_2 ) - ? buf[4] : SSL_MINOR_VERSION_2; + ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_3 ) + ? buf[4] : SSL_MINOR_VERSION_3; if( ( ret = ssl_fetch_input( ssl, 2 + n ) ) != 0 ) { @@ -108,6 +108,7 @@ static int ssl_parse_client_hello( ssl_context *ssl ) md5_update( &ssl->fin_md5 , buf + 2, n ); sha1_update( &ssl->fin_sha1, buf + 2, n ); + sha2_update( &ssl->fin_sha2, buf + 2, n ); buf = ssl->in_msg; n = ssl->in_left - 5; @@ -228,6 +229,7 @@ static int ssl_parse_client_hello( ssl_context *ssl ) md5_update( &ssl->fin_md5 , buf, n ); sha1_update( &ssl->fin_sha1, buf, n ); + sha2_update( &ssl->fin_sha2, buf, n ); /* * SSL layer: @@ -263,8 +265,8 @@ static int ssl_parse_client_hello( ssl_context *ssl ) } ssl->major_ver = SSL_MAJOR_VERSION_3; - ssl->minor_ver = ( buf[5] <= SSL_MINOR_VERSION_2 ) - ? buf[5] : SSL_MINOR_VERSION_2; + ssl->minor_ver = ( buf[5] <= SSL_MINOR_VERSION_3 ) + ? buf[5] : SSL_MINOR_VERSION_3; ssl->max_major_ver = buf[4]; ssl->max_minor_ver = buf[5]; @@ -540,6 +542,8 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) unsigned char hash[36]; md5_context md5; sha1_context sha1; + int hash_id; + unsigned int hashlen; #endif SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); @@ -595,30 +599,55 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->dhm_ctx.G ); SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->dhm_ctx.GX ); - /* - * digitally-signed struct { - * opaque md5_hash[16]; - * opaque sha_hash[20]; - * }; - * - * md5_hash - * MD5(ClientHello.random + ServerHello.random - * + ServerParams); - * sha_hash - * SHA(ClientHello.random + ServerHello.random - * + ServerParams); - */ - md5_starts( &md5 ); - md5_update( &md5, ssl->randbytes, 64 ); - md5_update( &md5, ssl->out_msg + 4, n ); - md5_finish( &md5, hash ); + if( ssl->minor_ver != SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + md5_starts( &md5 ); + md5_update( &md5, ssl->randbytes, 64 ); + md5_update( &md5, ssl->out_msg + 4, n ); + md5_finish( &md5, hash ); - sha1_starts( &sha1 ); - sha1_update( &sha1, ssl->randbytes, 64 ); - sha1_update( &sha1, ssl->out_msg + 4, n ); - sha1_finish( &sha1, hash + 16 ); + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->randbytes, 64 ); + sha1_update( &sha1, ssl->out_msg + 4, n ); + sha1_finish( &sha1, hash + 16 ); - SSL_DEBUG_BUF( 3, "parameters hash", hash, 36 ); + hashlen = 36; + hash_id = SIG_RSA_RAW; + } + else + { + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + /* TODO TLS1.2 Get Hash algorithm from ciphersuite! */ + + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->randbytes, 64 ); + sha1_update( &sha1, ssl->out_msg + 4, n ); + sha1_finish( &sha1, hash ); + + hashlen = 20; + hash_id = SIG_RSA_SHA1; + } + + SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); if ( ssl->rsa_key ) rsa_key_len = ssl->rsa_key->len; @@ -627,6 +656,15 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) rsa_key_len = ssl->pkcs11_key->len; #endif /* defined(POLARSSL_PKCS11_C) */ + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + // TODO TLS1.2 Base on signature algorithm extension received + ssl->out_msg[4 + n] = SSL_HASH_SHA1; + ssl->out_msg[5 + n] = SSL_SIG_RSA; + + n += 2; + } + ssl->out_msg[4 + n] = (unsigned char)( rsa_key_len >> 8 ); ssl->out_msg[5 + n] = (unsigned char)( rsa_key_len ); @@ -634,12 +672,12 @@ static int ssl_write_server_key_exchange( ssl_context *ssl ) { ret = rsa_pkcs1_sign( ssl->rsa_key, ssl->f_rng, ssl->p_rng, RSA_PRIVATE, - SIG_RSA_RAW, 36, hash, ssl->out_msg + 6 + n ); + hash_id, hashlen, hash, ssl->out_msg + 6 + n ); } #if defined(POLARSSL_PKCS11_C) else { ret = pkcs11_sign( ssl->pkcs11_key, RSA_PRIVATE, - SIG_RSA_RAW, 36, hash, ssl->out_msg + 6 + n ); + hash_id, hashlen, hash, ssl->out_msg + 6 + n ); } #endif /* defined(POLARSSL_PKCS11_C) */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 5a81f8b23..b5c89a9be 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -113,6 +113,49 @@ static int tls1_prf( unsigned char *secret, size_t slen, char *label, return( 0 ); } +static int tls_prf_sha256( unsigned char *secret, size_t slen, char *label, + unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb; + size_t i, j, k; + unsigned char tmp[128]; + unsigned char h_i[32]; + + if( sizeof( tmp ) < 32 + strlen( label ) + rlen ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + nb = strlen( label ); + memcpy( tmp + 32, label, nb ); + memcpy( tmp + 32 + nb, random, rlen ); + nb += rlen; + + /* + * Compute P_(secret, label + random)[0..dlen] + */ + sha2_hmac( secret, slen, tmp + 32, nb, tmp, 0 ); + + for( i = 0; i < dlen; i += 32 ) + { + sha2_hmac( secret, slen, tmp, 32 + nb, h_i, 0 ); + sha2_hmac( secret, slen, tmp, 32, tmp, 0 ); + + k = ( i + 32 > dlen ) ? dlen % 32 : 32; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + memset( tmp, 0, sizeof( tmp ) ); + memset( h_i, 0, sizeof( h_i ) ); + + return( 0 ); +} + +static void ssl_calc_finished_ssl (ssl_context *,unsigned char *,int); +static void ssl_calc_finished_tls (ssl_context *,unsigned char *,int); +static void ssl_calc_finished_tls1_2(ssl_context *,unsigned char *,int); + int ssl_derive_keys( ssl_context *ssl ) { int i; @@ -127,6 +170,24 @@ int ssl_derive_keys( ssl_context *ssl ) SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); + /* + * Set appropriate PRF function. + */ + if( ssl->minor_ver < SSL_MINOR_VERSION_3 ) + ssl->tls_prf = tls1_prf; + else + ssl->tls_prf = tls_prf_sha256; + + /* + * Set appropriate SSL / TLS / TLS1.2 functions + */ + if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) + ssl->calc_finished = ssl_calc_finished_ssl; + else if( ssl->minor_ver < SSL_MINOR_VERSION_3 ) + ssl->calc_finished = ssl_calc_finished_tls; + else + ssl->calc_finished = ssl_calc_finished_tls1_2; + /* * SSLv3: * master = @@ -161,9 +222,9 @@ int ssl_derive_keys( ssl_context *ssl ) md5_finish( &md5, ssl->session->master + i * 16 ); } } - else - tls1_prf( ssl->premaster, len, "master secret", - ssl->randbytes, 64, ssl->session->master, 48 ); + else + ssl->tls_prf( ssl->premaster, len, "master secret", + ssl->randbytes, 64, ssl->session->master, 48 ); memset( ssl->premaster, 0, sizeof( ssl->premaster ) ); } @@ -215,8 +276,8 @@ int ssl_derive_keys( ssl_context *ssl ) memset( sha1sum, 0, sizeof( sha1sum ) ); } else - tls1_prf( ssl->session->master, 48, "key expansion", - ssl->randbytes, 64, keyblk, 256 ); + ssl->tls_prf( ssl->session->master, 48, "key expansion", + ssl->randbytes, 64, keyblk, 256 ); SSL_DEBUG_MSG( 3, ( "ciphersuite = %s", ssl_get_ciphersuite( ssl ) ) ); SSL_DEBUG_BUF( 3, "master secret", ssl->session->master, 48 ); @@ -426,6 +487,7 @@ void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] ) { md5_context md5; sha1_context sha1; + sha2_context sha2; unsigned char pad_1[48]; unsigned char pad_2[48]; @@ -433,6 +495,7 @@ void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] ) memcpy( &md5 , &ssl->fin_md5 , sizeof( md5_context ) ); memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) ); + memcpy( &sha2, &ssl->fin_sha2, sizeof( sha2_context ) ); if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) { @@ -459,11 +522,15 @@ void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] ) sha1_update( &sha1, hash + 16, 20 ); sha1_finish( &sha1, hash + 16 ); } - else /* TLSv1 */ + else if( ssl->minor_ver != SSL_MINOR_VERSION_3 ) /* TLSv1 */ { md5_finish( &md5, hash ); sha1_finish( &sha1, hash + 16 ); } + else + { + sha2_finish( &sha2, hash ); + } SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); @@ -630,10 +697,10 @@ static int ssl_encrypt_buf( ssl_context *ssl ) enc_msg = ssl->out_msg; /* - * Prepend per-record IV for block cipher in TLS v1.1 as per - * Method 1 (6.2.3.2. in RFC4346) + * 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 == SSL_MINOR_VERSION_2 ) + if( ssl->minor_ver >= SSL_MINOR_VERSION_2 ) { /* * Generate IV @@ -781,9 +848,9 @@ static int ssl_decrypt_buf( ssl_context *ssl ) dec_msg_result = ssl->in_msg; /* - * Initialize for prepended IV for block cipher in TLS v1.1 + * Initialize for prepended IV for block cipher in TLS v1.1 and up */ - if( ssl->minor_ver == SSL_MINOR_VERSION_2 ) + if( ssl->minor_ver >= SSL_MINOR_VERSION_2 ) { dec_msg += ssl->ivlen; dec_msglen -= ssl->ivlen; @@ -1053,6 +1120,7 @@ int ssl_write_record( ssl_context *ssl ) md5_update( &ssl->fin_md5 , ssl->out_msg, len ); sha1_update( &ssl->fin_sha1, ssl->out_msg, len ); + sha2_update( &ssl->fin_sha2, ssl->out_msg, len ); } if( ssl->do_crypt != 0 ) @@ -1127,6 +1195,7 @@ int ssl_read_record( ssl_context *ssl ) md5_update( &ssl->fin_md5 , ssl->in_msg, ssl->in_hslen ); sha1_update( &ssl->fin_sha1, ssl->in_msg, ssl->in_hslen ); + sha2_update( &ssl->fin_sha2, ssl->in_msg, ssl->in_hslen ); return( 0 ); } @@ -1192,7 +1261,7 @@ int ssl_read_record( ssl_context *ssl ) /* * TLS encrypted messages can have up to 256 bytes of padding */ - if( ssl->minor_ver == SSL_MINOR_VERSION_1 && + if( ssl->minor_ver >= SSL_MINOR_VERSION_1 && ssl->in_msglen > ssl->minlen + SSL_MAX_CONTENT_LEN + 256 ) { SSL_DEBUG_MSG( 1, ( "bad message length" ) ); @@ -1256,6 +1325,7 @@ int ssl_read_record( ssl_context *ssl ) md5_update( &ssl->fin_md5 , ssl->in_msg, ssl->in_hslen ); sha1_update( &ssl->fin_sha1, ssl->in_msg, ssl->in_hslen ); + sha2_update( &ssl->fin_sha2, ssl->in_msg, ssl->in_hslen ); } if( ssl->in_msgtype == SSL_MSG_ALERT ) @@ -1600,17 +1670,21 @@ int ssl_parse_change_cipher_spec( ssl_context *ssl ) return( 0 ); } -static void ssl_calc_finished( - ssl_context *ssl, unsigned char *buf, int from, - md5_context *md5, sha1_context *sha1 ) +static void ssl_calc_finished_ssl( + ssl_context *ssl, unsigned char *buf, int from ) { - int len = 12; char *sender; + md5_context md5; + sha1_context sha1; + unsigned char padbuf[48]; unsigned char md5sum[16]; unsigned char sha1sum[20]; - SSL_DEBUG_MSG( 2, ( "=> calc finished" ) ); + SSL_DEBUG_MSG( 2, ( "=> calc finished ssl" ) ); + + memcpy( &md5 , &ssl->fin_md5 , sizeof( md5_context ) ); + memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) ); /* * SSLv3: @@ -1619,68 +1693,47 @@ static void ssl_calc_finished( * MD5( handshake + sender + master + pad1 ) ) * + SHA1( master + pad2 + * SHA1( handshake + sender + master + pad1 ) ) - * - * TLSv1: - * hash = PRF( master, finished_label, - * MD5( handshake ) + SHA1( handshake ) )[0..11] */ SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) - md5->state, sizeof( md5->state ) ); + md5.state, sizeof( md5.state ) ); SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) - sha1->state, sizeof( sha1->state ) ); + sha1.state, sizeof( sha1.state ) ); - if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) - { - sender = ( from == SSL_IS_CLIENT ) ? (char *) "CLNT" - : (char *) "SRVR"; + sender = ( from == SSL_IS_CLIENT ) ? (char *) "CLNT" + : (char *) "SRVR"; - memset( padbuf, 0x36, 48 ); + memset( padbuf, 0x36, 48 ); - md5_update( md5, (unsigned char *) sender, 4 ); - md5_update( md5, ssl->session->master, 48 ); - md5_update( md5, padbuf, 48 ); - md5_finish( md5, md5sum ); + md5_update( &md5, (unsigned char *) sender, 4 ); + md5_update( &md5, ssl->session->master, 48 ); + md5_update( &md5, padbuf, 48 ); + md5_finish( &md5, md5sum ); - sha1_update( sha1, (unsigned char *) sender, 4 ); - sha1_update( sha1, ssl->session->master, 48 ); - sha1_update( sha1, padbuf, 40 ); - sha1_finish( sha1, sha1sum ); + sha1_update( &sha1, (unsigned char *) sender, 4 ); + sha1_update( &sha1, ssl->session->master, 48 ); + sha1_update( &sha1, padbuf, 40 ); + sha1_finish( &sha1, sha1sum ); - memset( padbuf, 0x5C, 48 ); + memset( padbuf, 0x5C, 48 ); - md5_starts( md5 ); - md5_update( md5, ssl->session->master, 48 ); - md5_update( md5, padbuf, 48 ); - md5_update( md5, md5sum, 16 ); - md5_finish( md5, buf ); + md5_starts( &md5 ); + md5_update( &md5, ssl->session->master, 48 ); + md5_update( &md5, padbuf, 48 ); + md5_update( &md5, md5sum, 16 ); + md5_finish( &md5, buf ); - sha1_starts( sha1 ); - sha1_update( sha1, ssl->session->master, 48 ); - sha1_update( sha1, padbuf , 40 ); - sha1_update( sha1, sha1sum, 20 ); - sha1_finish( sha1, buf + 16 ); + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->session->master, 48 ); + sha1_update( &sha1, padbuf , 40 ); + sha1_update( &sha1, sha1sum, 20 ); + sha1_finish( &sha1, buf + 16 ); - len += 24; - } - else - { - sender = ( from == SSL_IS_CLIENT ) - ? (char *) "client finished" - : (char *) "server finished"; + SSL_DEBUG_BUF( 3, "calc finished result", buf, 36 ); - md5_finish( md5, padbuf ); - sha1_finish( sha1, padbuf + 16 ); - - tls1_prf( ssl->session->master, 48, sender, - padbuf, 36, buf, len ); - } - - SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); - - memset( md5, 0, sizeof( md5_context ) ); - memset( sha1, 0, sizeof( sha1_context ) ); + memset( &md5, 0, sizeof( md5_context ) ); + memset( &sha1, 0, sizeof( sha1_context ) ); memset( padbuf, 0, sizeof( padbuf ) ); memset( md5sum, 0, sizeof( md5sum ) ); @@ -1689,20 +1742,100 @@ static void ssl_calc_finished( SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); } -int ssl_write_finished( ssl_context *ssl ) +static void ssl_calc_finished_tls( + ssl_context *ssl, unsigned char *buf, int from ) { - int ret, hash_len; - md5_context md5; + int len = 12; + char *sender; + md5_context md5; sha1_context sha1; + unsigned char padbuf[36]; - SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + SSL_DEBUG_MSG( 2, ( "=> calc finished tls" ) ); memcpy( &md5 , &ssl->fin_md5 , sizeof( md5_context ) ); memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) ); - ssl_calc_finished( ssl, ssl->out_msg + 4, - ssl->endpoint, &md5, &sha1 ); + /* + * TLSv1: + * hash = PRF( master, finished_label, + * MD5( handshake ) + SHA1( handshake ) )[0..11] + */ + SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); + + SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); + + sender = ( from == SSL_IS_CLIENT ) + ? (char *) "client finished" + : (char *) "server finished"; + + md5_finish( &md5, padbuf ); + sha1_finish( &sha1, padbuf + 16 ); + + ssl->tls_prf( ssl->session->master, 48, sender, + padbuf, 36, buf, len ); + + SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + memset( &md5, 0, sizeof( md5_context ) ); + memset( &sha1, 0, sizeof( sha1_context ) ); + + memset( padbuf, 0, sizeof( padbuf ) ); + + SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} + +static void ssl_calc_finished_tls1_2( + ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + char *sender; + sha2_context sha2; + unsigned char padbuf[32]; + + SSL_DEBUG_MSG( 2, ( "=> calc finished tls 1.2" ) ); + + memcpy( &sha2, &ssl->fin_sha2, sizeof( sha2_context ) ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + + SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *) + sha2.state, sizeof( sha2.state ) ); + + sender = ( from == SSL_IS_CLIENT ) + ? (char *) "client finished" + : (char *) "server finished"; + + sha2_finish( &sha2, padbuf ); + + ssl->tls_prf( ssl->session->master, 48, sender, + padbuf, 32, buf, len ); + + SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + memset( &sha2, 0, sizeof( sha2_context ) ); + + memset( padbuf, 0, sizeof( padbuf ) ); + + SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} + +int ssl_write_finished( ssl_context *ssl ) +{ + int ret, hash_len; + + SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + ssl->calc_finished( ssl, ssl->out_msg + 4, ssl->endpoint ); + + // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63) hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12; ssl->out_msglen = 4 + hash_len; @@ -1741,13 +1874,10 @@ int ssl_parse_finished( ssl_context *ssl ) int ret; unsigned int hash_len; unsigned char buf[36]; - md5_context md5; - sha1_context sha1; SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); - memcpy( &md5 , &ssl->fin_md5 , sizeof( md5_context ) ); - memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) ); + ssl->calc_finished( ssl, buf, ssl->endpoint ^ 1 ); ssl->do_crypt = 1; @@ -1763,6 +1893,7 @@ int ssl_parse_finished( ssl_context *ssl ) return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); } + // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63) hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12; if( ssl->in_msg[0] != SSL_HS_FINISHED || @@ -1772,8 +1903,6 @@ int ssl_parse_finished( ssl_context *ssl ) return( POLARSSL_ERR_SSL_BAD_HS_FINISHED ); } - ssl_calc_finished( ssl, buf, ssl->endpoint ^ 1, &md5, &sha1 ); - if( memcmp( ssl->in_msg + 4, buf, hash_len ) != 0 ) { SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); @@ -1834,6 +1963,7 @@ int ssl_init( ssl_context *ssl ) md5_starts( &ssl->fin_md5 ); sha1_starts( &ssl->fin_sha1 ); + sha2_starts( &ssl->fin_sha2, 0 ); return( 0 ); } @@ -1879,6 +2009,7 @@ void ssl_session_reset( ssl_context *ssl ) md5_starts( &ssl->fin_md5 ); sha1_starts( &ssl->fin_sha1 ); + sha2_starts( &ssl->fin_sha2, 0 ); } /* @@ -2199,6 +2330,9 @@ const char *ssl_get_version( const ssl_context *ssl ) case SSL_MINOR_VERSION_2: return( "TLSv1.1" ); + case SSL_MINOR_VERSION_3: + return( "TLSv1.2" ); + default: break; }