fix(a7-auth): address SCRAM auth review findings A-G

- tests: pass CREDENTIAL_KEY_LEN to unhex for the 32-byte KAT proof/sig
  (sizeof(expect) is 348, over-reading the 65-byte hex literal under ASan)
- credentials: close the username-enumeration oracle with a store-wide
  dummy_key and a deterministic per-username dummy salt; make the store's
  iteration count uniform (reject intra-file and layered disagreements) and
  answer a miss with the store-wide count; run the constant-time key compare
  even when found=false and fold the decision with bitwise AND
- credentials_compute_keys: enforce [CREDENTIAL_MIN_ITERS, CREDENTIAL_MAX_ITERS]
- tests: recompute the whole KAT independently at CREDENTIAL_DEFAULT_ITERS
  (600000) and pin the golden store line; add non-uniform-store rejection,
  bound and deterministic-dummy-salt assertions
- server: send exactly one generic STATUS_AUTH_FAILED on every failure path
  (including credentials_get_verifier failure); route all handshake exits
  through one burn path
- credentials/server: burn the base64 decoders' scratch on error, the
  hash_store_line base64/line buffers on failure, and all handshake key/proof
  material
- fuzz: guard the auth-offset scan against size_t underflow and use a found flag
- docs: drop stale digest wording, use CREDENTIAL_MIN_ITERS as the --iterations
  bound, document 0600 output for --hash-credentials (plus a stderr warning on
  a group/other-accessible stdout file), and describe the deterministic dummy
  salt in the no-oracle claims
This commit is contained in:
2026-09-12 17:56:52 +02:00
parent 8c94ec9886
commit eaf67f6257
10 changed files with 302 additions and 112 deletions
+6 -4
View File
@@ -427,9 +427,10 @@ static const char* status_to_string(Status status) {
}
/* Shared string send/receive implementation. `redact` selects whether the
* payload body is written to the LOG_DEBUG_PROTO debug log: secrets (daemon
* auth username/digest) set it so a --verbose log never captures a replayable
* credential, while every other string keeps its normal debug trace. */
* payload body is written to the LOG_DEBUG_PROTO debug log: daemon auth material
* (the username and the proof/signature fields) sets it so a --verbose log never
* captures a replayable credential, while every other string keeps its normal
* debug trace. */
static bool protocol_send_str_impl(ProtocolSession* session, const char* data, bool redact) {
if (data == NULL)
return false;
@@ -602,7 +603,8 @@ char* receive_str(int fd) {
return protocol_receive_str(legacy_session(fd, -1));
}
/* Redacted variants: identical framing, but the string body is never written to
the debug protocol log. Used for the daemon auth username/digest. */
the debug protocol log. Used for daemon auth material (username, proof,
signature). */
bool send_str_redacted(int fd, const char* data) {
return protocol_send_str_redacted(legacy_session(-1, fd), data);
}