digest: escape control codes too

Since the username is decoded when used and control codes are accepted
in HTTP usernames in general, the username encoding for the Digest auth
needs to percent encode such bytes.

Verified by test 3221

Reported-by: Trail of Bits
Closes #21915
This commit is contained in:
Daniel Stenberg 2026-06-08 23:21:55 +02:00
parent 04afd16076
commit a2b943b115
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
3 changed files with 81 additions and 1 deletions

View file

@ -36,6 +36,7 @@
#include "curl_sha512_256.h"
#include "curlx/strparse.h"
#include "rand.h"
#include "escape.h"
#ifndef USE_WINDOWS_SSPI
#define SESSION_ALGO 1 /* for algos with this bit set */
@ -163,6 +164,11 @@ static char *auth_digest_string_quoted(const char *s)
if(!result)
result = curlx_dyn_addn(&out, s, 1);
}
else if((*s < ' ') || (*s > 0x7e)) {
unsigned char buf[3] = { '%' };
Curl_hexbyte(&buf[1], (unsigned char)*s);
result = curlx_dyn_addn(&out, buf, 3);
}
else
result = curlx_dyn_addn(&out, s, 1);
if(result)

View file

@ -281,7 +281,7 @@ test3100 test3101 test3102 test3103 test3104 test3105 test3106 \
\
test3200 test3201 test3202 test3203 test3204 test3205 test3206 test3207 \
test3208 test3209 test3210 test3211 test3212 test3213 test3214 test3215 \
test3216 test3217 test3218 test3219 test3220 \
test3216 test3217 test3218 test3219 test3220 test3221 \
\
test3300 test3301 test3302 test3303 test3304 \
\

74
tests/data/test3221 Normal file
View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP GET
digest
</keywords>
</info>
# Server-side
<reply>
<data crlf="headers">
HTTP/1.1 401 Authorization Required
WWW-Authenticate: Digest realm="testrealm%0a%0d", nonce="1053604145"
Content-Length: 4
hej
</data>
<data1000 crlf="headers">
HTTP/1.1 200 OK
Content-Length: 23
This IS the real page!
</data1000>
<datacheck crlf="headers">
HTTP/1.1 401 Authorization Required
WWW-Authenticate: Digest realm="testrealm%0a%0d", nonce="1053604145"
Content-Length: 4
HTTP/1.1 200 OK
Content-Length: 23
This IS the real page!
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<features>
!SSPI
crypto
digest
</features>
<name>
HTTP Digest with CRLF in username
</name>
<command>
http://hello%0a%0d:there@%HOSTIP:%HTTPPORT/ --digest
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<protocol crlf="headers">
GET / HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
GET / HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Authorization: Digest username="hello%0A%0D", realm="testrealm%0a%0d", nonce="1053604145", uri="/", response="64e5ae1b90f05309847ac483c1094284"
User-Agent: curl/%VERSION
Accept: */*
</protocol>
</verify>
</testcase>