/*
- * $Id: auth_digest.cc,v 1.22 2003/02/26 06:11:41 robertc Exp $
+ * $Id: auth_digest.cc,v 1.23 2003/06/19 18:57:00 hno Exp $
*
* DEBUG: section 29 Authenticator
* AUTHOR: Robert Collins
intnc = strtol(nc, NULL, 16);
+ /* has it already been invalidated ? */
+ if (!nonce->flags.valid) {
+ debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n");
+ return 0;
+ }
+
+ /* is the nonce-count ok ? */
+ if (!digestConfig->CheckNonceCount) {
+ nonce->nc++;
+ return -1; /* forced OK by configuration */
+ }
+
if ((digestConfig->NonceStrictness && intnc != nonce->nc + 1) ||
intnc < nonce->nc + 1) {
debug(29, 4) ("authDigestNonceIsValid: Nonce count doesn't match\n");
return 0;
}
- /* has it already been invalidated ? */
- if (!nonce->flags.valid) {
- debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n");
- return 0;
- }
-
/* seems ok */
/* increment the nonce count - we've already checked that intnc is a
* valid representation for us, so we don't need the test here.
"squid is = '%s'\n", digest_request->response, Response);
if (strcasecmp(digest_request->response, Response)) {
- credentials(Failed);
- return;
+ if (digestConfig->PostWorkaround && request->method != METHOD_GET) {
+ /* Ugly workaround for certain very broken browsers using the
+ * wrong method to calculate the request-digest on POST request.
+ * This should be deleted once Digest authentication becomes more
+ * widespread and such broken browsers no longer are commonly
+ * used.
+ */
+ DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
+ digest_request->nc, digest_request->cnonce, digest_request->qop,
+ RequestMethodStr[METHOD_GET], digest_request->uri, HA2, Response);
+
+ if (strcasecmp(digest_request->response, Response)) {
+ credentials(Failed);
+ return;
+ } else {
+ const char *useragent = httpHeaderGetStr(&request->header, HDR_USER_AGENT);
+
+ static struct in_addr last_broken_addr = {0};
+
+ if (memcmp(&last_broken_addr, &request->client_addr, sizeof(last_broken_addr)) != 0) {
+ debug(29, 1) ("\nDigest POST bug detected from %s using '%s'. Please upgrade browser. See Bug #630 for details.\n", inet_ntoa(request->client_addr), useragent ? useragent : "-");
+ last_broken_addr = request->client_addr;
+ }
+ }
+ } else {
+ credentials(Failed);
+ return;
+ }
+
+ /* check for stale nonce */
+ if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) {
+ debug(29, 3) ("authenticateDigestAuthenticateuser: user '%s' validated OK but nonce stale\n",
+ digest_user->username);
+ digest_request->flags.nonce_stale = 1;
+ credentials(Failed);
+ return;
+ }
}
credentials(Ok);
+
/* password was checked and did match */
debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
digest_user->username);
case Ok:
- if (authDigestNonceIsStale(nonce))
- /* send stale response to the client agent */
- return -2;
-
return 0;
case Pending:
return -1;
case Failed:
+
+ if (digest_request->flags.nonce_stale)
+ /* nonce is stale, send new challenge */
+ return 1;
+
return -2;
}
digest_request = dynamic_cast < digest_request_h * >(auth_user_request->state());
assert (digest_request);
- if (digest_request->authenticated())
- /* stale indicates that the old nonce can't be used
- * and we are providing a new one.
- */
- stale = authDigestNonceIsStale(digest_request->nonce);
+ stale = digest_request->flags.nonce_stale;
}
/* on a 407 or 401 we always use a new nonce */
digestConfig->noncemaxduration = 30 * 60;
/* 50 requests */
digestConfig->noncemaxuses = 50;
- /* strict nonce count behaviour */
- digestConfig->NonceStrictness = 1;
+ /* Not strict nonce count behaviour */
+ digestConfig->NonceStrictness = 0;
+ /* Verify nonce count */
+ digestConfig->CheckNonceCount = 1;
}
digestConfig = static_cast < auth_digest_config * >(scheme->scheme_data);
parse_int((int *) &digestConfig->noncemaxuses);
} else if (strcasecmp(param_str, "nonce_strictness") == 0) {
parse_onoff(&digestConfig->NonceStrictness);
+ } else if (strcasecmp(param_str, "check_nonce_count") == 0) {
+ parse_onoff(&digestConfig->CheckNonceCount);
+ } else if (strcasecmp(param_str, "post_workaround") == 0) {
+ parse_onoff(&digestConfig->PostWorkaround);
} else {
debug(28, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str);
}
/* now the nonce */
nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
- if ((nonce == NULL) || !(authDigestNonceIsValid(nonce, digest_request->nc))) {
+ if (!nonce) {
/* we couldn't find a matching nonce! */
debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
authDigestLogUsername(auth_user_request, username);
#
-# $Id: cf.data.pre,v 1.322 2003/06/19 17:34:10 hno Exp $
+# $Id: cf.data.pre,v 1.323 2003/06/19 18:56:59 hno Exp $
#
#
# SQUID Web Proxy Cache http://www.squid-cache.org/
used.
"nonce_strictness" on|off
- Determines if squid requires increment-by-1 behaviour for
- nonce counts (on - the default), or strictly incrementing
- (off - for use when useragents generate nonce counts that
- occasionally miss 1 (ie, 1,2,4,6)).
+ Determines if squid requires strict increment-by-1 behaviour
+ for nonce counts, or just incrementing (off - for use when
+ useragents generate nonce counts that occasionally miss 1
+ (ie, 1,2,4,6)). Default off.
+
+ "check_nonce_count" on|off
+ This directive if set to off can disable the nonce count check
+ completely to work around buggy digest qop implementations in
+ certain mainstream browser versions. Default on to check the
+ nonce count to protect from authentication replay attacks.
+
+ "post_workaround" on|off
+ This is a workaround to certain buggy browsers who sends
+ an incorrect request digest in POST requests when reusing
+ the same nonce as aquired earlier on a GET request.
+
=== NTLM scheme options follow ===