Commit ac419bf5 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

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
parent 520833cb
Loading
Loading
Loading
Loading
+47 −2
Original line number Diff line number Diff line
@@ -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;

+1 −1
Original line number Diff line number Diff line
@@ -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 \

tests/data/test1229

0 → 100644
+82 −0
Original line number Diff line number Diff line
<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>