mirror of
https://github.com/mirror/wget.git
synced 2025-03-25 01:00:13 +08:00
Fix buffer overflow in Public Key Pinning
* src/utils.c (wget_base64_decode): Add param for destination size, (wg_pubkey_pem_to_der): Amend call to wget_base64_decode(), (wg_pin_peer_pubkey): Likewise and fix code style. * src/utils.h: Add param to wget_base64_decode() * src/http-ntlm.c (ntlm_input): Amend call to wget_base64_decode() * src/http.c (skip_content_type): Likewise Fixes #51227
This commit is contained in:
parent
407c1f990a
commit
ae293c945a
@ -122,7 +122,7 @@ ntlm_input (struct ntlmdata *ntlm, const char *header)
|
||||
|
||||
DEBUGP (("Received a type-2 NTLM message.\n"));
|
||||
|
||||
size = wget_base64_decode (header, buffer);
|
||||
size = wget_base64_decode (header, buffer, strlen (header));
|
||||
if (size < 0)
|
||||
return false; /* malformed base64 from server */
|
||||
|
||||
|
@ -2998,7 +2998,7 @@ skip_content_type:
|
||||
char *bin_hash = alloca (dig_hash_str_len * 3 / 4 + 1);
|
||||
ssize_t hash_bin_len;
|
||||
|
||||
hash_bin_len = wget_base64_decode (dig_hash, bin_hash);
|
||||
hash_bin_len = wget_base64_decode (dig_hash, bin_hash, dig_hash_str_len * 3 / 4 + 1);
|
||||
|
||||
/* Detect malformed base64 input. */
|
||||
if (hash_bin_len < 0)
|
||||
|
138
src/utils.c
138
src/utils.c
@ -2346,7 +2346,7 @@ wget_base64_encode (const void *data, size_t length, char *dest)
|
||||
This function originates from Free Recode. */
|
||||
|
||||
ssize_t
|
||||
wget_base64_decode (const char *base64, void *dest)
|
||||
wget_base64_decode (const char *base64, void *dest, size_t size)
|
||||
{
|
||||
/* Table of base64 values for first 128 characters. Note that this
|
||||
assumes ASCII (but so does Wget in other places). */
|
||||
@ -2370,7 +2370,8 @@ wget_base64_decode (const char *base64, void *dest)
|
||||
#define IS_BASE64(c) ((IS_ASCII (c) && BASE64_CHAR_TO_VALUE (c) >= 0) || c == '=')
|
||||
|
||||
const char *p = base64;
|
||||
char *q = dest;
|
||||
unsigned char *q = dest;
|
||||
ssize_t n = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -2392,7 +2393,12 @@ wget_base64_decode (const char *base64, void *dest)
|
||||
if (c == '=' || !IS_BASE64 (c))
|
||||
return -1; /* illegal char while decoding base64 */
|
||||
value |= BASE64_CHAR_TO_VALUE (c) << 12;
|
||||
*q++ = value >> 16;
|
||||
if (size)
|
||||
{
|
||||
*q++ = value >> 16;
|
||||
size--;
|
||||
}
|
||||
n++;
|
||||
|
||||
/* Process third byte of a quadruplet. */
|
||||
NEXT_CHAR (c, p);
|
||||
@ -2412,7 +2418,12 @@ wget_base64_decode (const char *base64, void *dest)
|
||||
}
|
||||
|
||||
value |= BASE64_CHAR_TO_VALUE (c) << 6;
|
||||
*q++ = 0xff & value >> 8;
|
||||
if (size)
|
||||
{
|
||||
*q++ = 0xff & value >> 8;
|
||||
size--;
|
||||
}
|
||||
n++;
|
||||
|
||||
/* Process fourth byte of a quadruplet. */
|
||||
NEXT_CHAR (c, p);
|
||||
@ -2424,12 +2435,17 @@ wget_base64_decode (const char *base64, void *dest)
|
||||
return -1; /* illegal char while decoding base64 */
|
||||
|
||||
value |= BASE64_CHAR_TO_VALUE (c);
|
||||
*q++ = 0xff & value;
|
||||
if (size)
|
||||
{
|
||||
*q++ = 0xff & value;
|
||||
size--;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
#undef IS_BASE64
|
||||
#undef BASE64_CHAR_TO_VALUE
|
||||
|
||||
return q - (char *) dest;
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBPCRE
|
||||
@ -2726,7 +2742,7 @@ wg_pubkey_pem_to_der (const char *pem, unsigned char **der, size_t *der_len)
|
||||
|
||||
base64data = xmalloc (BASE64_LENGTH(stripped_pem_count));
|
||||
|
||||
size = wget_base64_decode (stripped_pem, base64data);
|
||||
size = wget_base64_decode (stripped_pem, base64data, BASE64_LENGTH(stripped_pem_count));
|
||||
|
||||
if (size < 0) {
|
||||
xfree (base64data); /* malformed base64 from server */
|
||||
@ -2765,54 +2781,65 @@ wg_pin_peer_pubkey (const char *pinnedpubkey, const char *pubkey, size_t pubkeyl
|
||||
return result;
|
||||
|
||||
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
|
||||
if (strncmp (pinnedpubkey, "sha256//", 8) == 0) {
|
||||
/* compute sha256sum of public key */
|
||||
sha256sumdigest = xmalloc (SHA256_DIGEST_SIZE);
|
||||
sha256_buffer (pubkey, pubkeylen, sha256sumdigest);
|
||||
expectedsha256sumdigest = xmalloc (SHA256_DIGEST_SIZE + 1);
|
||||
if (strncmp (pinnedpubkey, "sha256//", 8) == 0)
|
||||
{
|
||||
/* compute sha256sum of public key */
|
||||
sha256sumdigest = xmalloc (SHA256_DIGEST_SIZE);
|
||||
sha256_buffer (pubkey, pubkeylen, sha256sumdigest);
|
||||
expectedsha256sumdigest = xmalloc (SHA256_DIGEST_SIZE);
|
||||
|
||||
/* it starts with sha256//, copy so we can modify it */
|
||||
pinkeylen = strlen (pinnedpubkey) + 1;
|
||||
pinkeycopy = xmalloc (pinkeylen);
|
||||
memcpy (pinkeycopy, pinnedpubkey, pinkeylen);
|
||||
/* it starts with sha256//, copy so we can modify it */
|
||||
pinkeylen = strlen (pinnedpubkey) + 1;
|
||||
pinkeycopy = xmalloc (pinkeylen);
|
||||
memcpy (pinkeycopy, pinnedpubkey, pinkeylen);
|
||||
|
||||
/* point begin_pos to the copy, and start extracting keys */
|
||||
begin_pos = pinkeycopy;
|
||||
do
|
||||
{
|
||||
end_pos = strstr (begin_pos, ";sha256//");
|
||||
/*
|
||||
* if there is an end_pos, null terminate,
|
||||
* otherwise it'll go to the end of the original string
|
||||
*/
|
||||
if (end_pos)
|
||||
end_pos[0] = '\0';
|
||||
/* point begin_pos to the copy, and start extracting keys */
|
||||
begin_pos = pinkeycopy;
|
||||
do
|
||||
{
|
||||
end_pos = strstr (begin_pos, ";sha256//");
|
||||
/*
|
||||
* if there is an end_pos, null terminate,
|
||||
* otherwise it'll go to the end of the original string
|
||||
*/
|
||||
if (end_pos)
|
||||
end_pos[0] = '\0';
|
||||
|
||||
/* decode base64 pinnedpubkey, 8 is length of "sha256//" */
|
||||
decoded_hash_length = wget_base64_decode (begin_pos + 8, expectedsha256sumdigest);
|
||||
/* if valid base64, compare sha256 digests directly */
|
||||
if (SHA256_DIGEST_SIZE == decoded_hash_length &&
|
||||
!memcmp (sha256sumdigest, expectedsha256sumdigest, SHA256_DIGEST_SIZE)) {
|
||||
result = true;
|
||||
break;
|
||||
/* decode base64 pinnedpubkey, 8 is length of "sha256//" */
|
||||
decoded_hash_length = wget_base64_decode (begin_pos + 8, expectedsha256sumdigest, SHA256_DIGEST_SIZE);
|
||||
|
||||
/* if valid base64, compare sha256 digests directly */
|
||||
if (SHA256_DIGEST_SIZE == decoded_hash_length)
|
||||
{
|
||||
if (!memcmp (sha256sumdigest, expectedsha256sumdigest, SHA256_DIGEST_SIZE))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
logprintf (LOG_VERBOSE, _ ("Skipping key with wrong size (%d/%d): %s\n"),
|
||||
(strlen (begin_pos + 8) * 3) / 4, SHA256_DIGEST_SIZE,
|
||||
quote (begin_pos + 8));
|
||||
|
||||
/*
|
||||
* change back the null-terminator we changed earlier,
|
||||
* and look for next begin
|
||||
*/
|
||||
if (end_pos)
|
||||
{
|
||||
end_pos[0] = ';';
|
||||
begin_pos = strstr (end_pos, "sha256//");
|
||||
}
|
||||
}
|
||||
while (end_pos && begin_pos);
|
||||
|
||||
/*
|
||||
* change back the null-terminator we changed earlier,
|
||||
* and look for next begin
|
||||
*/
|
||||
if (end_pos) {
|
||||
end_pos[0] = ';';
|
||||
begin_pos = strstr (end_pos, "sha256//");
|
||||
}
|
||||
} while (end_pos && begin_pos);
|
||||
xfree (sha256sumdigest);
|
||||
xfree (expectedsha256sumdigest);
|
||||
xfree (pinkeycopy);
|
||||
|
||||
xfree (sha256sumdigest);
|
||||
xfree (expectedsha256sumdigest);
|
||||
xfree (pinkeycopy);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* fall back to assuming this is a file path */
|
||||
fm = wget_read_file (pinnedpubkey);
|
||||
@ -2832,11 +2859,12 @@ wg_pin_peer_pubkey (const char *pinnedpubkey, const char *pubkey, size_t pubkeyl
|
||||
goto cleanup;
|
||||
|
||||
/* If the sizes are the same, it can't be base64 encoded, must be der */
|
||||
if (pubkeylen == size) {
|
||||
if (!memcmp (pubkey, fm->content, pubkeylen))
|
||||
result = true;
|
||||
goto cleanup;
|
||||
}
|
||||
if (pubkeylen == size)
|
||||
{
|
||||
if (!memcmp (pubkey, fm->content, pubkeylen))
|
||||
result = true;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we will assume it's PEM and try to decode it
|
||||
@ -2858,7 +2886,7 @@ wg_pin_peer_pubkey (const char *pinnedpubkey, const char *pubkey, size_t pubkeyl
|
||||
if (pubkeylen == pem_len && !memcmp (pubkey, pem_ptr, pubkeylen))
|
||||
result = true;
|
||||
|
||||
cleanup:
|
||||
cleanup:
|
||||
xfree (buf);
|
||||
xfree (pem_ptr);
|
||||
wget_read_file_free (fm);
|
||||
|
@ -149,7 +149,7 @@ void xsleep (double);
|
||||
#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
|
||||
|
||||
size_t wget_base64_encode (const void *, size_t, char *);
|
||||
ssize_t wget_base64_decode (const char *, void *);
|
||||
ssize_t wget_base64_decode (const char *, void *, size_t);
|
||||
|
||||
#ifdef HAVE_LIBPCRE
|
||||
void *compile_pcre_regex (const char *);
|
||||
|
Loading…
Reference in New Issue
Block a user