diff options
| author | Hauke Mehrtens | 2026-05-31 15:23:54 +0000 |
|---|---|---|
| committer | Hauke Mehrtens | 2026-06-07 11:24:17 +0000 |
| commit | 391dacd10d31dfec2fd32af5c74841cf07f89c28 (patch) | |
| tree | c9500b3f31ef5e4db9b0516a1ae6cdba5155b856 | |
| parent | ec47f4176b1ea3c8916ed668a8935cb8636f9317 (diff) | |
| download | uclient-391dacd10d31dfec2fd32af5c74841cf07f89c28.tar.gz | |
uclient-http: fail digest auth when the cnonce cannot be randomized
get_cnonce() returned early when fread() from /dev/urandom failed,
leaving the caller's cnonce_str[9] buffer uninitialized. That garbage
stack memory was then hashed into the digest response, embedded into the
Authorization header sent to the server (a stack information leak), and
passed to strlen()/strchr() in add_field(), which could read out of
bounds if the 9 bytes contained no NUL.
Rather than fall back to a fixed value such as a zeroed cnonce, which
would weaken digest authentication by making the client nonce
predictable, give get_cnonce() a return value and fail when no random
data can be obtained. On a failed open or read it returns -EIO and
writes nothing; the caller propagates the error and aborts the request
before the cnonce buffer is used, so it is neither leaked nor read while
uninitialized.
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/uclient/pull/16
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
| -rw-r--r-- | uclient-http.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/uclient-http.c b/uclient-http.c index 7b25e89..aa048c5 100644 --- a/uclient-http.c +++ b/uclient-http.c @@ -431,22 +431,26 @@ static bool strmatch(char **str, const char *prefix) return true; } -static void +static int get_cnonce(char *dest) { uint32_t val = 0; FILE *f; - size_t n; f = fopen("/dev/urandom", "r"); - if (f) { - n = fread(&val, sizeof(val), 1, f); + if (!f) + return -EIO; + + if (fread(&val, sizeof(val), 1, f) != 1) { fclose(f); - if (n != 1) - return; + return -EIO; } + fclose(f); + bin_to_hex(dest, &val, sizeof(val)); + + return 0; } static void add_field(char **buf, int *ofs, int *len, const char *name, const char *val) @@ -564,7 +568,9 @@ uclient_http_add_auth_digest(struct uclient_http *uh) } sprintf(nc_str, "%08x", uh->nc++); - get_cnonce(cnonce_str); + err = get_cnonce(cnonce_str); + if (err) + goto fail; data.qop = "auth"; data.uri = url->location; |