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:
parent
520833cbe1
commit
ac419bf562
@ -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;
|
||||
|
||||
|
@ -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
82
tests/data/test1229
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user