Digest auth: escape user names with \ or " in them

When sending the HTTP Authorization: header for digest, the user name
needs to be escaped if it contains a double-quote or backslash.

Test 1229 was added to verify

Reported and fixed by: Nach M. S
Bug: http://curl.haxx.se/bug/view.cgi?id=1230
This commit is contained in:
Daniel Stenberg 2013-05-27 19:45:12 +02:00
parent 520833cbe1
commit ac419bf562
3 changed files with 130 additions and 3 deletions

View File

@ -267,6 +267,38 @@ static void md5_to_ascii(unsigned char *source, /* 16 bytes */
snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
}
/* Perform quoted-string escaping as described in RFC2616 and its errata */
static char *string_quoted(const char *source)
{
char *dest, *d;
const char *s = source;
size_t n = 1; /* null terminator */
/* Calculate size needed */
while(*s) {
++n;
if(*s == '"' || *s == '\\') {
++n;
}
++s;
}
dest = (char *)malloc(n);
if(dest) {
s = source;
d = dest;
while(*s) {
if(*s == '"' || *s == '\\') {
*d++ = '\\';
}
*d++ = *s++;
}
*d = 0;
}
return dest;
}
CURLcode Curl_output_digest(struct connectdata *conn,
bool proxy,
const unsigned char *request,
@ -289,6 +321,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
char **allocuserpwd;
size_t userlen;
const char *userp;
char *userp_quoted;
const char *passwdp;
struct auth *authp;
@ -468,7 +501,18 @@ CURLcode Curl_output_digest(struct connectdata *conn,
Authorization: Digest username="testuser", realm="testrealm", \
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
Digest parameters are all quoted strings. Username which is provided by
the user will need double quotes and backslashes within it escaped. For
the other fields, this shouldn't be an issue. realm, nonce, and opaque
are copied as is from the server, escapes and all. cnonce is generated
with web-safe characters. uri is already percent encoded. nc is 8 hex
characters. algorithm and qop with standard values only contain web-safe
chracters.
*/
userp_quoted = string_quoted(userp);
if(!*userp_quoted)
return CURLE_OUT_OF_MEMORY;
if(d->qop) {
*allocuserpwd =
@ -482,7 +526,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
"qop=%s, "
"response=\"%s\"",
proxy?"Proxy-":"",
userp,
userp_quoted,
d->realm,
d->nonce,
uripath, /* this is the PATH part of the URL */
@ -505,12 +549,13 @@ CURLcode Curl_output_digest(struct connectdata *conn,
"uri=\"%s\", "
"response=\"%s\"",
proxy?"Proxy-":"",
userp,
userp_quoted,
d->realm,
d->nonce,
uripath, /* this is the PATH part of the URL */
request_digest);
}
free(userp_quoted);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;

View File

@ -93,7 +93,7 @@ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
test1216 test1217 test1218 test1219 \
test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
test1228 \
test1228 test1229 \
\
test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \

82
tests/data/test1229 Normal file
View File

@ -0,0 +1,82 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
HTTP Digest auth
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 401 Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
Content-Type: text/html; charset=iso-8859-1
Content-Length: 26
This is not the real page
</data>
# This is supposed to be returned when the server gets a
# Authorization: Digest line passed-in from the client
<data1000>
HTTP/1.1 200 OK swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Content-Length: 23
This IS the real page!
</data1000>
<datacheck>
HTTP/1.1 401 Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
Content-Type: text/html; charset=iso-8859-1
Content-Length: 26
HTTP/1.1 200 OK swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Content-Length: 23
This IS the real page!
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<features>
crypto
</features>
<name>
HTTP with Digest authorization with user name needing escape
</name>
<command>
http://%5cuser%22:password@%HOSTIP:%HTTPPORT/1229 --digest
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
GET /1229 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
GET /1229 HTTP/1.1
Authorization: Digest username="\\user\"", realm="testrealm", nonce="1053604145", uri="/1229", response="f2694d426040712584c156d3de72b8d6"
Host: %HOSTIP:%HTTPPORT
Accept: */*
</protocol>
</verify>
</testcase>