EVP_CTRL_GCM_IV_GEN: reject if the IV length is <8.

If the IV length is <8, then there is no space to store a sequence
number, and thus the incrementing logic will underflow.

Change-Id: Ia9c87e42c43a0dcf6ed9e51621d7484d6a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/95627
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Rudolf Polzer <rpolzer@google.com>
diff --git a/crypto/cipher/cipher_test.cc b/crypto/cipher/cipher_test.cc
index ea593f5..cdd235c 100644
--- a/crypto/cipher/cipher_test.cc
+++ b/crypto/cipher/cipher_test.cc
@@ -1247,6 +1247,22 @@
     int out_len;
     EXPECT_TRUE(EVP_EncryptUpdate(ctx.get(), out, &out_len, in, sizeof(in)));
   }
+
+  {
+    // If GCM IV length is less than 8, SET_IV_FIXED(-1) is allowed to succeed,
+    // but a subsequent EVP_CTRL_GCM_IV_GEN call must fail rather than
+    // underflow.
+    ScopedEVP_CIPHER_CTX ctx;
+    ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), kCipher, /*impl=*/nullptr, kKey,
+                                   /*iv=*/nullptr));
+    ASSERT_TRUE(
+        EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_SET_IVLEN, 7, nullptr));
+    ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_SET_IV_FIXED, -1,
+                                    const_cast<uint8_t *>(kIV)));
+    uint8_t counter[8];
+    EXPECT_FALSE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_IV_GEN,
+                                     sizeof(counter), counter));
+  }
 }
 
 // EVP_CIPHER's buffer management for AES-GCM's variable-length IV is messy.
diff --git a/crypto/fipsmodule/cipher/e_aes.cc.inc b/crypto/fipsmodule/cipher/e_aes.cc.inc
index 4ddf4b9..9e88412 100644
--- a/crypto/fipsmodule/cipher/e_aes.cc.inc
+++ b/crypto/fipsmodule/cipher/e_aes.cc.inc
@@ -341,7 +341,7 @@
       return 1;
 
     case EVP_CTRL_GCM_IV_GEN: {
-      if (gctx->iv_gen == 0 || gctx->key_set == 0) {
+      if (gctx->iv_gen == 0 || gctx->key_set == 0 || gctx->ivlen < 8) {
         return 0;
       }
       CRYPTO_gcm128_init_ctx(&gctx->key, &gctx->gcm, gctx->iv, gctx->ivlen);
@@ -349,8 +349,6 @@
         arg = gctx->ivlen;
       }
       OPENSSL_memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg);
-      // Invocation field will be at least 8 bytes in size, so no need to check
-      // wrap around or increment more than last 8 bytes.
       uint8_t *ctr = gctx->iv + gctx->ivlen - 8;
       CRYPTO_store_u64_be(ctr, CRYPTO_load_u64_be(ctr) + 1);
       gctx->iv_set = 1;