mirror of
https://github.com/esphome/esphome.git
synced 2026-03-03 03:08:21 -07:00
Derive provided_len from string size and bound loop to digest_len
- Use auth.value().size() instead of strlen() to avoid rescanning attacker-controlled header content. - Iterate over digest_len (expected length) instead of max_len so a long Authorization header cannot force extra work. The full-width length XOR already rejects any length mismatch.
This commit is contained in:
@@ -356,21 +356,22 @@ bool AsyncWebServerRequest::authenticate(const char *username, const char *passw
|
||||
|
||||
// Constant-time comparison to avoid timing side channels.
|
||||
// No early return on length mismatch — the length difference is folded
|
||||
// into the accumulator and the loop runs over the longer of the two
|
||||
// strings so extra trailing bytes are also compared.
|
||||
// into the accumulator so any mismatch is rejected.
|
||||
const char *provided = auth_str + auth_prefix_len;
|
||||
size_t digest_len = out; // length from esp_crypto_base64_encode
|
||||
size_t provided_len = strlen(provided);
|
||||
// Derive provided_len from the already-sized std::string rather than
|
||||
// rescanning with strlen (avoids attacker-controlled scan length).
|
||||
size_t provided_len = auth.value().size() - auth_prefix_len;
|
||||
// Use full-width XOR so any bit difference in the lengths is preserved
|
||||
// (uint8_t truncation would miss differences in higher bytes, e.g.
|
||||
// digest_len vs digest_len + 256).
|
||||
volatile size_t result = digest_len ^ provided_len;
|
||||
size_t max_len = (digest_len > provided_len) ? digest_len : provided_len;
|
||||
for (size_t i = 0; i < max_len; i++) {
|
||||
// Bounds-safe: substitute 0 for bytes beyond each string's length
|
||||
char digest_ch = (i < digest_len) ? digest.get()[i] : 0;
|
||||
// Iterate over the expected digest length only — the full-width length
|
||||
// XOR above already rejects any length mismatch, and bounding the loop
|
||||
// prevents a long Authorization header from forcing extra work.
|
||||
for (size_t i = 0; i < digest_len; i++) {
|
||||
char provided_ch = (i < provided_len) ? provided[i] : 0;
|
||||
result |= static_cast<uint8_t>(digest_ch ^ provided_ch);
|
||||
result |= static_cast<uint8_t>(digest.get()[i] ^ provided_ch);
|
||||
}
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user