Two fixes addressing cryptographic and parsing correctness issues:
1. Enforce 16-byte GCM authentication tag in decrypt_ciphertext()
The base64url-decoded 5th JWE component (authentication tag) was passed
directly to EVP_CTRL_AEAD_SET_TAG with its attacker-controlled length.
OpenSSL accepts 1-16 byte GCM tags and only verifies that many bytes, so
a 1-byte tag reduces forgery work factor to ~256. RFC 7518 mandates 128-bit
(16 byte) tags for A*GCM. The CBC-HMAC path already enforced correct length,
confirming this was an oversight.
Fix: Add (*aead_tag)->data != 16 check before the GCM branch in
decrypt_ciphertext(), rejecting any non-16-byte tag.
Introduced by
416b87d5db (JWE A*GCM support).
2. Enforce 16-byte GCMKW tag in parse_jose() decode_jose_field()
The $.tag field from the attacker-supplied protected header in A*GCMKW
key-wrap was similarly decoded without length enforcement. Fix: Add a
size != 16 check for fields named ".tag" in decode_jose_field() when
called from the GCMKW path.
Introduced by
026652a7eb (GCMKW tag field parsing).
if (gcm) {
- /* Look for "tag" field (used by aes gcm encryption) */
- if (decode_jose_field(decoded_jose, "$.tag", &jose_fields->tag, 1))
+ /* Look for "tag" field (used by aes gcm encryption).
+ * GCMKW tag must be exactly 16 bytes per RFC 7518 */
+ if (decode_jose_field(decoded_jose, "$.tag", &jose_fields->tag, 1) ||
+ b_data(jose_fields->tag) != 16)
goto end;
/* Look for "iv" field (used by aes gcm encryption) */
(*aead_tag)->data = size;
if (gcm) {
+ /* RFC 7518 mandates a 128-bit (16 byte) authentication tag for A*GCM.
+ * OpenSSL accepts 1-16 bytes but only verifies that many bytes, so a
+ * truncated tag reduces forgery work factor to ~256 per byte short. */
+ if ((*aead_tag)->data != 16)
+ goto end;
+
aad = alloc_trash_chunk();
if (!aad)
goto end;