Return the correct value in EVP_CIPHER_CTX_iv_length after EVP_CTRL_AEAD_SET_IVLEN

Previously, EVP_CIPHER_CTX_iv_length always returned the cipher's fixed IV length. Now, after modification with EVP_CTRL_AEAD_SET_IVLEN, it returns the correct value.

Fixed: 626
Change-Id: Id98c929439850b3e83a80111f35aabebc6e5d47a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/62907
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/cipher_extra/cipher_test.cc b/crypto/cipher_extra/cipher_test.cc
index 6101ef9..9375bc1 100644
--- a/crypto/cipher_extra/cipher_test.cc
+++ b/crypto/cipher_extra/cipher_test.cc
@@ -211,6 +211,7 @@
     ASSERT_LE(iv.size(), size_t{INT_MAX});
     ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_SET_IVLEN,
                                     static_cast<int>(iv.size()), 0));
+    ASSERT_EQ(EVP_CIPHER_CTX_iv_length(ctx.get()), iv.size());
   } else {
     ASSERT_EQ(iv.size(), EVP_CIPHER_CTX_iv_length(ctx.get()));
   }
diff --git a/crypto/fipsmodule/cipher/cipher.c b/crypto/fipsmodule/cipher/cipher.c
index 18b5e0a..bff7996 100644
--- a/crypto/fipsmodule/cipher/cipher.c
+++ b/crypto/fipsmodule/cipher/cipher.c
@@ -586,6 +586,16 @@
 }
 
 unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) {
+  if (EVP_CIPHER_mode(ctx->cipher) == EVP_CIPH_GCM_MODE) {
+    int length;
+    int res = EVP_CIPHER_CTX_ctrl((EVP_CIPHER_CTX *)ctx, EVP_CTRL_GET_IVLEN, 0,
+                                  &length);
+    // EVP_CIPHER_CTX_ctrl returning an error should be impossible under this
+    // circumstance. If it somehow did, fallback to the static cipher iv_len.
+    if (res == 1) {
+      return length;
+    }
+  }
   return ctx->cipher->iv_len;
 }
 
diff --git a/crypto/fipsmodule/cipher/e_aes.c b/crypto/fipsmodule/cipher/e_aes.c
index 0db77b8..6d91cc4 100644
--- a/crypto/fipsmodule/cipher/e_aes.c
+++ b/crypto/fipsmodule/cipher/e_aes.c
@@ -454,6 +454,10 @@
       gctx->ivlen = arg;
       return 1;
 
+    case EVP_CTRL_GET_IVLEN:
+      *(int *)ptr = gctx->ivlen;
+      return 1;
+
     case EVP_CTRL_AEAD_SET_TAG:
       if (arg <= 0 || arg > 16 || c->encrypt) {
         return 0;
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
index 310d7c2..18c1e70 100644
--- a/include/openssl/cipher.h
+++ b/include/openssl/cipher.h
@@ -542,6 +542,7 @@
 #define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
 // EVP_CTRL_GCM_SET_IV_INV sets the GCM invocation field, decrypt only
 #define EVP_CTRL_GCM_SET_IV_INV 0x18
+#define EVP_CTRL_GET_IVLEN 0x19
 
 // The following constants are unused.
 #define EVP_GCM_TLS_FIXED_IV_LEN 4