diff options
| -rw-r--r-- | lib/http_digest.c | 49 | ||||
| -rw-r--r-- | tests/data/Makefile.am | 2 | ||||
| -rw-r--r-- | tests/data/test1229 | 82 | 
3 files changed, 130 insertions, 3 deletions
diff --git a/lib/http_digest.c b/lib/http_digest.c index 43513966b..74689842e 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -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; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index d54152f41..48204a15f 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -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 \ diff --git a/tests/data/test1229 b/tests/data/test1229 new file mode 100644 index 000000000..dcb55e886 --- /dev/null +++ b/tests/data/test1229 @@ -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>  | 
