vauth/digest: improve the digest parser

Previously, if for example the nonce would end with "realm=" etc it
would get the wrong piece, due to the naive parser.

Reported-by: Joshua Rogers
Closes #18975
This commit is contained in:
Daniel Stenberg 2025-10-09 16:35:39 +02:00
parent 1e6d507de7
commit 2a2a2e5d10
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2

View file

@ -193,26 +193,43 @@ static char *auth_digest_string_quoted(const char *source)
/* Retrieves the value for a corresponding key from the challenge string
* returns TRUE if the key could be found, FALSE if it does not exists
*/
static bool auth_digest_get_key_value(const char *chlg,
const char *key,
char *value,
size_t max_val_len,
char end_char)
static bool auth_digest_get_key_value(const char *chlg, const char *key,
char *buf, size_t buflen)
{
char *find_pos;
size_t i;
/* keyword=[value],keyword2=[value]
The values may or may not be quoted.
*/
find_pos = strstr(chlg, key);
if(!find_pos)
return FALSE;
do {
struct Curl_str data;
struct Curl_str name;
if(!curlx_str_until(&chlg, &name, 64, '=') &&
!curlx_str_single(&chlg, '=')) {
/* this is the key, get the value, possibly quoted */
int rc = curlx_str_quotedword(&chlg, &data, 256);
if(rc == STRE_BEGQUOTE)
/* try unquoted until comma */
rc = curlx_str_until(&chlg, &data, 256, ',');
if(rc)
return FALSE; /* weird */
find_pos += strlen(key);
if(curlx_str_cmp(&name, key)) {
/* if this is our key, return the value */
if(curlx_strlen(&data) >= buflen)
/* doesn't fit */
return FALSE;
memcpy(buf, curlx_str(&data), curlx_strlen(&data));
buf[curlx_strlen(&data)] = 0;
return TRUE;
}
if(curlx_str_single(&chlg, ','))
return FALSE;
}
else /* odd syntax */
break;
} while(1);
for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
value[i] = *find_pos++;
value[i] = '\0';
return TRUE;
return FALSE;
}
static CURLcode auth_digest_get_qop_values(const char *options, int *value)
@ -268,21 +285,21 @@ static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
return CURLE_BAD_CONTENT_ENCODING;
/* Retrieve nonce string from the challenge */
if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"'))
if(!auth_digest_get_key_value(chlg, "nonce", nonce, nlen))
return CURLE_BAD_CONTENT_ENCODING;
/* Retrieve realm string from the challenge */
if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
if(!auth_digest_get_key_value(chlg, "realm", realm, rlen)) {
/* Challenge does not have a realm, set empty string [RFC2831] page 6 */
*realm = '\0';
}
/* Retrieve algorithm string from the challenge */
if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ','))
if(!auth_digest_get_key_value(chlg, "algorithm", alg, alen))
return CURLE_BAD_CONTENT_ENCODING;
/* Retrieve qop-options string from the challenge */
if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"'))
if(!auth_digest_get_key_value(chlg, "qop", qop, qlen))
return CURLE_BAD_CONTENT_ENCODING;
return CURLE_OK;