F-12165: validate AES-GMAC tag length in WolfCryptMac init

Chris Conlon 2026-09-01 10:19:53 -06:00
parent 0b1dec74ae
commit c8cd44719c
2 changed files with 119 additions and 2 deletions

View File

@ -221,6 +221,7 @@ public class WolfCryptMac extends MacSpi {
protected void engineInit(Key key, AlgorithmParameterSpec params)
throws InvalidKeyException, InvalidAlgorithmParameterException {
int gmacTagBits;
byte[] encodedKey;
/* key must be of type SecretKey */
@ -242,10 +243,23 @@ public class WolfCryptMac extends MacSpi {
"AES-GMAC requires GCMParameterSpec with IV");
}
GCMParameterSpec gcmSpec = (GCMParameterSpec) params;
/* Validate all parameters before mutating any instance field,
* so a rejected init() cannot leave the object partially
* reconfigured (ex: a new IV paired with the old tag len). */
gmacTagBits = gcmSpec.getTLen();
if (gmacTagBits <= 0 || (gmacTagBits % 8) != 0 ||
(gmacTagBits / 8) > Aes.BLOCK_SIZE) {
throw new InvalidAlgorithmParameterException(
"AES-GMAC tag length must be a positive multiple of " +
"8 bits, up to " + (Aes.BLOCK_SIZE * 8) +
" bits, got " + gmacTagBits);
}
this.aesGmac.setKey(encodedKey);
this.gmacIv = gcmSpec.getIV();
/* Convert bits to bytes */
this.gmacTagLen = gcmSpec.getTLen() / 8;
this.aesGmac.setKey(encodedKey);
this.gmacTagLen = gmacTagBits / 8;
/* Reset auth data accumulator */
gmacAuthData.reset();
} else {

View File

@ -2150,6 +2150,109 @@ public class WolfCryptMacTest {
assertArrayEquals(expectedTag, mac.doFinal(authIn));
}
@Test
public void testAesGmacRejectsInvalidTagLength()
throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {
if (!enabledAlgos.contains("AESGMAC")) {
return;
}
byte[] key = new byte[] {
(byte)0x89, (byte)0xc9, (byte)0x49, (byte)0xe9,
(byte)0xc8, (byte)0x04, (byte)0xaf, (byte)0x01,
(byte)0x4d, (byte)0x56, (byte)0x04, (byte)0xb3,
(byte)0x94, (byte)0x59, (byte)0xf2, (byte)0xc8
};
byte[] iv = new byte[] {
(byte)0xd1, (byte)0xb1, (byte)0x04, (byte)0xc8,
(byte)0x15, (byte)0xbf, (byte)0x1e, (byte)0x94,
(byte)0xe2, (byte)0x8c, (byte)0x8f, (byte)0x16
};
Mac mac = Mac.getInstance("AESGMAC", "wolfJCE");
SecretKeySpec keyspec = new SecretKeySpec(key, "AES");
/* Tag lengths that are not a positive multiple of 8 bits (0, 4, 100),
* or that exceed the AES block size (136 bits = 17 bytes), must be
* rejected at init() rather than silently truncated. Exact native
* min (WOLFSSL_MIN_AUTH_TAG_SZ) is left to native wolfCrypt. */
int[] badTagBits = { 0, 4, 100, 136 };
for (int tagBits : badTagBits) {
try {
mac.init(keyspec, new GCMParameterSpec(tagBits, iv));
fail("GMAC should reject tag length " + tagBits + " bits");
} catch (InvalidAlgorithmParameterException e) {
/* expected */
}
}
/* A valid 128 bit tag must still initialize */
mac.init(keyspec, new GCMParameterSpec(128, iv));
assertEquals(16, mac.getMacLength());
}
@Test
public void testAesGmacRejectedInitPreservesState()
throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException,
ShortBufferException {
if (!enabledAlgos.contains("AESGMAC")) {
return;
}
byte[] key = new byte[] {
(byte)0x89, (byte)0xc9, (byte)0x49, (byte)0xe9,
(byte)0xc8, (byte)0x04, (byte)0xaf, (byte)0x01,
(byte)0x4d, (byte)0x56, (byte)0x04, (byte)0xb3,
(byte)0x94, (byte)0x59, (byte)0xf2, (byte)0xc8
};
byte[] iv = new byte[] {
(byte)0xd1, (byte)0xb1, (byte)0x04, (byte)0xc8,
(byte)0x15, (byte)0xbf, (byte)0x1e, (byte)0x94,
(byte)0xe2, (byte)0x8c, (byte)0x8f, (byte)0x16
};
byte[] authIn = new byte[] {
(byte)0x82, (byte)0xad, (byte)0xcd, (byte)0x63,
(byte)0x8d, (byte)0x3f, (byte)0xa9, (byte)0xd9,
(byte)0xf3, (byte)0xe8, (byte)0x41, (byte)0x00,
(byte)0xd6, (byte)0x1e, (byte)0x07, (byte)0x77
};
byte[] expectedTag = new byte[] {
(byte)0x88, (byte)0xdb, (byte)0x9d, (byte)0x62,
(byte)0x17, (byte)0x2e, (byte)0xd0, (byte)0x43,
(byte)0xaa, (byte)0x10, (byte)0xf1, (byte)0x6d,
(byte)0x22, (byte)0x7d, (byte)0xc4, (byte)0x1b
};
Mac mac = Mac.getInstance("AESGMAC", "wolfJCE");
SecretKeySpec keyspec = new SecretKeySpec(key, "AES");
/* Successful init with a valid 128 bit tag, then buffer auth data */
mac.init(keyspec, new GCMParameterSpec(128, iv));
mac.update(authIn);
/* A rejected init (invalid tag length) must not mutate the object,
* the prior valid configuration must remain intact. */
try {
mac.init(keyspec, new GCMParameterSpec(4, iv));
fail("GMAC should reject a 4 bit tag length");
} catch (InvalidAlgorithmParameterException e) {
/* expected */
}
/* getMacLength() and doFinal() must reflect the original config,
* not the rejected one */
assertEquals(16, mac.getMacLength());
assertArrayEquals(expectedTag, mac.doFinal());
}
@Test
public void testAesGmacMultipleUpdate()
throws InvalidKeyException, NoSuchAlgorithmException,