CMAC truncates one-shot block counts above 64 GiB
Closed, ResolvedPublic

Assigned To
None
Authored By
werner
Tue, Aug 4, 4:57 PM
Subscribers

Description

CMAC truncates one-shot block counts above 64 GiB

_gcry_cmac_write computes the number of complete cipher blocks from a size_t input length but stores it in unsigned int. On 64-bit builds, a sufficiently large one-shot write truncates the count passed to the bulk CBC routine, while pointer and remaining-length updates use that truncated value. The resulting CMAC covers the wrong data and returns an invalid authentication value.

Vulnerable code

In cipher/cipher-cmac.c, function _gcry_cmac_write:

if (c->bulk.cbc_enc && inlen > blocksize)
  {
    nblocks = inlen >> blocksize_shift;
    nblocks -= ((nblocks << blocksize_shift) == inlen);

    c->bulk.cbc_enc (&c->context.c, ctx->u_iv.iv, outbuf, inbuf, nblocks, 1);
    inbuf += nblocks << blocksize_shift;
    inlen -= nblocks << blocksize_shift;

    wipememory (outbuf, sizeof (outbuf));
  }

Why it matters

The supplied red/green harness used a 68,719,476,752-byte logical input: 4,294,967,296 complete blocks were expected, but the bulk callback observed one. Changing nblocks to size_t made the same test pass. Exploitation requires a single CMAC update above roughly 64 GiB with a bulk backend, which is unusual but permitted by the size_t API. Applications that authenticate very large mapped or streamed regions in one call can silently obtain the wrong tag.

Proposed fix

Declare nblocks as size_t and keep all shifts, pointer advances, and callback counts in that type. Audit bulk callback signatures to ensure they do not narrow the value again. Add the existing large logical-buffer callback test to the regression suite, checking the exact block count and a split-versus-one-shot CMAC equivalence case around the UINT_MAX-block boundary.

Related Objects

StatusAssignedTask
ResolvedNone

Event Timeline

werner triaged this task as Normal priority.Tue, Aug 4, 4:57 PM
werner created this task.
werner created this object with visibility "Public (No Login Required)".
werner created this object with edit policy "Contributor (Project)".

Internal comment by jk: Wrong CMAC tag if 64GiB+ single buffer is processed. Quite hard to trigger, but might happen if mmapped file is checksummed. Should be fixed.

jukivili changed the task status from Open to Testing.Mon, Aug 10, 6:41 AM
werner shifted this object from the Restricted Space space to the S1 Public space.