Change cipher prototypes for GCM
diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h
index 67ca28c..ef037be 100644
--- a/include/polarssl/cipher.h
+++ b/include/polarssl/cipher.h
@@ -320,7 +320,7 @@
  * \param ctx           cipher's context. Must have been initialised.
  *
  * \return              size of the cipher's IV, or 0 if ctx has not been
- *                      initialised.
+ *                      initialised or accepts IV of various sizes.
  */
 static inline int cipher_get_iv_size( const cipher_context_t *ctx )
 {
@@ -432,11 +432,18 @@
  *
  * \param ctx           generic cipher context
  * \param iv            IV to use or NONCE_COUNTER in the case of a CTR-mode cipher
+ * \param iv_len        IV length for ciphers with variable-size IV,
+ *                      Discared by ciphers with fixed-size IV.
+ * \param ad            Additional data for AEAD ciphers, or discarded.
+ *                      May be NULL only if ad_len is 0.
+ * \param ad_len        Length of ad for AEAD ciphers, or discarded.
  *
  * \returns             0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA
  *                      if parameter verification fails.
  */
-int cipher_reset( cipher_context_t *ctx, const unsigned char *iv );
+int cipher_reset( cipher_context_t *ctx,
+                  const unsigned char *iv, size_t iv_len,
+                  const unsigned char *ad, size_t ad_len );
 
 /**
  * \brief               Generic cipher update function. Encrypts/decrypts
@@ -471,8 +478,13 @@
  *                      the last block, and written to the output buffer.
  *
  * \param ctx           Generic cipher context
- * \param output        buffer to write data to. Needs block_size data available.
+ * \param output        buffer to write data to. Needs block_size available.
  * \param olen          length of the data written to the output buffer.
+ * \param tag           Ignore by non-AEAD ciphers. For AEAD ciphers:
+ *                      - on encryption: buffer to write the tag;
+ *                      - on decryption: tag to verify.
+ *                      May be NULL if tag_len is zero.
+ * \param tag_len       Length of the tag to write/check for AEAD ciphers.
  *
  * \returns             0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if
  *                      parameter verification fails,
@@ -481,7 +493,9 @@
  *                      POLARSSL_ERR_CIPHER_INVALID_PADDING on invalid padding
  *                      while decrypting or a cipher specific error code.
  */
-int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen);
+int cipher_finish( cipher_context_t *ctx,
+                   unsigned char *output, size_t *olen,
+                   unsigned char *tag, size_t tag_len );
 
 /**
  * \brief          Checkup routine
diff --git a/include/polarssl/gcm.h b/include/polarssl/gcm.h
index 2bed342..dc058dc 100644
--- a/include/polarssl/gcm.h
+++ b/include/polarssl/gcm.h
@@ -146,7 +146,7 @@
  * \param mode      GCM_ENCRYPT or GCM_DECRYPT
  * \param iv        initialization vector
  * \param iv_len    length of IV
- * \param add       additional data
+ * \param add       additional data (or NULL if length is 0)
  * \param add_len   length of additional data
  *
  * \return         0 if successful
@@ -182,14 +182,14 @@
 
 /**
  * \brief           Generic GCM finalisation function. Wraps up the GCM stream
- *                  and generated the tag. The tag can have a maximum length of
+ *                  and generates the tag. The tag can have a maximum length of
  *                  16 bytes.
  *
  * \param ctx       GCM context
- * \param tag       buffer for holding the tag
+ * \param tag       buffer for holding the tag (may be NULL if tag_len is 0)
  * \param tag_len   length of the tag to generate
  *
- * \return         0 if successful or POLARSSL_ERR_GCM_BAD_INPUT
+ * \return          0 if successful or POLARSSL_ERR_GCM_BAD_INPUT
  */
 int gcm_finish( gcm_context *ctx,
                 unsigned char *tag,
diff --git a/library/cipher.c b/library/cipher.c
index 733f6e5..d7cac05 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -396,7 +396,9 @@
     return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA;
 }
 
-int cipher_reset( cipher_context_t *ctx, const unsigned char *iv )
+int cipher_reset( cipher_context_t *ctx,
+                  const unsigned char *iv, size_t iv_len,
+                  const unsigned char *ad, size_t ad_len )
 {
     if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv )
         return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA;
@@ -406,11 +408,13 @@
 #if defined(POLARSSL_GCM_C)
     if( POLARSSL_MODE_GCM == ctx->cipher_info->mode )
     {
-        // TODO: allow other IV length
-        // TODO: allow additional data
         return gcm_starts( ctx->cipher_ctx, ctx->operation,
-                iv, 12, (unsigned char *) "", 0 );
+                           iv, iv_len, ad, ad_len );
     }
+#else
+    ((void) ad);
+    ((void) ad_len);
+    ((void) iv_len);
 #endif
 
     memcpy( ctx->iv, iv, cipher_get_iv_size( ctx ) );
@@ -742,7 +746,9 @@
     return 0;
 }
 
-int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen)
+int cipher_finish( cipher_context_t *ctx,
+                   unsigned char *output, size_t *olen,
+                   unsigned char *tag, size_t tag_len )
 {
     int ret = 0;
 
@@ -761,8 +767,9 @@
 #if defined(POLARSSL_GCM_C)
     if( POLARSSL_MODE_GCM == ctx->cipher_info->mode )
     {
-        size_t tag_len = 0; // TODO
-        unsigned char tag[16];
+        unsigned char check_tag[16];
+        size_t i;
+        int diff;
 
         if( 0 != ( ret = gcm_update( ctx->cipher_ctx,
                         ctx->unprocessed_len, ctx->unprocessed_data,
@@ -773,11 +780,29 @@
 
         *olen += ctx->unprocessed_len;
 
-        if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, tag, tag_len ) ) )
+        if( 0 != ( ret = gcm_finish( ctx->cipher_ctx, check_tag, tag_len ) ) )
             return( ret );
 
+        /* On encryption, write the tag */
+        if( POLARSSL_ENCRYPT == ctx->operation )
+        {
+            if( tag_len != 0 )
+                memcpy( tag, check_tag, tag_len );
+            return( 0 );
+        }
+
+        /* On decryption, check the tag (in "constant-time") */
+        for( diff = 0, i = 0; i < tag_len; i++ )
+            diff |= tag[i] ^ check_tag[i];
+
+        if( diff != 0 )
+            return( POLARSSL_ERR_GCM_AUTH_FAILED );
+
         return( 0 );
     }
+#else
+    ((void) tag);
+    ((void) tag_len);
 #endif
 
     if( POLARSSL_MODE_CBC == ctx->cipher_info->mode )
diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c
index c8eee54..5c98100 100644
--- a/library/cipher_wrap.c
+++ b/library/cipher_wrap.c
@@ -271,7 +271,7 @@
     POLARSSL_MODE_GCM,
     128,
     "AES-128-GCM",
-    16,
+    0,
     16,
     &gcm_aes_info
 };
@@ -281,7 +281,7 @@
     POLARSSL_MODE_GCM,
     256,
     "AES-256-GCM",
-    16,
+    0,
     16,
     &gcm_aes_info
 };
diff --git a/library/gcm.c b/library/gcm.c
index 104fda3..99036a0 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -296,7 +296,8 @@
     if( tag_len > 16 )
         return( POLARSSL_ERR_GCM_BAD_INPUT );
 
-    memcpy( tag, ctx->base_ectr, tag_len );
+    if( tag_len != 0 )
+        memcpy( tag, ctx->base_ectr, tag_len );
 
     if( orig_len || orig_add_len )
     {
diff --git a/library/pkcs12.c b/library/pkcs12.c
index e0d7207..9ccb60a 100644
--- a/library/pkcs12.c
+++ b/library/pkcs12.c
@@ -184,7 +184,7 @@
     if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 )
         goto exit;
 
-    if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 )
+    if( ( ret = cipher_reset( &cipher_ctx, iv, 0, NULL, 0 ) ) != 0 )
         goto exit;
 
     if( ( ret = cipher_update( &cipher_ctx, data, len,
@@ -193,8 +193,11 @@
         goto exit;
     }
 
-    if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
+    if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen, NULL, 0 ) )
+                != 0 )
+    {
         ret = POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH;
+    }
 
 exit:
     cipher_free_ctx( &cipher_ctx );
diff --git a/library/pkcs5.c b/library/pkcs5.c
index 9e3ce93..2b6a75a 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -187,7 +187,7 @@
     if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 )
         goto exit;
 
-    if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 )
+    if( ( ret = cipher_reset( &cipher_ctx, iv, 0, NULL, 0 ) ) != 0 )
         goto exit;
 
     if( ( ret = cipher_update( &cipher_ctx, data, datalen,
@@ -196,8 +196,11 @@
         goto exit;
     }
 
-    if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
+    if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen, NULL, 0 ) )
+                != 0 )
+    {
         ret = POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH;
+    }
 
 exit:
     md_free_ctx( &md_ctx );
diff --git a/programs/aes/crypt_and_hash.c b/programs/aes/crypt_and_hash.c
index 47b17d5..a9b862e 100644
--- a/programs/aes/crypt_and_hash.c
+++ b/programs/aes/crypt_and_hash.c
@@ -306,7 +306,7 @@
             fprintf( stderr, "cipher_setkey() returned error\n");
             goto exit;
         }
-        if( cipher_reset( &cipher_ctx, IV ) != 0 )
+        if( cipher_reset( &cipher_ctx, IV, 16, NULL, 0 ) != 0 )
         {
             fprintf( stderr, "cipher_reset() returned error\n");
             goto exit;
@@ -338,7 +338,7 @@
             }
         }
 
-        if( cipher_finish( &cipher_ctx, output, &olen ) != 0 )
+        if( cipher_finish( &cipher_ctx, output, &olen, NULL, 0 ) != 0 )
         {
             fprintf( stderr, "cipher_finish() returned error\n" );
             goto exit;
@@ -424,7 +424,7 @@
 
         cipher_setkey( &cipher_ctx, digest, cipher_info->key_length,
             POLARSSL_DECRYPT );
-        cipher_reset( &cipher_ctx, IV);
+        cipher_reset( &cipher_ctx, IV, 16, NULL, 0 );
 
         md_hmac_starts( &md_ctx, digest, 32 );
 
@@ -455,7 +455,7 @@
         /*
          * Write the final block of data
          */
-        cipher_finish( &cipher_ctx, output, &olen );
+        cipher_finish( &cipher_ctx, output, &olen, NULL, 0 );
 
         if( fwrite( output, 1, olen, fout ) != olen )
         {
diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function
index 5377208..b1814fa 100644
--- a/tests/suites/test_suite_cipher.function
+++ b/tests/suites/test_suite_cipher.function
@@ -14,6 +14,8 @@
     size_t length = length_val;
     unsigned char key[32];
     unsigned char iv[16];
+    unsigned char ad[13];
+    unsigned char tag[16];
 
     const cipher_info_t *cipher_info;
     cipher_context_t ctx_dec;
@@ -35,6 +37,8 @@
     memset( inbuf, 5, 64 );
     memset( encbuf, 0, 64 );
     memset( decbuf, 0, 64 );
+    memset( tag, 0, 16 );
+    memset( ad, 0x2a, 13 );
 
     /* Check and get info structures */
     cipher_info = cipher_info_from_type( cipher_id );
@@ -54,8 +58,8 @@
         TEST_ASSERT( 0 == cipher_set_padding_mode( &ctx_enc, pad_mode ) );
     }
 
-    TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv ) );
-    TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv ) );
+    TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, ad, 13 ) );
+    TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv, 16, ad, 13 ) );
 
     /* encode length number of bytes from inbuf */
     TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, length, encbuf, &outlen ) );
@@ -66,7 +70,8 @@
                    total_len < length &&
                    total_len + cipher_get_block_size( &ctx_enc ) > length ) );
 
-    TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + outlen, &outlen ) );
+    TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + outlen, &outlen,
+                                     tag, 16 ) );
     total_len += outlen;
 
     TEST_ASSERT( total_len == length ||
@@ -83,7 +88,8 @@
                    total_len < length &&
                    total_len + cipher_get_block_size( &ctx_dec ) >= length ) );
 
-    TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) );
+    TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen,
+                                     tag, 16 ) );
     total_len += outlen;
 
     TEST_ASSERT( total_len == length );
@@ -127,11 +133,11 @@
     TEST_ASSERT( 0 == cipher_init_ctx( &ctx, cipher_info ) );
     TEST_ASSERT( 0 == cipher_setkey( &ctx, key, key_len, POLARSSL_ENCRYPT ) );
     TEST_ASSERT( 0 == cipher_set_padding_mode( &ctx, pad_mode ) );
-    TEST_ASSERT( 0 == cipher_reset( &ctx, iv ) );
+    TEST_ASSERT( 0 == cipher_reset( &ctx, iv, 16, NULL, 0 ) );
 
     /* encode length number of bytes from inbuf */
     TEST_ASSERT( 0 == cipher_update( &ctx, inbuf, length, encbuf, &outlen ) );
-    TEST_ASSERT( ret == cipher_finish( &ctx, encbuf + outlen, &outlen ) );
+    TEST_ASSERT( ret == cipher_finish( &ctx, encbuf + outlen, &outlen, NULL, 0 ) );
 
     /* done */
     TEST_ASSERT( 0 == cipher_free_ctx( &ctx ) );
@@ -168,12 +174,13 @@
 
     TEST_ASSERT( 0 == cipher_setkey( &ctx_dec, key, 128, POLARSSL_DECRYPT ) );
 
-    TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv ) );
+    TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, NULL, 0 ) );
 
     /* decode 0-byte string */
     TEST_ASSERT( 0 == cipher_update( &ctx_dec, encbuf, 0, decbuf, &outlen ) );
     TEST_ASSERT( 0 == outlen );
-    TEST_ASSERT( POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) );
+    TEST_ASSERT( POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED == cipher_finish(
+                 &ctx_dec, decbuf + outlen, &outlen, NULL, 0 ) );
     TEST_ASSERT( 0 == outlen );
 
     TEST_ASSERT( 0 == cipher_free_ctx( &ctx_dec ) );
@@ -221,8 +228,8 @@
     TEST_ASSERT( 0 == cipher_setkey( &ctx_dec, key, key_len, POLARSSL_DECRYPT ) );
     TEST_ASSERT( 0 == cipher_setkey( &ctx_enc, key, key_len, POLARSSL_ENCRYPT ) );
 
-    TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv ) );
-    TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv ) );
+    TEST_ASSERT( 0 == cipher_reset( &ctx_dec, iv, 16, NULL, 0 ) );
+    TEST_ASSERT( 0 == cipher_reset( &ctx_enc, iv, 16, NULL, 0 ) );
 
     /* encode length number of bytes from inbuf */
     TEST_ASSERT( 0 == cipher_update( &ctx_enc, inbuf, first_length, encbuf, &outlen ) );
@@ -234,7 +241,8 @@
                    totaloutlen < length &&
                    totaloutlen + cipher_get_block_size( &ctx_enc ) > length ) );
 
-    TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + totaloutlen, &outlen ) );
+    TEST_ASSERT( 0 == cipher_finish( &ctx_enc, encbuf + totaloutlen, &outlen,
+                                     NULL, 0 ) );
     totaloutlen += outlen;
     TEST_ASSERT( totaloutlen == length ||
                  ( totaloutlen % cipher_get_block_size( &ctx_enc ) == 0 &&
@@ -250,7 +258,8 @@
                    totaloutlen < length &&
                    totaloutlen + cipher_get_block_size( &ctx_dec ) >= length ) );
 
-    TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen ) );
+    TEST_ASSERT( 0 == cipher_finish( &ctx_dec, decbuf + outlen, &outlen,
+                                     NULL, 0 ) );
     totaloutlen += outlen;
 
     TEST_ASSERT( totaloutlen == length );