digest: handle quotes in the path
No binary (build failed)
—
(log yok)
| @@ -148,35 +148,26 @@ static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */ | |
| } | |
| /* Perform quoted-string escaping as described in RFC2616 and its errata */ | |
| - | static char *auth_digest_string_quoted(const char *source) |
| + | static char *auth_digest_string_quoted(const char *s) |
| { | |
| - | char *dest; |
| - | const char *s = source; |
| - | size_t n = 1; /* null-terminator */ |
| - | |
| - | /* Calculate size needed */ |
| + | struct dynbuf out; |
| + | curlx_dyn_init(&out, 2048); |
| + | if(!*s) /* for zero length input, make sure we return an empty string */ |
| + | return curlx_strdup(""); |
| while(*s) { | |
| - | ++n; |
| + | CURLcode result; |
| if(*s == '"' || *s == '\\') { | |
| - | ++n; |
| - | } |
| - | ++s; |
| - | } |
| - | |
| - | dest = curlx_malloc(n); |
| - | if(dest) { |
| - | char *d = dest; |
| - | s = source; |
| - | while(*s) { |
| - | if(*s == '"' || *s == '\\') { |
| - | *d++ = '\\'; |
| - | } |
| - | *d++ = *s++; |
| + | result = curlx_dyn_addn(&out, "\\", 1); |
| + | if(!result) |
| + | result = curlx_dyn_addn(&out, s, 1); |
| } | |
| - | *d = '\0'; |
| + | else |
| + | result = curlx_dyn_addn(&out, s, 1); |
| + | if(result) |
| + | return NULL; |
| + | s++; |
| } | |
| - | |
| - | return dest; |
| + | return curlx_dyn_ptr(&out); |
| } | |
| /* Retrieves the value for a corresponding key from the challenge string | |
| @@ -672,16 +663,15 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, | |
| * Returns CURLE_OK on success. | |
| */ | |
| static CURLcode auth_create_digest_http_message( | |
| - | struct Curl_easy *data, |
| - | const char *userp, |
| - | const char *passwdp, |
| - | const unsigned char *request, |
| - | const unsigned char *uripath, |
| - | struct digestdata *digest, |
| - | char **outptr, size_t *outlen, |
| - | void (*convert_to_ascii)(unsigned char *, unsigned char *), |
| - | CURLcode (*hash)(unsigned char *, const unsigned char *, |
| - | const size_t)) |
| + | struct Curl_easy *data, |
| + | const char *userp, |
| + | const char *passwdp, |
| + | const unsigned char *request, |
| + | const unsigned char *uripath, |
| + | struct digestdata *digest, |
| + | char **outptr, size_t *outlen, |
| + | void (*convert_to_ascii)(unsigned char *, unsigned char *), |
| + | CURLcode (*hash)(unsigned char *, const unsigned char *, const size_t)) |
| { | |
| CURLcode result; | |
| unsigned char hashbuf[32]; /* 32 bytes/256 bits */ | |
| @@ -691,12 +681,15 @@ static CURLcode auth_create_digest_http_message( | |
| char userh[65]; | |
| char *cnonce = NULL; | |
| size_t cnonce_sz = 0; | |
| - | char *userp_quoted; |
| - | char *realm_quoted; |
| - | char *nonce_quoted; |
| - | char *response = NULL; |
| + | char *userp_quoted = NULL; |
| + | char *realm_quoted = NULL; |
| + | char *nonce_quoted = NULL; |
| char *hashthis = NULL; | |
| - | char *tmp = NULL; |
| + | char *uri_quoted = NULL; |
| + | struct dynbuf response; |
| + | *outptr = NULL; |
| + | |
| + | curlx_dyn_init(&response, 4096); /* arbitrary max */ |
| memset(hashbuf, 0, sizeof(hashbuf)); | |
| if(!digest->nc) | |
| @@ -710,27 +703,27 @@ static CURLcode auth_create_digest_http_message( | |
| #endif | |
| (unsigned char *)cnoncebuf, | |
| sizeof(cnoncebuf)); | |
| + | if(!result) |
| + | result = curlx_base64_encode((uint8_t *)cnoncebuf, sizeof(cnoncebuf), |
| + | &cnonce, &cnonce_sz); |
| if(result) | |
| - | return result; |
| - | |
| - | result = curlx_base64_encode((uint8_t *)cnoncebuf, sizeof(cnoncebuf), |
| - | &cnonce, &cnonce_sz); |
| - | if(result) |
| - | return result; |
| + | goto oom; |
| digest->cnonce = cnonce; | |
| } | |
| if(digest->userhash) { | |
| - | hashthis = curl_maprintf("%s:%s", userp, |
| - | digest->realm ? digest->realm : ""); |
| - | if(!hashthis) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | char *hasht = curl_maprintf("%s:%s", userp, |
| + | digest->realm ? digest->realm : ""); |
| + | if(!hasht) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| - | result = hash(hashbuf, (unsigned char *)hashthis, strlen(hashthis)); |
| - | curlx_free(hashthis); |
| + | result = hash(hashbuf, (unsigned char *)hasht, strlen(hasht)); |
| + | curlx_free(hasht); |
| if(result) | |
| - | return result; |
| + | goto oom; |
| convert_to_ascii(hashbuf, (unsigned char *)userh); | |
| } | |
| @@ -745,27 +738,31 @@ static CURLcode auth_create_digest_http_message( | |
| unq(nonce-value) ":" unq(cnonce-value) | |
| */ | |
| - | hashthis = curl_maprintf("%s:%s:%s", userp, |
| - | digest->realm ? digest->realm : "", passwdp); |
| - | if(!hashthis) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | hashthis = curl_maprintf("%s:%s:%s", userp, digest->realm ? |
| + | digest->realm : "", passwdp); |
| + | if(!hashthis) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| result = hash(hashbuf, (unsigned char *)hashthis, strlen(hashthis)); | |
| curlx_free(hashthis); | |
| if(result) | |
| - | return result; |
| + | goto oom; |
| convert_to_ascii(hashbuf, ha1); | |
| if(digest->algo & SESSION_ALGO) { | |
| /* nonce and cnonce are OUTSIDE the hash */ | |
| - | tmp = curl_maprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); |
| - | if(!tmp) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | char *tmp = curl_maprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); |
| + | if(!tmp) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| result = hash(hashbuf, (unsigned char *)tmp, strlen(tmp)); | |
| curlx_free(tmp); | |
| if(result) | |
| - | return result; |
| + | goto oom; |
| convert_to_ascii(hashbuf, ha1); | |
| } | |
| @@ -782,9 +779,17 @@ static CURLcode auth_create_digest_http_message( | |
| 5.1.1 of RFC 2616) | |
| */ | |
| + | uri_quoted = auth_digest_string_quoted((const char *)uripath); |
| + | if(!uri_quoted) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| + | |
| hashthis = curl_maprintf("%s:%s", request, uripath); | |
| - | if(!hashthis) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | if(!hashthis) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| if(digest->qop && curl_strequal(digest->qop, "auth-int")) { | |
| /* We do not support auth-int for PUT or POST */ | |
| @@ -792,41 +797,40 @@ static CURLcode auth_create_digest_http_message( | |
| char *hashthis2; | |
| result = hash(hashbuf, (const unsigned char *)"", 0); | |
| - | if(result) { |
| - | curlx_free(hashthis); |
| - | return result; |
| - | } |
| + | if(result) |
| + | goto oom; |
| convert_to_ascii(hashbuf, (unsigned char *)hashed); | |
| hashthis2 = curl_maprintf("%s:%s", hashthis, hashed); | |
| curlx_free(hashthis); | |
| hashthis = hashthis2; | |
| + | if(!hashthis) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| } | |
| - | if(!hashthis) |
| - | return CURLE_OUT_OF_MEMORY; |
| - | |
| result = hash(hashbuf, (unsigned char *)hashthis, strlen(hashthis)); | |
| curlx_free(hashthis); | |
| if(result) | |
| - | return result; |
| + | goto oom; |
| convert_to_ascii(hashbuf, ha2); | |
| - | if(digest->qop) { |
| + | if(digest->qop) |
| hashthis = curl_maprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, | |
| digest->nc, digest->cnonce, digest->qop, ha2); | |
| - | } |
| - | else { |
| + | else |
| hashthis = curl_maprintf("%s:%s:%s", ha1, digest->nonce, ha2); | |
| - | } |
| - | if(!hashthis) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | if(!hashthis) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| result = hash(hashbuf, (unsigned char *)hashthis, strlen(hashthis)); | |
| curlx_free(hashthis); | |
| if(result) | |
| - | return result; |
| + | goto oom; |
| convert_to_ascii(hashbuf, request_digest); | |
| /* For test case 64 (snooped from a Mozilla 1.3a request) | |
| @@ -843,8 +847,10 @@ static CURLcode auth_create_digest_http_message( | |
| characters. | |
| */ | |
| userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp); | |
| - | if(!userp_quoted) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | if(!userp_quoted) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| + | } |
| if(digest->realm) | |
| realm_quoted = auth_digest_string_quoted(digest->realm); | |
| else { | |
| @@ -853,98 +859,93 @@ static CURLcode auth_create_digest_http_message( | |
| realm_quoted[0] = 0; | |
| } | |
| if(!realm_quoted) { | |
| - | curlx_free(userp_quoted); |
| - | return CURLE_OUT_OF_MEMORY; |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| } | |
| + | |
| nonce_quoted = auth_digest_string_quoted(digest->nonce); | |
| if(!nonce_quoted) { | |
| - | curlx_free(realm_quoted); |
| - | curlx_free(userp_quoted); |
| - | return CURLE_OUT_OF_MEMORY; |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| } | |
| if(digest->qop) { | |
| - | response = curl_maprintf("username=\"%s\", " |
| - | "realm=\"%s\", " |
| - | "nonce=\"%s\", " |
| - | "uri=\"%s\", " |
| - | "cnonce=\"%s\", " |
| - | "nc=%08x, " |
| - | "qop=%s, " |
| - | "response=\"%s\"", |
| - | userp_quoted, |
| - | realm_quoted, |
| - | nonce_quoted, |
| - | uripath, |
| - | digest->cnonce, |
| - | digest->nc, |
| - | digest->qop, |
| - | request_digest); |
| + | result = curlx_dyn_addf(&response, "username=\"%s\", " |
| + | "realm=\"%s\", " |
| + | "nonce=\"%s\", " |
| + | "uri=\"%s\", " |
| + | "cnonce=\"%s\", " |
| + | "nc=%08x, " |
| + | "qop=%s, " |
| + | "response=\"%s\"", |
| + | userp_quoted, |
| + | realm_quoted, |
| + | nonce_quoted, |
| + | uri_quoted, |
| + | digest->cnonce, |
| + | digest->nc, |
| + | digest->qop, |
| + | request_digest); |
| /* Increment nonce-count to use another nc value for the next request */ | |
| digest->nc++; | |
| } | |
| else { | |
| - | response = curl_maprintf("username=\"%s\", " |
| - | "realm=\"%s\", " |
| - | "nonce=\"%s\", " |
| - | "uri=\"%s\", " |
| - | "response=\"%s\"", |
| - | userp_quoted, |
| - | realm_quoted, |
| - | nonce_quoted, |
| - | uripath, |
| - | request_digest); |
| + | result = curlx_dyn_addf(&response, "username=\"%s\", " |
| + | "realm=\"%s\", " |
| + | "nonce=\"%s\", " |
| + | "uri=\"%s\", " |
| + | "response=\"%s\"", |
| + | userp_quoted, |
| + | realm_quoted, |
| + | nonce_quoted, |
| + | uri_quoted, |
| + | request_digest); |
| } | |
| - | curlx_free(nonce_quoted); |
| - | curlx_free(realm_quoted); |
| - | curlx_free(userp_quoted); |
| - | if(!response) |
| - | return CURLE_OUT_OF_MEMORY; |
| + | if(result) |
| + | goto oom; |
| /* Add the optional fields */ | |
| if(digest->opaque) { | |
| - | char *opaque_quoted; |
| /* Append the opaque */ | |
| - | opaque_quoted = auth_digest_string_quoted(digest->opaque); |
| + | char *opaque_quoted = auth_digest_string_quoted(digest->opaque); |
| if(!opaque_quoted) { | |
| - | curlx_free(response); |
| - | return CURLE_OUT_OF_MEMORY; |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto oom; |
| } | |
| - | tmp = curl_maprintf("%s, opaque=\"%s\"", response, opaque_quoted); |
| - | curlx_free(response); |
| + | result = curlx_dyn_addf(&response, ", opaque=\"%s\"", opaque_quoted); |
| curlx_free(opaque_quoted); | |
| - | if(!tmp) |
| - | return CURLE_OUT_OF_MEMORY; |
| - | |
| - | response = tmp; |
| + | if(result) |
| + | goto oom; |
| } | |
| if(digest->algorithm) { | |
| /* Append the algorithm */ | |
| - | tmp = curl_maprintf("%s, algorithm=%s", response, digest->algorithm); |
| - | curlx_free(response); |
| - | if(!tmp) |
| - | return CURLE_OUT_OF_MEMORY; |
| - | |
| - | response = tmp; |
| + | result = curlx_dyn_addf(&response, ", algorithm=%s", digest->algorithm); |
| + | if(result) |
| + | goto oom; |
| } | |
| if(digest->userhash) { | |
| /* Append the userhash */ | |
| - | tmp = curl_maprintf("%s, userhash=true", response); |
| - | curlx_free(response); |
| - | if(!tmp) |
| - | return CURLE_OUT_OF_MEMORY; |
| - | |
| - | response = tmp; |
| + | result = curlx_dyn_add(&response, ", userhash=true"); |
| + | if(result) |
| + | goto oom; |
| } | |
| /* Return the output */ | |
| - | *outptr = response; |
| - | *outlen = strlen(response); |
| + | *outptr = curlx_dyn_ptr(&response); |
| + | *outlen = curlx_dyn_len(&response); |
| + | result = CURLE_OK; |
| - | return CURLE_OK; |
| + | oom: |
| + | curlx_free(nonce_quoted); |
| + | curlx_free(realm_quoted); |
| + | curlx_free(uri_quoted); |
| + | curlx_free(userp_quoted); |
| + | if(result) |
| + | curlx_dyn_free(&response); |
| + | return result; |
| } | |
| /* | |
| @@ -61,21 +61,21 @@ digest | |
| HTTP with Digest authorization | |
| </name> | |
| <command> | |
| - | http://%HOSTIP:%HTTPPORT/%TESTNUMBER -u testuser:testpass --digest |
| + | 'http://%HOSTIP:%HTTPPORT/%TESTNUMBER"' -u testuser:testpass --digest |
| </command> | |
| </client> | |
| # Verify data after the test has been "shot" | |
| <verify> | |
| <protocol crlf="headers"> | |
| - | GET /%TESTNUMBER HTTP/1.1 |
| + | GET /%TESTNUMBER" HTTP/1.1 |
| Host: %HOSTIP:%HTTPPORT | |
| User-Agent: curl/%VERSION | |
| Accept: */* | |
| - | GET /%TESTNUMBER HTTP/1.1 |
| + | GET /%TESTNUMBER" HTTP/1.1 |
| Host: %HOSTIP:%HTTPPORT | |
| - | Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/%TESTNUMBER", response="c55f7f30d83d774a3d2dcacf725abaca" |
| + | Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/%TESTNUMBER\"", response="1ee14b238b3259f17602e9ce41491ef9" |
| User-Agent: curl/%VERSION | |
| Accept: */* | |