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;