cURL / Mailing Lists / curl-library / Single Mail

curl-library

RE: Regression in 7.28 (and 7.27) with HTTP Digest authentication and connection reuse

From: Joe Mason <jmason_at_rim.com>
Date: Mon, 15 Oct 2012 19:59:40 +0000

> From: curl-library [curl-library-bounces_at_cool.haxx.se] on behalf of Nick
> Zitzmann [nick_at_chronosnet.com]
>
> So it appears that limiting authentication choices to digest only works around
> the problem. I also tested this with OS X's built-in curl tool, which is at
> version 7.24 under Mountain Lion, and it does not have this problem.
>
> I hope this helps resolve the issue. And I realize how frustrating it is when
> a bug-fix ends up causing a regression…

Yes. The high-level description of the problem is this:

Curl maintains three bitmasks, auth->wanted (a bit for each auth scheme that's turned on in the client), auth->avail (a bit for each auth scheme in a WWW-Authenticate header returned from the server) and auth->picked (a single bit, the single auth scheme which will actually be used). The "pickoneauth" function sets auth->picked to the most secure auth type that's in both auth->wanted and auth->avail.

curl generates the Digest auth header in a request if the "auth->picked" bitmask is set to *exactly* CURLAUTH_DIGEST, *before* pickoneauth is called. In fact at the place that auth->picked is checked, auth->avail isn't even filled in yet, because it's just generating the request, so obviously there haven't been any response headers yet. So on the first request, of course there can never be a digest header. When this happens, curl automatically generates a second request:

1st request (triggered from client) -> auth->wanted filled in, auth->avail is 0, auth->picked is 0 - no Auth header
1st response (from server) -> HTTP 401 with WWW-Authenticate header -> auth->avail filled in, pickoneauth called to set auth->picked - curl creates a followup request
2nd request (generated internally from curl) -> same as 1st request, but auth->picked now set to a single value, so Auth header added

The other bit of info needed is the nonce sent as part of WWW-Authenticate. This is sent back as part of the Auth header, so that's also stored in state.digest->nonce.

The problem comes when reusing the curl handle to make a 3rd request (2nd from the client's point of view). Before the bugfix/regression, auth->picked was inherited by this new request, even if curl_easy_reset was called. (And the last nonce received is inherited too!) So you get:

3rd request (triggered from client) -> auth->picked still set to CURLAUTH_DIGEST, so add Auth header, reusing the nonce

But this is wrong if auth->wanted has changed: maybe it doesn't include CURLAUTH_DIGEST any more, or maybe it now includes a more secure scheme that should be used instead. So now auth->picked is cleared when resetting the handle. It seems to me we SHOULD now get:

3rd request (triggered from client) -> auth->picked is 0 - no Auth header
3rd response (from server) -> HTTP 401 with WWW-Authenticate header, new nonce -> auth->avail filled in again, pickoneauth called again to set auth->picked again - curl creates a followup request
4th respose (generated internally from curl) -> same as 1st request, but auth->picked now set to a single value, so Auth header added using new nonce

Which should work even if it's not as efficient as sending a Digest header automatically. I'm not sure why that's not happening.

I've also seen an error where on the 3rd request, WWW-Authenticate is received with a new nonce, but curl ignores it because it already has a nonce set (still inherited from the last request even though auth->picked is not). That triggers this check in Curl_input_digest, causing curl to not generate a new digest header:

    /* We had a nonce since before, and we got another one now without
       'stale=true'. This means we provided bad credentials in the previous
       request */
    if(before && !d->stale)
      return CURLDIGEST_BAD;

I'm not sure exactly how to reproduce this, though.

The other wrinkle is that whatever changes we make to fix this problem, have to be tested to be sure they don't break cases where the last request actually DID fail.

Since the auth->picked bug that was fixed is more of a corner case than these new regressions, perhaps it should be reverted until these are fixed.

Unfortunately I've been called away on some non-curl work and haven't been able to look at this further.

Joe
---------------------------------------------------------------------
This transmission (including any attachments) may contain confidential information, privileged material (including material protected by the solicitor-client or other applicable privileges), or constitute non-public information. Any use of this information by anyone other than the intended recipient is prohibited. If you have received this transmission in error, please immediately reply to the sender and delete this information from your system. Use, dissemination, distribution, or reproduction of this transmission by unintended recipients is not authorized and may be unlawful.

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2012-10-15