[crypto] Reject zero-length IVs for GCM ciphers

A zero-length IV is not permitted by the NIST GCM specification, since
it would lead to leaking the authentication key.

The only existing code path that can currently lead to the use of a
GCM cipher with a zero-length initialisation vector is CMS decryption.
Modifying a CMS encrypted message to include a zero-length IV would
leak information required to obtain the authentication key into the
transient decrypted image, but this transient image would then fail
the GCM authentication tag check and so the decrypted plaintext would
be immediately overwritten (with the re-encrypted ciphertext).

Improve robustness by rejecting a zero-length initialisation vector
for a GCM cipher, and add a test case to ensure that this rejection
remains in place in future.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2026-09-01 14:24:42 +01:00
parent 474abc95d9
commit e49e1db1c2
3 changed files with 13 additions and 1 deletions
+7 -1
View File
@@ -37,6 +37,7 @@ FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/gcm.h>
@@ -473,7 +474,7 @@ int gcm_setiv ( struct cipher_algorithm *cipher, void *ctx,
/* Initialisation vector is exactly 96 bits, use it as-is */
memcpy ( context->gcm.ctr.ctr.iv, iv, ivlen );
} else {
} else if ( ivlen ) {
/* Calculate hash over initialisation vector */
context->gcm.flags = GCM_FL_IV;
@@ -486,6 +487,11 @@ int gcm_setiv ( struct cipher_algorithm *cipher, void *ctx,
build_assert ( gcm_offset ( ctr ) > gcm_offset ( hash ) );
build_assert ( gcm_offset ( ctr ) > gcm_offset ( len ) );
build_assert ( gcm_offset ( ctr ) < gcm_offset ( key ) );
} else {
/* Zero-length IVs are not permitted */
return -ENOTSUP;
}
DBGC2 ( context, "GCM %p Y[0]:\n", context );
+1
View File
@@ -457,6 +457,7 @@ FILE_SECBOOT ( PERMITTED );
#define ERRFILE_cbc ( ERRFILE_OTHER | 0x006c0000 )
#define ERRFILE_channel ( ERRFILE_OTHER | 0x006d0000 )
#define ERRFILE_tlskey ( ERRFILE_OTHER | 0x006e0000 )
#define ERRFILE_gcm ( ERRFILE_OTHER | 0x006f0000 )
/** @} */
+5
View File
@@ -357,6 +357,10 @@ CIPHER_TEST ( gcm_test_18, &aes_gcm_algorithm, GCM_KEY_256,
AUTH ( 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, 0xc8,
0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a ) );
/** Zero-length IV */
CIPHER_TEST ( gcm_empty_iv, &aes_gcm_algorithm, GCM_KEY_256, IV(),
ADDITIONAL(), PLAINTEXT(), CIPHERTEXT(), AUTH() );
/**
* Perform Galois/Counter Mode self-test
*
@@ -384,6 +388,7 @@ static void gcm_test_exec ( void ) {
cipher_ok ( &gcm_test_16 );
cipher_ok ( &gcm_test_17 );
cipher_ok ( &gcm_test_18 );
cipher_iv_fail_ok ( &gcm_empty_iv );
/* Speed tests */
for ( keylen = 128 ; keylen <= 256 ; keylen += 64 ) {