[PATCH 3/7] gost28147: fix out-of-bounds read in IMIT MAC verify
Jussi Kivilinna <[email protected]> Fri, 24 Jul 2026 21:48:02 +0300
| Newsgroups | gmane.comp.encryption.gpg.libgcrypt.devel |
|---|---|
| Message-ID | <[email protected]> |
* cipher/gost28147.c (gost_imit_verify): Reject tag longer than MAC. * tests/basic.c (check_mac_gost_imit_verify_len): New. (check_mac): Call check_mac_gost_imit_verify_len. -- gost_imit_verify built 8-byte MAC in stack buffer but compared caller supplied number of bytes without bounding it. Verify request longer than 8 bytes read past buffer into adjacent stack storage. Reject length above MAC size with GPG_ERR_INV_LENGTH, as HMAC verify does. Shorter lengths still verify for truncated tags. Reported-by: JEAN Jeremy <[email protected]> Signed-off-by: Jussi Kivilinna <[email protected]> --- cipher/gost28147.c | 3 +++ tests/basic.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/cipher/gost28147.c b/cipher/gost28147.c index f094d5ba..10383c23 100644 --- a/cipher/gost28147.c +++ b/cipher/gost28147.c @@ -485,6 +485,9 @@ gost_imit_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) { unsigned char tbuf[8]; + if (buflen > sizeof(tbuf)) + return GPG_ERR_INV_LENGTH; + gost_imit_finish (h); buf_put_le32 (tbuf+0, h->u.imit.n1); diff --git a/tests/basic.c b/tests/basic.c index b62a9a90..0dceebd7 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -16159,6 +16159,68 @@ out: gcry_mac_close (hd); } +#if USE_GOST28147 +static void +check_mac_gost_imit_verify_len (void) +{ + static const char key[32] _GCRY_GCC_ATTR_NONSTRING = + "\x9d\x05\xb7\x9e\x90\xca\xd0\x0a\x2c\xda\xd2\x2e\xf4\xe8\x6f\x5c" + "\xf5\xdc\x37\x68\x19\x85\xb3\xbf\xaa\x18\xc1\xc3\x05\x0a\x91\xa2"; + static const char data[16] _GCRY_GCC_ATTR_NONSTRING = + "\xb5\xa1\xf0\xe3\xce\x2f\x02\x1d\x67\x61\x94\x34\x5c\x41\xe3\x6e"; + static const size_t bad_lens[] = { 9, 16, 64, 4096 }; + unsigned char tag[8]; + unsigned char big[4096]; + size_t taglen = sizeof (tag); + gcry_mac_hd_t hd; + gcry_error_t err; + unsigned int i; + + if (gcry_mac_test_algo (GCRY_MAC_GOST28147_IMIT)) + return; + + if (verbose) + fprintf (stderr, " checking GOST28147 IMIT verify length handling\n"); + + err = gcry_mac_open (&hd, GCRY_MAC_GOST28147_IMIT, 0, NULL); + if (err) + { + fail ("gost imit verify: gcry_mac_open failed: %s\n", gpg_strerror (err)); + return; + } + + if (!(err = gcry_mac_setkey (hd, key, sizeof (key)))) + err = gcry_mac_write (hd, data, sizeof (data)); + if (!err) + err = gcry_mac_read (hd, tag, &taglen); + if (err || taglen != sizeof (tag)) + { + fail ("gost imit verify: setup failed: %s\n", gpg_strerror (err)); + goto out; + } + + err = gcry_mac_verify (hd, tag, sizeof (tag)); + if (err) + fail ("gost imit verify: 8-byte tag rejected: %s\n", gpg_strerror (err)); + err = gcry_mac_verify (hd, tag, 4); + if (err) + fail ("gost imit verify: 4-byte tag rejected: %s\n", gpg_strerror (err)); + + memset (big, 0, sizeof (big)); + memcpy (big, tag, sizeof (tag)); + for (i = 0; i < DIM (bad_lens); i++) + { + err = gcry_mac_verify (hd, big, bad_lens[i]); + if (gcry_err_code (err) != GPG_ERR_INV_LENGTH) + fail ("gost imit verify: oversized len %d not rejected: %s\n", + (int)bad_lens[i], gpg_strerror (err)); + } + +out: + gcry_mac_close (hd); +} +#endif /* USE_GOST28147 */ + static void check_mac (void) { @@ -17110,6 +17172,10 @@ check_mac (void) algos[i].expect, 1); } +#if USE_GOST28147 + check_mac_gost_imit_verify_len (); +#endif + if (verbose) fprintf (stderr, "Completed MAC checks.\n"); } -- 2.53.0