From a2b943b115ab55e25464b555aed746b2e67c8dfe Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 8 Jun 2026 23:21:55 +0200 Subject: [PATCH] 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 --- lib/vauth/digest.c | 6 ++++ tests/data/Makefile.am | 2 +- tests/data/test3221 | 74 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/data/test3221 diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c index 6d935fc99e..6cc4edbee1 100644 --- a/lib/vauth/digest.c +++ b/lib/vauth/digest.c @@ -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) diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 1fb219832e..b0caa11346 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -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 \ \ diff --git a/tests/data/test3221 b/tests/data/test3221 new file mode 100644 index 0000000000..321213ab09 --- /dev/null +++ b/tests/data/test3221 @@ -0,0 +1,74 @@ + + + + +HTTP +HTTP GET +digest + + + +# Server-side + + +HTTP/1.1 401 Authorization Required +WWW-Authenticate: Digest realm="testrealm%0a%0d", nonce="1053604145" +Content-Length: 4 + +hej + + + +HTTP/1.1 200 OK +Content-Length: 23 + +This IS the real page! + + + +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! + + + +# Client-side + + +http + + +!SSPI +crypto +digest + + +HTTP Digest with CRLF in username + + +http://hello%0a%0d:there@%HOSTIP:%HTTPPORT/ --digest + + + +# Verify data after the test has been "shot" + + +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: */* + + + +