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.