Skip to content

mod_auth_digest: cleanup part 5 - #859

Open
notroj wants to merge 9 commits into
apache:trunkfrom
notroj:mod_auth_digest-p5
Open

notroj wants to merge 9 commits into
apache:trunkfrom
notroj:mod_auth_digest-p5

Conversation

@notroj

@notroj notroj commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Follow-ups to #787 for mod_auth_digest, one commit each:

  • A nonce now verifies only under the AuthDigestNonceLifetime kind (timed or one-time) it was issued for, so a realm with both kinds of location no longer records a timestamp as a client's last one-time ordinal.
  • A client entry is bound to the user who first used it, within the server, realm and AuthDigestDomain; a request from another user quoting that entry's opaque is challenged with a fresh opaque rather than updating it.
  • A failed nonce-count check is challenged stale=true (the digest verified, and concurrent requests legitimately arrive out of order), and an unknown opaque no longer forces stale=true over the caller's flag.
  • A failed child init logs and continues with the inherited handles instead of destroying the shared memory and mutex, which the other children are using.

The entry owner is keyed on what defines the protection space (server, realm, domain) rather than the per-directory config, since that is one struct per section, and one per request under .htaccess.

🤖 Generated with Claude Code

@notroj
notroj force-pushed the mod_auth_digest-p5 branch from edb956e to 0c1770e Compare October 19, 2026 07:54
notroj and others added 9 commits October 19, 2026 19:20
* modules/aaa/mod_auth_digest.c (gen_nonce_hash): Hash in whether the
  nonce time is a timestamp or a one-time ordinal, so that a nonce
  minted under one lifetime does not verify under the other.

* test/modules/aaa/test_014_mixed_lifetime.py: New test suite.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* modules/aaa/mod_auth_digest.c (client_entry): Add owner field.
  (DEF_SHMEM_SIZE): Update the entry count for it.
  (nonce_state): Add NONCE_NOT_OWNER.
  (owner_hash): New, a keyed hash of the server name, realm and
  username.
  (client_update_nonce): Record the owner on first use; return
  NONCE_NOT_OWNER for a request from another user, leaving the entry
  alone. Drop const from r.
  (check_and_record_nonce): Challenge NONCE_NOT_OWNER as stale, with a
  new opaque, clearing the quoted one from the record.

* test/modules/aaa/test_015_cross_client.py: New test suite.

* test/modules/aaa/conftest.py: Add a second vhost sharing the realm
  with its own password file, and a tracked section with a domain.

* test/modules/aaa/env.py (AAATestEnv): Write that file.

* test/modules/aaa/htdocs/digest/nccheck-domain/secret.txt: New file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Mythos 5.1 <noreply@anthropic.com>
* modules/aaa/mod_auth_digest.c (cleanup_tables, log_error_and_cleanup):
  Removed.
  (init_failed): New, replacing them; logs the failure and returns !OK.
  (initialize_tables): Use it.
  (initialize_child): Log a failure and continue with the inherited
  handles.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* modules/aaa/mod_auth_digest.c (check_and_record_nonce): Answer
  NONCE_BAD_COUNT with stale=true like NONCE_STALE.
  (client_update_nonce): Log it at INFO rather than ERR, and without
  the "possible replay attack" wording: an out-of-order nonce-count is
  what a client's concurrent requests look like, and a replay cannot
  answer the new nonce. Alerting on AH01774 at ERR will no longer see
  it.
  (authenticate_digest_user): Expand the comment on the check order.

* test/modules/aaa/test_003_nccheck.py (test_digest_032),
  test/modules/aaa/test_007_replay.py (test_digest_074): Expect stale.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* modules/aaa/mod_auth_digest.c (note_digest_auth_failure): Leave the
  caller's stale flag alone when issuing a new opaque.

* test/modules/aaa/test_001_challenge_response.py (test_digest_016):
  New.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
  unused server argument.
  (note_digest_auth_failure, check_nonce, add_auth_info): Adjust.
  (authenticate_digest_user): Remove the unreachable missing-realm
  checks and the NULL check on new_digest().
  (init_digest_request): Fix the function name in the comment.

No functional change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
  hostnames with ap_cstr_casecmp().

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* modules/aaa/mod_auth_digest.c (client_note_renewed): Removed.
  (client_generate): Take a renewed flag and count it under the lock
  already held; log the gc summary and any rmm_free failure after
  releasing the lock, so the summary now counts the entry just added.
  (gc): Return the first rmm_free failure as the result, and the count
  through a new argument, instead of logging.
  (note_digest_auth_failure): Adjust.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* modules/aaa/mod_auth_digest.c (check_nonce): The base64 decoder stops
  at the first byte which is not base64, so a nonce of the right length
  could leave part of the decoded time unset. Check the decoded length
  and challenge as stale if it is short, before using the time.

* test/modules/aaa/test_012_truncated_nonce.py
  (test_digest_012_02_time_not_base64): New test.

Co-Authored-By: Claude Mythos 5.1 <noreply@anthropic.com>
@notroj
notroj force-pushed the mod_auth_digest-p5 branch from 0c1770e to 5e9aaa6 Compare October 19, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant