- Added GCM ciphersuites to TLS implementation

diff --git a/ChangeLog b/ChangeLog
index 8333b5a..3bde699 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,7 @@
    * Added cert_req example application
    * Added base Galois Counter Mode (GCM) for AES
    * Added TLS 1.2 support
+   * Added GCM suites to TLS 1.2 (RFC 5288)
 
 Changes
    * Removed redundant POLARSSL_DEBUG_MSG define
diff --git a/include/polarssl/gcm.h b/include/polarssl/gcm.h
index 14b04d2..2f88c70 100644
--- a/include/polarssl/gcm.h
+++ b/include/polarssl/gcm.h
@@ -35,6 +35,7 @@
 #define GCM_DECRYPT     0
 
 #define POLARSSL_ERR_GCM_AUTH_FAILED                       -0x0012  /**< Authenticated decryption failed. */
+#define POLARSSL_ERR_GCM_BAD_INPUT                         -0x0014  /**< Bad input parameters to function. */
 
 /**
  * \brief          GCM context structure
@@ -64,6 +65,11 @@
 /**
  * \brief           GCM buffer encryption/decryption using AES
  *
+ * \note On encryption, the output buffer can be the same as the input buffer.
+ *       On decryption, the output buffer cannot be the same as input buffer.
+ *       If buffers overlap, the output buffer must trail at least 8 bytes
+ *       behind the input buffer.
+ *
  * \param ctx       GCM context
  * \param mode      GCM_ENCRYPT or GCM_DECRYPT
  * \param length    length of the input data
@@ -93,6 +99,10 @@
 /**
  * \brief           GCM buffer authenticated decryption using AES
  *
+ * \note On decryption, the output buffer cannot be the same as input buffer.
+ *       If buffers overlap, the output buffer must trail at least 8 bytes
+ *       behind the input buffer.
+ *
  * \param ctx       GCM context
  * \param length    length of the input data
  * \param iv        initialization vector
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 90de649..8110fbc 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -35,6 +35,7 @@
 #include "md5.h"
 #include "sha1.h"
 #include "sha2.h"
+#include "sha4.h"
 #include "x509.h"
 #include "config.h"
 
@@ -142,6 +143,11 @@
 #define SSL_RSA_CAMELLIA_256_SHA256     0xC0   /**< TLS 1.2 */
 #define SSL_EDH_RSA_CAMELLIA_256_SHA256 0xC4   /**< TLS 1.2 */
 
+#define SSL_RSA_AES_128_GCM_SHA256      0x9C
+#define SSL_RSA_AES_256_GCM_SHA384      0x9D
+#define SSL_EDH_RSA_AES_128_GCM_SHA256  0x9E
+#define SSL_EDH_RSA_AES_256_GCM_SHA384  0x9F
+
 /*
  * Supported Signature and Hash algorithms (For TLS 1.2)
  */
@@ -172,7 +178,7 @@
 #define SSL_ALERT_MSG_DECRYPTION_FAILED     21  /* 0x15 */
 #define SSL_ALERT_MSG_RECORD_OVERFLOW       22  /* 0x16 */
 #define SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30  /* 0x1E */
-#define SSL_ALERT_MSG_HANDSHAKE_FAILURE     41  /* 0x29 */
+#define SSL_ALERT_MSG_HANDSHAKE_FAILURE     40  /* 0x28 */
 #define SSL_ALERT_MSG_NO_CERT               41  /* 0x29 */
 #define SSL_ALERT_MSG_BAD_CERT              42  /* 0x2A */
 #define SSL_ALERT_MSG_UNSUPPORTED_CERT      43  /* 0x2B */
@@ -339,6 +345,7 @@
     md5_context fin_md5;                /*!<  Finished MD5 checksum   */
     sha1_context fin_sha1;              /*!<  Finished SHA-1 checksum */
     sha2_context fin_sha2;              /*!<  Finished SHA-256 checksum */
+    sha4_context fin_sha4;              /*!<  Finished SHA-384 checksum */
 
     void (*calc_finished)(ssl_context *, unsigned char *, int);
     int  (*tls_prf)(unsigned char *, size_t, char *,
@@ -351,6 +358,7 @@
     unsigned int keylen;                /*!<  symmetric key length    */
     size_t minlen;                      /*!<  min. ciphertext length  */
     size_t ivlen;                       /*!<  IV length               */
+    size_t fixed_ivlen;                 /*!<  Fixed part of IV (AEAD) */
     size_t maclen;                      /*!<  MAC length              */
 
     unsigned char randbytes[64];        /*!<  random bytes            */
@@ -362,8 +370,8 @@
     unsigned char mac_enc[32];          /*!<  MAC (encryption)        */
     unsigned char mac_dec[32];          /*!<  MAC (decryption)        */
 
-    unsigned long ctx_enc[128];         /*!<  encryption context      */
-    unsigned long ctx_dec[128];         /*!<  decryption context      */
+    unsigned long ctx_enc[134];         /*!<  encryption context      */
+    unsigned long ctx_dec[134];         /*!<  decryption context      */
 
     /*
      * TLS extensions
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 6f9206f..df4dbb0 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -453,7 +453,9 @@
         ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_128_SHA &&
         ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_256_SHA &&
         ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_128_SHA256 &&
-        ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_256_SHA256 )
+        ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_256_SHA256 &&
+        ssl->session->ciphersuite != SSL_EDH_RSA_AES_128_GCM_SHA256 &&
+        ssl->session->ciphersuite != SSL_EDH_RSA_AES_256_GCM_SHA384 )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) );
         ssl->state++;
@@ -786,7 +788,9 @@
         ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_128_SHA ||
         ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_256_SHA ||
         ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_128_SHA256 ||
-        ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_256_SHA256 )
+        ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_256_SHA256 ||
+        ssl->session->ciphersuite == SSL_EDH_RSA_AES_128_GCM_SHA256 ||
+        ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
     {
 #if !defined(POLARSSL_DHM_C)
         SSL_DEBUG_MSG( 1, ( "support for dhm in not available" ) );
@@ -888,7 +892,7 @@
 {
     int ret = 0;
     size_t n = 0, offset = 0;
-    unsigned char hash[36];
+    unsigned char hash[48];
     int hash_id = SIG_RSA_RAW;
     unsigned int hashlen = 36;
 
@@ -903,8 +907,21 @@
 
     if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
     {
-        hash_id = SIG_RSA_SHA256;
-        hashlen = 32;
+        // TODO TLS1.2 Should be based on allowed signature algorithm received in
+        // Certificate Request according to RFC 5246. But OpenSSL only allows
+        // SHA256 and SHA384. Find out why OpenSSL does this.
+        //
+        if( ssl->session->ciphersuite == SSL_RSA_AES_256_GCM_SHA384 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
+        {
+            hash_id = SIG_RSA_SHA384;
+            hashlen = 48;
+        }
+        else
+        {
+            hash_id = SIG_RSA_SHA256;
+            hashlen = 32;
+        }
     }
 
     if( ssl->rsa_key == NULL )
@@ -934,9 +951,21 @@
 
     if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
     {
-        // TODO TLS1.2 Base on signature algorithm received in Certificate Request
-        ssl->out_msg[4] = SSL_HASH_SHA256;
-        ssl->out_msg[5] = SSL_SIG_RSA;
+        // TODO TLS1.2 Should be based on allowed signature algorithm received in
+        // Certificate Request according to RFC 5246. But OpenSSL only allows
+        // SHA256 and SHA384. Find out why OpenSSL does this.
+        //
+        if( ssl->session->ciphersuite == SSL_RSA_AES_256_GCM_SHA384 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
+        {
+            ssl->out_msg[4] = SSL_HASH_SHA384;
+            ssl->out_msg[5] = SSL_SIG_RSA;
+        }
+        else
+        {
+            ssl->out_msg[4] = SSL_HASH_SHA256;
+            ssl->out_msg[5] = SSL_SIG_RSA;
+        }
 
         offset = 2;
     }
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 2d8b0b8..790b8a7 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -109,6 +109,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 );
+        sha4_update( &ssl->fin_sha4, buf + 2, n );
 
         buf = ssl->in_msg;
         n = ssl->in_left - 5;
@@ -230,6 +231,7 @@
          md5_update( &ssl->fin_md5 , buf, n );
         sha1_update( &ssl->fin_sha1, buf, n );
         sha2_update( &ssl->fin_sha2, buf, n );
+        sha4_update( &ssl->fin_sha4, buf, n );
 
         /*
          * SSL layer:
@@ -539,7 +541,7 @@
 #if defined(POLARSSL_DHM_C)
     int ret;
     size_t n, rsa_key_len = 0;
-    unsigned char hash[36];
+    unsigned char hash[48];
     md5_context md5;
     sha1_context sha1;
     int hash_id;
@@ -557,7 +559,9 @@
         ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_128_SHA &&
         ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_256_SHA &&
         ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_128_SHA256 &&
-        ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_256_SHA256 )
+        ssl->session->ciphersuite != SSL_EDH_RSA_CAMELLIA_256_SHA256 &&
+        ssl->session->ciphersuite != SSL_EDH_RSA_AES_128_GCM_SHA256 &&
+        ssl->session->ciphersuite != SSL_EDH_RSA_AES_256_GCM_SHA384 )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
         ssl->state++;
@@ -770,7 +774,9 @@
         ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_128_SHA ||
         ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_256_SHA ||
         ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_128_SHA256 ||
-        ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_256_SHA256 )
+        ssl->session->ciphersuite == SSL_EDH_RSA_CAMELLIA_256_SHA256 ||
+        ssl->session->ciphersuite == SSL_EDH_RSA_AES_128_GCM_SHA256 ||
+        ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
     {
 #if !defined(POLARSSL_DHM_C)
         SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 98a2187..9a962b2 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -43,6 +43,10 @@
 #include "polarssl/ssl.h"
 #include "polarssl/sha2.h"
 
+#if defined(POLARSSL_GCM_C)
+#include "polarssl/gcm.h"
+#endif
+
 #include <stdlib.h>
 #include <time.h>
 
@@ -152,9 +156,49 @@
     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);
+static int tls_prf_sha384( 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[48];
+
+    if( sizeof( tmp ) < 48 + strlen( label ) + rlen )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    nb = strlen( label );
+    memcpy( tmp + 48, label, nb );
+    memcpy( tmp + 48 + nb, random, rlen );
+    nb += rlen;
+
+    /*
+     * Compute P_<hash>(secret, label + random)[0..dlen]
+     */
+    sha4_hmac( secret, slen, tmp + 48, nb, tmp, 1 );
+
+    for( i = 0; i < dlen; i += 48 )
+    {
+        sha4_hmac( secret, slen, tmp, 48 + nb, h_i, 1 );
+        sha4_hmac( secret, slen, tmp, 48,      tmp, 1 );
+
+        k = ( i + 48 > dlen ) ? dlen % 48 : 48;
+
+        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_tls_sha256(ssl_context *,unsigned char *,int);
+static void ssl_calc_finished_tls_sha384(ssl_context *,unsigned char *,int);
 
 int ssl_derive_keys( ssl_context *ssl )
 {
@@ -167,26 +211,34 @@
     unsigned char keyblk[256];
     unsigned char *key1;
     unsigned char *key2;
+    unsigned int iv_copy_len;
 
     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
+     * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions
      */
     if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        ssl->tls_prf = tls1_prf;
         ssl->calc_finished = ssl_calc_finished_ssl;
+    }
     else if( ssl->minor_ver < SSL_MINOR_VERSION_3 )
+    {
+        ssl->tls_prf = tls1_prf;
         ssl->calc_finished = ssl_calc_finished_tls;
+    }
+    else if( ssl->session->ciphersuite == SSL_RSA_AES_256_GCM_SHA384 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
+    {
+        ssl->tls_prf = tls_prf_sha384;
+        ssl->calc_finished = ssl_calc_finished_tls_sha384;
+    }
     else
-        ssl->calc_finished = ssl_calc_finished_tls1_2;
+    {
+        ssl->tls_prf = tls_prf_sha256;
+        ssl->calc_finished = ssl_calc_finished_tls_sha256;
+    }
 
     /*
      * SSLv3:
@@ -337,6 +389,21 @@
             ssl->ivlen  = 16; ssl->maclen = 32;
             break;
 #endif
+#if defined(POLARSSL_GCM_C)
+        case SSL_RSA_AES_128_GCM_SHA256:
+        case SSL_EDH_RSA_AES_128_GCM_SHA256:
+            ssl->keylen = 16; ssl->minlen = 1;
+            ssl->ivlen  = 12; ssl->maclen = 0;
+            ssl->fixed_ivlen = 4;
+            break;
+
+        case SSL_RSA_AES_256_GCM_SHA384:
+        case SSL_EDH_RSA_AES_256_GCM_SHA384:
+            ssl->keylen = 32; ssl->minlen = 1;
+            ssl->ivlen  = 12; ssl->maclen = 0;
+            ssl->fixed_ivlen = 4;
+            break;
+#endif
 #endif
 
 #if defined(POLARSSL_CAMELLIA_C)
@@ -417,9 +484,10 @@
         /*
          * This is not used in TLS v1.1.
          */
-        memcpy( ssl->iv_enc, key2 + ssl->keylen,  ssl->ivlen );
-        memcpy( ssl->iv_dec, key2 + ssl->keylen + ssl->ivlen,
-                ssl->ivlen );
+        iv_copy_len = ( ssl->fixed_ivlen ) ? ssl->fixed_ivlen : ssl->ivlen;
+        memcpy( ssl->iv_enc, key2 + ssl->keylen,  iv_copy_len );
+        memcpy( ssl->iv_dec, key2 + ssl->keylen + iv_copy_len,
+                iv_copy_len );
     }
     else
     {
@@ -432,9 +500,10 @@
         /*
          * This is not used in TLS v1.1.
          */
-        memcpy( ssl->iv_dec, key1 + ssl->keylen,  ssl->ivlen );
-        memcpy( ssl->iv_enc, key1 + ssl->keylen + ssl->ivlen,
-                ssl->ivlen );
+        iv_copy_len = ( ssl->fixed_ivlen ) ? ssl->fixed_ivlen : ssl->ivlen;
+        memcpy( ssl->iv_dec, key1 + ssl->keylen,  iv_copy_len );
+        memcpy( ssl->iv_enc, key1 + ssl->keylen + iv_copy_len,
+                iv_copy_len );
     }
 
     switch( ssl->session->ciphersuite )
@@ -458,42 +527,48 @@
 #if defined(POLARSSL_AES_C)
         case SSL_RSA_AES_128_SHA:
         case SSL_EDH_RSA_AES_128_SHA:
-#if defined(POLARSSL_SHA2_C)
         case SSL_RSA_AES_128_SHA256:
         case SSL_EDH_RSA_AES_128_SHA256:
-#endif
             aes_setkey_enc( (aes_context *) ssl->ctx_enc, key1, 128 );
             aes_setkey_dec( (aes_context *) ssl->ctx_dec, key2, 128 );
             break;
 
         case SSL_RSA_AES_256_SHA:
         case SSL_EDH_RSA_AES_256_SHA:
-#if defined(POLARSSL_SHA2_C)
         case SSL_RSA_AES_256_SHA256:
         case SSL_EDH_RSA_AES_256_SHA256:
-#endif
             aes_setkey_enc( (aes_context *) ssl->ctx_enc, key1, 256 );
             aes_setkey_dec( (aes_context *) ssl->ctx_dec, key2, 256 );
             break;
+
+#if defined(POLARSSL_GCM_C)
+        case SSL_RSA_AES_128_GCM_SHA256:
+        case SSL_EDH_RSA_AES_128_GCM_SHA256:
+            gcm_init( (gcm_context *) ssl->ctx_enc, key1, 128 );
+            gcm_init( (gcm_context *) ssl->ctx_dec, key2, 128 );
+            break;
+
+        case SSL_RSA_AES_256_GCM_SHA384:
+        case SSL_EDH_RSA_AES_256_GCM_SHA384:
+            gcm_init( (gcm_context *) ssl->ctx_enc, key1, 256 );
+            gcm_init( (gcm_context *) ssl->ctx_dec, key2, 256 );
+            break;
+#endif
 #endif
 
 #if defined(POLARSSL_CAMELLIA_C)
         case SSL_RSA_CAMELLIA_128_SHA:
         case SSL_EDH_RSA_CAMELLIA_128_SHA:
-#if defined(POLARSSL_SHA2_C)
         case SSL_RSA_CAMELLIA_128_SHA256:
         case SSL_EDH_RSA_CAMELLIA_128_SHA256:
-#endif
             camellia_setkey_enc( (camellia_context *) ssl->ctx_enc, key1, 128 );
             camellia_setkey_dec( (camellia_context *) ssl->ctx_dec, key2, 128 );
             break;
 
         case SSL_RSA_CAMELLIA_256_SHA:
         case SSL_EDH_RSA_CAMELLIA_256_SHA:
-#if defined(POLARSSL_SHA2_C)
         case SSL_RSA_CAMELLIA_256_SHA256:
         case SSL_EDH_RSA_CAMELLIA_256_SHA256:
-#endif
             camellia_setkey_enc( (camellia_context *) ssl->ctx_enc, key1, 256 );
             camellia_setkey_dec( (camellia_context *) ssl->ctx_dec, key2, 256 );
             break;
@@ -527,11 +602,12 @@
     return( 0 );
 }
 
-void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] )
+void ssl_calc_verify( ssl_context *ssl, unsigned char hash[48] )
 {
     md5_context md5;
     sha1_context sha1;
     sha2_context sha2;
+    sha4_context sha4;
     unsigned char pad_1[48];
     unsigned char pad_2[48];
 
@@ -540,6 +616,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 ) );
+    memcpy( &sha4, &ssl->fin_sha4, sizeof( sha4_context ) );
 
     if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
     {
@@ -571,12 +648,17 @@
          md5_finish( &md5,  hash );
         sha1_finish( &sha1, hash + 16 );
     }
+    else if( ssl->session->ciphersuite == SSL_RSA_AES_256_GCM_SHA384 ||
+             ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
+    {
+        sha4_finish( &sha4, hash );
+    }
     else
     {
         sha2_finish( &sha2, hash );
     }
 
-    SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 );
+    SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 );
     SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
 
     return;
@@ -690,10 +772,6 @@
 
     ssl->out_msglen += ssl->maclen;
 
-    for( i = 8; i > 0; i-- )
-        if( ++ssl->out_ctr[i - 1] != 0 )
-            break;
-
     if( ssl->ivlen == 0 )
     {
         padlen = 0;
@@ -723,6 +801,82 @@
 #endif
         return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
     }
+    else if( ssl->ivlen == 12 )
+    {
+        size_t enc_msglen;
+        unsigned char *enc_msg;
+        unsigned char add_data[13];
+        int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
+
+        padlen = 0;
+        enc_msglen = ssl->out_msglen;
+
+        memcpy( add_data, ssl->out_ctr, 8 );
+        add_data[8]  = ssl->out_msgtype;
+        add_data[9]  = ssl->major_ver;
+        add_data[10] = ssl->minor_ver;
+        add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF;
+        add_data[12] = ssl->out_msglen & 0xFF;
+
+        SSL_DEBUG_BUF( 4, "additional data used for AEAD",
+                       add_data, 13 );
+
+#if defined(POLARSSL_AES_C) && defined(POLARSSL_GCM_C)
+
+        if( ssl->session->ciphersuite == SSL_RSA_AES_128_GCM_SHA256 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_128_GCM_SHA256 ||
+            ssl->session->ciphersuite == SSL_RSA_AES_256_GCM_SHA384 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
+        {
+            /*
+             * Generate IV
+             */
+            ret = ssl->f_rng( ssl->p_rng, ssl->iv_enc + ssl->fixed_ivlen,
+                                  ssl->ivlen - ssl->fixed_ivlen );
+            if( ret != 0 )
+                return( ret );
+
+            /*
+             * Shift message for ivlen bytes and prepend IV
+             */
+            memmove( ssl->out_msg + ssl->ivlen - ssl->fixed_ivlen,
+                     ssl->out_msg, ssl->out_msglen );
+            memcpy( ssl->out_msg, ssl->iv_enc + ssl->fixed_ivlen,
+                    ssl->ivlen - ssl->fixed_ivlen );
+
+            /*
+             * Fix pointer positions and message length with added IV
+             */
+            enc_msg = ssl->out_msg + ssl->ivlen - ssl->fixed_ivlen;
+            enc_msglen = ssl->out_msglen;
+            ssl->out_msglen += ssl->ivlen - ssl->fixed_ivlen;
+
+            SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
+                                "including %d bytes of padding",
+                           ssl->out_msglen, 0 ) );
+
+            SSL_DEBUG_BUF( 4, "before encrypt: output payload",
+                           ssl->out_msg, ssl->out_msglen );
+
+            /*
+             * Adjust for tag
+             */
+            ssl->out_msglen += 16;
+            
+            gcm_crypt_and_tag( (gcm_context *) ssl->ctx_enc,
+                    GCM_ENCRYPT, enc_msglen,
+                    ssl->iv_enc, ssl->ivlen,
+                    add_data, 13,
+                    enc_msg, enc_msg,
+                    16, enc_msg + enc_msglen );
+
+            SSL_DEBUG_BUF( 4, "after encrypt: tag",
+                           enc_msg + enc_msglen, 16 );
+
+        } else
+#endif
+        return( ret );
+    }
     else
     {
         unsigned char *enc_msg;
@@ -834,6 +988,10 @@
         }
     }
 
+    for( i = 8; i > 0; i-- )
+        if( ++ssl->out_ctr[i - 1] != 0 )
+            break;
+
     SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) );
 
     return( 0 );
@@ -879,6 +1037,65 @@
 #endif
         return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
     }
+    else if( ssl->ivlen == 12 )
+    {
+        unsigned char *dec_msg;
+        unsigned char *dec_msg_result;
+        size_t dec_msglen;
+        unsigned char add_data[13];
+        int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
+
+        padlen = 0;
+
+#if defined(POLARSSL_AES_C) && defined(POLARSSL_GCM_C)
+        if( ssl->session->ciphersuite == SSL_RSA_AES_128_GCM_SHA256 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_128_GCM_SHA256 ||
+            ssl->session->ciphersuite == SSL_RSA_AES_256_GCM_SHA384 ||
+            ssl->session->ciphersuite == SSL_EDH_RSA_AES_256_GCM_SHA384 )
+        {
+            dec_msglen = ssl->in_msglen - ( ssl->ivlen - ssl->fixed_ivlen );
+            dec_msglen -= 16;
+            dec_msg = ssl->in_msg + ( ssl->ivlen - ssl->fixed_ivlen );
+            dec_msg_result = ssl->in_msg;
+            ssl->in_msglen = dec_msglen;
+
+            memcpy( add_data, ssl->in_ctr, 8 );
+            add_data[8]  = ssl->in_msgtype;
+            add_data[9]  = ssl->major_ver;
+            add_data[10] = ssl->minor_ver;
+            add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF;
+            add_data[12] = ssl->in_msglen & 0xFF;
+
+            SSL_DEBUG_BUF( 4, "additional data used for AEAD",
+                           add_data, 13 );
+
+            memcpy( ssl->iv_dec + ssl->fixed_ivlen, ssl->in_msg,
+                    ssl->ivlen - ssl->fixed_ivlen );
+
+            SSL_DEBUG_BUF( 4, "IV used", ssl->iv_dec, ssl->ivlen );
+            SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, 16 );
+
+            memcpy( ssl->iv_dec + ssl->fixed_ivlen, ssl->in_msg,
+                    ssl->ivlen - ssl->fixed_ivlen );
+
+            ret = gcm_auth_decrypt( (gcm_context *) ssl->ctx_dec,
+                                     dec_msglen,
+                                     ssl->iv_dec, ssl->ivlen,
+                                     add_data, 13,
+                                     dec_msg + dec_msglen, 16,
+                                     dec_msg, dec_msg_result );
+            
+            if( ret != 0 )
+            {
+                SSL_DEBUG_MSG( 1, ( "AEAD decrypt failed on validation (ret = -0x%02x)",
+                                    -ret ) );
+
+                return( POLARSSL_ERR_SSL_INVALID_MAC );
+            }
+        } else
+#endif
+        return( ret );
+    }
     else
     {
         unsigned char *dec_msg;
@@ -1063,7 +1280,7 @@
      * Finally check the padding length; bad padding
      * will produce the same error as an invalid MAC.
      */
-    if( ssl->ivlen != 0 && padlen == 0 )
+    if( ssl->ivlen != 0 && ssl->ivlen != 12 && padlen == 0 )
         return( POLARSSL_ERR_SSL_INVALID_MAC );
 
     if( ssl->in_msglen == 0 )
@@ -1181,6 +1398,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 );
+        sha4_update( &ssl->fin_sha4, ssl->out_msg, len );
     }
 
     if( ssl->do_crypt != 0 )
@@ -1256,6 +1474,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 );
+        sha4_update( &ssl->fin_sha4, ssl->in_msg, ssl->in_hslen );
 
         return( 0 );
     }
@@ -1402,6 +1621,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 );
+        sha4_update( &ssl->fin_sha4, ssl->in_msg, ssl->in_hslen );
     }
 
     if( ssl->in_msgtype == SSL_MSG_ALERT )
@@ -1888,7 +2108,7 @@
     SSL_DEBUG_MSG( 2, ( "<= calc  finished" ) );
 }
 
-static void ssl_calc_finished_tls1_2(
+static void ssl_calc_finished_tls_sha256(
                 ssl_context *ssl, unsigned char *buf, int from )
 {
     int len = 12;
@@ -1927,6 +2147,45 @@
     SSL_DEBUG_MSG( 2, ( "<= calc  finished" ) );
 }
 
+static void ssl_calc_finished_tls_sha384(
+                ssl_context *ssl, unsigned char *buf, int from )
+{
+    int len = 12;
+    char *sender;
+    sha4_context sha4;
+    unsigned char padbuf[48];
+
+    SSL_DEBUG_MSG( 2, ( "=> calc  finished tls 1.2" ) );
+
+    memcpy( &sha4, &ssl->fin_sha4, sizeof( sha4_context ) );
+
+    /*
+     * TLSv1.2:
+     *   hash = PRF( master, finished_label,
+     *               Hash( handshake ) )[0.11]
+     */
+
+    SSL_DEBUG_BUF( 4, "finished sha4 state", (unsigned char *)
+                   sha4.state, sizeof( sha4.state ) );
+
+    sender = ( from == SSL_IS_CLIENT )
+             ? (char *) "client finished"
+             : (char *) "server finished";
+
+    sha4_finish( &sha4, padbuf );
+
+    ssl->tls_prf( ssl->session->master, 48, sender,
+                  padbuf, 48, buf, len );
+
+    SSL_DEBUG_BUF( 3, "calc finished result", buf, len );
+
+    memset( &sha4, 0, sizeof( sha4_context ) );
+
+    memset(  padbuf, 0, sizeof(  padbuf ) );
+
+    SSL_DEBUG_MSG( 2, ( "<= calc  finished" ) );
+}
+
 int ssl_write_finished( ssl_context *ssl )
 {
     int ret, hash_len;
@@ -2064,6 +2323,7 @@
      md5_starts( &ssl->fin_md5  );
     sha1_starts( &ssl->fin_sha1 );
     sha2_starts( &ssl->fin_sha2, 0 );
+    sha4_starts( &ssl->fin_sha4, 1 );
 
     return( 0 );
 }
@@ -2110,6 +2370,7 @@
      md5_starts( &ssl->fin_md5  );
     sha1_starts( &ssl->fin_sha1 );
     sha2_starts( &ssl->fin_sha2, 0 );
+    sha4_starts( &ssl->fin_sha4, 1 );
 }
 
 /*
@@ -2326,8 +2587,24 @@
         case SSL_EDH_RSA_AES_256_SHA256:
             return( "SSL-EDH-RSA-AES-256-SHA256" );
 #endif
+
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+        case SSL_RSA_AES_128_GCM_SHA256:
+            return( "SSL-RSA-AES-128-GCM-SHA256" );
+
+        case SSL_EDH_RSA_AES_128_GCM_SHA256:
+            return( "SSL-EDH-RSA-AES-128-GCM-SHA256" );
 #endif
 
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+        case SSL_RSA_AES_256_GCM_SHA384:
+            return( "SSL-RSA-AES-256-GCM-SHA384" );
+
+        case SSL_EDH_RSA_AES_256_GCM_SHA384:
+            return( "SSL-EDH-RSA-AES-256-GCM-SHA384" );
+#endif
+#endif /* POLARSSL_AES_C */
+
 #if defined(POLARSSL_CAMELLIA_C)
         case SSL_RSA_CAMELLIA_128_SHA:
             return( "SSL-RSA-CAMELLIA-128-SHA" );
@@ -2417,6 +2694,20 @@
     if (0 == strcasecmp(ciphersuite_name, "SSL-EDH-RSA-AES-256-SHA256"))
         return( SSL_EDH_RSA_AES_256_SHA256 );
 #endif
+
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    if (0 == strcasecmp(ciphersuite_name, "SSL-RSA-AES-128-GCM-SHA256"))
+        return( SSL_RSA_AES_128_GCM_SHA256 );
+    if (0 == strcasecmp(ciphersuite_name, "SSL-EDH-RSA-AES-128-GCM-SHA256"))
+        return( SSL_EDH_RSA_AES_128_GCM_SHA256 );
+#endif
+
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    if (0 == strcasecmp(ciphersuite_name, "SSL-RSA-AES-256-GCM-SHA384"))
+        return( SSL_RSA_AES_256_GCM_SHA384 );
+    if (0 == strcasecmp(ciphersuite_name, "SSL-EDH-RSA-AES-256-GCM-SHA384"))
+        return( SSL_EDH_RSA_AES_256_GCM_SHA384 );
+#endif
 #endif
 
 #if defined(POLARSSL_CAMELLIA_C)
@@ -2495,17 +2786,27 @@
 #if defined(POLARSSL_AES_C)
 #if defined(POLARSSL_SHA2_C)
     SSL_EDH_RSA_AES_256_SHA256,
-    SSL_EDH_RSA_AES_128_SHA256,
 #endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+    SSL_EDH_RSA_AES_256_GCM_SHA384,
+#endif
     SSL_EDH_RSA_AES_256_SHA,
+#if defined(POLARSSL_SHA2_C)
+    SSL_EDH_RSA_AES_128_SHA256,
+#endif
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    SSL_EDH_RSA_AES_128_GCM_SHA256,
+#endif
     SSL_EDH_RSA_AES_128_SHA,
 #endif
 #if defined(POLARSSL_CAMELLIA_C)
 #if defined(POLARSSL_SHA2_C)
     SSL_EDH_RSA_CAMELLIA_256_SHA256,
-    SSL_EDH_RSA_CAMELLIA_128_SHA256,
 #endif /* POLARSSL_SHA2_C */
     SSL_EDH_RSA_CAMELLIA_256_SHA,
+#if defined(POLARSSL_SHA2_C)
+    SSL_EDH_RSA_CAMELLIA_128_SHA256,
+#endif /* POLARSSL_SHA2_C */
     SSL_EDH_RSA_CAMELLIA_128_SHA,
 #endif
 #if defined(POLARSSL_DES_C)
@@ -2517,6 +2818,9 @@
 #if defined(POLARSSL_SHA2_C)
     SSL_RSA_AES_256_SHA256,
 #endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+    SSL_RSA_AES_256_GCM_SHA384,
+#endif /* POLARSSL_SHA2_C */
     SSL_RSA_AES_256_SHA,
 #endif
 #if defined(POLARSSL_CAMELLIA_C)
@@ -2529,6 +2833,9 @@
 #if defined(POLARSSL_SHA2_C)
     SSL_RSA_AES_128_SHA256,
 #endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    SSL_RSA_AES_128_GCM_SHA256,
+#endif /* POLARSSL_SHA2_C */
     SSL_RSA_AES_128_SHA,
 #endif
 #if defined(POLARSSL_CAMELLIA_C)
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
index d4798ec..0d24787 100644
--- a/programs/ssl/ssl_server.c
+++ b/programs/ssl/ssl_server.c
@@ -80,6 +80,12 @@
 #endif /* POLARSSL_SHA2_C */
     SSL_EDH_RSA_AES_256_SHA,
     SSL_EDH_RSA_AES_128_SHA,
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+    SSL_EDH_RSA_AES_256_GCM_SHA384,
+#endif
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    SSL_EDH_RSA_AES_128_GCM_SHA256,
+#endif
 #endif
 #if defined(POLARSSL_CAMELLIA_C)
 #if defined(POLARSSL_SHA2_C)
@@ -111,6 +117,12 @@
     SSL_RSA_AES_128_SHA256,
 #endif /* POLARSSL_SHA2_C */
     SSL_RSA_AES_128_SHA,
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+    SSL_RSA_AES_256_GCM_SHA384,
+#endif
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    SSL_RSA_AES_128_GCM_SHA256,
+#endif
 #endif
 #if defined(POLARSSL_CAMELLIA_C)
 #if defined(POLARSSL_SHA2_C)
diff --git a/tests/compat.sh b/tests/compat.sh
index ac41ec3..473a21a 100644
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -7,7 +7,7 @@
 if [ "X$VERIFY" = "XYES" ];
 then
     P_CLIENT_ARGS="crt_file=data_files/server2.crt key_file=data_files/server2.key"
-    O_SERVER_ARGS="-verify 10"
+    O_SERVER_ARGS="-verify 10 -CAfile data_files/test-ca.crt"
 fi
 
 for MODE in $MODES;
@@ -61,6 +61,10 @@
         SSL-EDH-RSA-AES-128-SHA256      \
         SSL-RSA-AES-256-SHA256          \
         SSL-EDH-RSA-AES-256-SHA256      \
+        SSL-RSA-AES-128-GCM-SHA256      \
+        SSL-EDH-RSA-AES-128-GCM-SHA256  \
+        SSL-RSA-AES-256-GCM-SHA384      \
+        SSL-EDH-RSA-AES-256-GCM-SHA384  \
         "
 
     O_CIPHERS="$O_CIPHERS           \
@@ -69,6 +73,10 @@
         DHE-RSA-AES128-SHA256       \
         AES256-SHA256               \
         DHE-RSA-AES256-SHA256       \
+        AES128-GCM-SHA256           \
+        DHE-RSA-AES128-GCM-SHA256   \
+        AES256-GCM-SHA384           \
+        DHE-RSA-AES256-GCM-SHA384   \
         "
 fi