- Initial bare version of TLS 1.2

diff --git a/library/dhm.c b/library/dhm.c
index bddd076..ef456af 100644
--- a/library/dhm.c
+++ b/library/dhm.c
@@ -113,12 +113,6 @@
     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 fa476b9..18850c2 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -54,7 +54,7 @@
     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 @@
     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 @@
         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:
      *
@@ -390,6 +394,63 @@
 
     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 @@
     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_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 @@
         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 @@
         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 @@
         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 70ca5bb..9ef9731 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -97,8 +97,8 @@
         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 @@
 
          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 @@
 
          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 @@
         }
 
         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 @@
     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 @@
     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 @@
         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 @@
     {
         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 5a81f8b..b5c89a9 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -113,6 +113,49 @@
     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_<hash>(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;
@@ -128,6 +171,24 @@
     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 =
      *     MD5( premaster + SHA1( 'A'   + premaster + randbytes ) ) +
@@ -161,9 +222,9 @@
                 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 @@
         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 @@
 {
     md5_context md5;
     sha1_context sha1;
+    sha2_context sha2;
     unsigned char pad_1[48];
     unsigned char pad_2[48];
 
@@ -433,6 +495,7 @@
 
     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 @@
         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 @@
         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 @@
         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 @@
 
          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 @@
 
          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 @@
         /*
          * 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 @@
 
          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 @@
     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 @@
      *          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 @@
     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 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 @@
         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 @@
         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 @@
 
      md5_starts( &ssl->fin_md5  );
     sha1_starts( &ssl->fin_sha1 );
+    sha2_starts( &ssl->fin_sha2, 0 );
 
     return( 0 );
 }
@@ -1879,6 +2009,7 @@
 
      md5_starts( &ssl->fin_md5  );
     sha1_starts( &ssl->fin_sha1 );
+    sha2_starts( &ssl->fin_sha2, 0 );
 }
 
 /*
@@ -2199,6 +2330,9 @@
         case SSL_MINOR_VERSION_2:
             return( "TLSv1.1" );
 
+        case SSL_MINOR_VERSION_3:
+            return( "TLSv1.2" );
+
         default:
             break;
     }