Split mbedtls_gcm_update_ad out of mbedtls_gcm_starts

The GCM interface now has separate functions to start the operation
and to pass the associated data.

This is in preparation for allowing the associated data to be passed
in chunks with repeatated calls to mbedtls_gcm_update_ad().

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/cipher.c b/library/cipher.c
index 7e6d0e0..e09130a 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -415,6 +415,15 @@
     }
 #endif
 
+#if defined(MBEDTLS_GCM_C)
+    if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+    {
+        return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx,
+                                    ctx->operation,
+                                    iv, iv_len ) );
+    }
+#endif
+
     if ( actual_iv_size != 0 )
     {
         memcpy( ctx->iv, iv, actual_iv_size );
@@ -466,8 +475,8 @@
 #if defined(MBEDTLS_GCM_C)
     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
     {
-        return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
-                                    ctx->iv, ctx->iv_size, ad, ad_len ) );
+        return( mbedtls_gcm_update_ad( (mbedtls_gcm_context *) ctx->cipher_ctx,
+                                       ad, ad_len ) );
     }
 #endif
 
diff --git a/library/gcm.c b/library/gcm.c
index 13e7296..ee10093 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -269,11 +269,8 @@
 }
 
 int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
-                int mode,
-                const unsigned char *iv,
-                size_t iv_len,
-                const unsigned char *add,
-                size_t add_len )
+                        int mode,
+                        const unsigned char *iv, size_t iv_len )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char work_buf[16];
@@ -283,16 +280,11 @@
 
     GCM_VALIDATE_RET( ctx != NULL );
     GCM_VALIDATE_RET( iv != NULL );
-    GCM_VALIDATE_RET( add_len == 0 || add != NULL );
 
-    /* IV and AD are limited to 2^64 bits, so 2^61 bytes */
+    /* IV is are limited to 2^64 bits, so 2^61 bytes */
     /* IV is not allowed to be zero length */
-    if( iv_len == 0 ||
-      ( (uint64_t) iv_len  ) >> 61 != 0 ||
-      ( (uint64_t) add_len ) >> 61 != 0 )
-    {
+    if( iv_len == 0 || (uint64_t) iv_len >> 61 != 0 )
         return( MBEDTLS_ERR_GCM_BAD_INPUT );
-    }
 
     memset( ctx->y, 0x00, sizeof(ctx->y) );
     memset( ctx->buf, 0x00, sizeof(ctx->buf) );
@@ -337,6 +329,26 @@
         return( ret );
     }
 
+    return( 0 );
+}
+
+
+int mbedtls_gcm_update_ad( mbedtls_gcm_context *ctx,
+                           const unsigned char *add, size_t add_len )
+{
+    const unsigned char *p;
+    size_t use_len, i;
+
+    GCM_VALIDATE_RET( add_len == 0 || add != NULL );
+
+    /* IV is are limited to 2^64 bits, so 2^61 bytes */
+    if( (uint64_t) add_len >> 61 != 0 )
+        return( MBEDTLS_ERR_GCM_BAD_INPUT );
+
+    /* Calling update_ad multiple times is not yet supported */
+    if( ctx->add_len != 0 )
+        return( MBEDTLS_ERR_GCM_BAD_INPUT );
+
     ctx->add_len = add_len;
     p = add;
     while( add_len > 0 )
@@ -546,7 +558,10 @@
     GCM_VALIDATE_RET( length == 0 || output != NULL );
     GCM_VALIDATE_RET( tag != NULL );
 
-    if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 )
+    if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len ) ) != 0 )
+        return( ret );
+
+    if( ( ret = mbedtls_gcm_update_ad( ctx, add, add_len ) ) != 0 )
         return( ret );
 
     if( ( ret = mbedtls_gcm_update( ctx, input, length,
@@ -961,10 +976,14 @@
                 goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT,
-                                  iv_test_data[iv_index_test_data[i]],
-                                  iv_len_test_data[i],
-                                  additional_test_data[add_index_test_data[i]],
-                                  add_len_test_data[i] );
+                                      iv_test_data[iv_index_test_data[i]],
+                                      iv_len_test_data[i] );
+            if( ret != 0 )
+                goto exit;
+
+            ret = mbedtls_gcm_update_ad( &ctx,
+                              additional_test_data[add_index_test_data[i]],
+                              add_len_test_data[i] );
             if( ret != 0 )
                 goto exit;
 
@@ -1031,8 +1050,11 @@
                 goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT,
-                              iv_test_data[iv_index_test_data[i]],
-                              iv_len_test_data[i],
+                                      iv_test_data[iv_index_test_data[i]],
+                                      iv_len_test_data[i] );
+            if( ret != 0 )
+                goto exit;
+            ret = mbedtls_gcm_update_ad( &ctx,
                               additional_test_data[add_index_test_data[i]],
                               add_len_test_data[i] );
             if( ret != 0 )