aes_process() passes the caller-provided tag length straight to
EVP_CTRL_AEAD_SET_TAG, and OpenSSL accepts and verifies GCM tags as short
as one byte. In the "aes_gcm_dec" converter the tag argument is documented
as coming from a variable, which in practice is populated from request
data, and in the JWE AES-GCM key-wrap path it comes directly from the
token. In both cases the party submitting the ciphertext also chooses how
many bytes of the authentication tag get checked.
An attacker submitting a one-byte tag therefore only needs about 256
attempts, instead of 2^128, to have arbitrary ciphertext accepted as
authentic. For a configuration relying on these converters to validate a
signed or encrypted token, this is a full authentication bypass.
The encrypt side always emits a 16-byte tag, so let's simply require
exactly that on the decrypt side.
This has been there since these converters were introduced, the shared
helper coming from commit
f0e64de75 ("MINOR: ssl: Factorize AES GCM data
processing") in 3.4. It must be backported to all stable versions
providing "aes_gcm_dec".
Reported-by: Claude (ANT-2026-15HD08AS)
size = out->data;
if (decrypt && gcm) {
+ /* the tag length is provided by the caller, hence often by the
+ * input itself; OpenSSL happily verifies tags as short as one
+ * byte, so require the full length that the encrypt path emits.
+ */
+ if (b_data(aead_tag) != 16)
+ goto err;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, b_data(aead_tag), b_orig(aead_tag)))
goto err;
}