mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-20 23:58:54 +02:00
ghmac: Fix some signed/unsigned issues with g_checksum_update()
The length argument to `g_checksum_update()` is signed, allowing `length < 0` to indicate a nul-terminated input string. However, most of the `GHmac` machinery which calls `g_checksum_update()` uses unsigned `gsize`s. If any of those sizes exceed `G_MAXSSIZE` (which is very unlikely and could only happen with a buggy caller), the unsigned-to-signed conversion would wrap and cause `g_checksum_update()` to inappropriately interpret the input as nul-terminated. Fix that by adding a load of assertions and making the unsigned-to-signed comparisons explicit. Signed-off-by: Philip Withnall <pwithnall@endlessos.org> Coverity CID: #1486807
This commit is contained in:
20
glib/ghmac.c
20
glib/ghmac.c
@@ -100,6 +100,9 @@ g_hmac_new (GChecksumType digest_type,
|
|||||||
guchar *pad;
|
guchar *pad;
|
||||||
gsize i, len;
|
gsize i, len;
|
||||||
gsize block_size;
|
gsize block_size;
|
||||||
|
gssize block_size_signed, key_len_signed;
|
||||||
|
|
||||||
|
g_return_val_if_fail (key_len <= G_MAXSSIZE, NULL);
|
||||||
|
|
||||||
checksum = g_checksum_new (digest_type);
|
checksum = g_checksum_new (digest_type);
|
||||||
g_return_val_if_fail (checksum != NULL, NULL);
|
g_return_val_if_fail (checksum != NULL, NULL);
|
||||||
@@ -134,7 +137,9 @@ g_hmac_new (GChecksumType digest_type,
|
|||||||
if (key_len > block_size)
|
if (key_len > block_size)
|
||||||
{
|
{
|
||||||
len = block_size;
|
len = block_size;
|
||||||
g_checksum_update (hmac->digesti, key, key_len);
|
g_assert (key_len <= G_MAXSSIZE);
|
||||||
|
key_len_signed = key_len;
|
||||||
|
g_checksum_update (hmac->digesti, key, key_len_signed);
|
||||||
g_checksum_get_digest (hmac->digesti, buffer, &len);
|
g_checksum_get_digest (hmac->digesti, buffer, &len);
|
||||||
g_checksum_reset (hmac->digesti);
|
g_checksum_reset (hmac->digesti);
|
||||||
}
|
}
|
||||||
@@ -145,15 +150,19 @@ g_hmac_new (GChecksumType digest_type,
|
|||||||
memcpy (buffer, key, key_len);
|
memcpy (buffer, key, key_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* g_checksum_update() accepts a signed length, so build and check that. */
|
||||||
|
g_assert (block_size <= G_MAXSSIZE);
|
||||||
|
block_size_signed = block_size;
|
||||||
|
|
||||||
/* First pad */
|
/* First pad */
|
||||||
for (i = 0; i < block_size; i++)
|
for (i = 0; i < block_size; i++)
|
||||||
pad[i] = 0x36 ^ buffer[i]; /* ipad value */
|
pad[i] = 0x36 ^ buffer[i]; /* ipad value */
|
||||||
g_checksum_update (hmac->digesti, pad, block_size);
|
g_checksum_update (hmac->digesti, pad, block_size_signed);
|
||||||
|
|
||||||
/* Second pad */
|
/* Second pad */
|
||||||
for (i = 0; i < block_size; i++)
|
for (i = 0; i < block_size; i++)
|
||||||
pad[i] = 0x5c ^ buffer[i]; /* opad value */
|
pad[i] = 0x5c ^ buffer[i]; /* opad value */
|
||||||
g_checksum_update (hmac->digesto, pad, block_size);
|
g_checksum_update (hmac->digesto, pad, block_size_signed);
|
||||||
|
|
||||||
return hmac;
|
return hmac;
|
||||||
}
|
}
|
||||||
@@ -316,6 +325,7 @@ g_hmac_get_digest (GHmac *hmac,
|
|||||||
gsize *digest_len)
|
gsize *digest_len)
|
||||||
{
|
{
|
||||||
gsize len;
|
gsize len;
|
||||||
|
gssize len_signed;
|
||||||
|
|
||||||
g_return_if_fail (hmac != NULL);
|
g_return_if_fail (hmac != NULL);
|
||||||
|
|
||||||
@@ -324,7 +334,9 @@ g_hmac_get_digest (GHmac *hmac,
|
|||||||
|
|
||||||
/* Use the same buffer, because we can :) */
|
/* Use the same buffer, because we can :) */
|
||||||
g_checksum_get_digest (hmac->digesti, buffer, &len);
|
g_checksum_get_digest (hmac->digesti, buffer, &len);
|
||||||
g_checksum_update (hmac->digesto, buffer, len);
|
g_assert (len <= G_MAXSSIZE);
|
||||||
|
len_signed = len;
|
||||||
|
g_checksum_update (hmac->digesto, buffer, len_signed);
|
||||||
g_checksum_get_digest (hmac->digesto, buffer, digest_len);
|
g_checksum_get_digest (hmac->digesto, buffer, digest_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user