Skip to content

fix(server): warn on unsupported password hashes and fix hash docs - #355

Merged
inureyes merged 4 commits into
mainfrom
fix/issue-354-password-hash-format-warn
Nov 6, 2026
Merged

inureyes merged 4 commits into
mainfrom
fix/issue-354-password-hash-format-warn

Conversation

@inureyes

@inureyes inureyes commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Aligns the server password hash docs with the formats the verifier accepts and surfaces unsupported hashes at load time instead of only per login attempt. Auth behavior is unchanged and still fails closed: verify_internal dispatch is untouched.

  • UserDefinition::password_hash rustdoc recommends Argon2id (bssh-server hash-password), accepts bcrypt ($2a$, $2b$, $2y$), and says SHA-crypt ($5$/$6$, openssl passwd -5/-6) and /etc/shadow values are rejected.
  • New private is_supported_hash_format in src/server/auth/password.rs. reload_users calls it once per final user (after inline overrides) and warns for each unsupported hash, logging only the username, never the hash. Loading continues and reload_users still returns Ok(()).
  • docs/architecture/server-configuration.md now states that SHA-crypt and /etc/shadow hashes are unsupported and produce a load-time warning.
  • The $6$ fixture in test_yaml_parsing_comprehensive is now an Argon2id-style placeholder.
  • New tests: the is_supported_hash_format helper, verifier construction with * and $6$ users, and a regression matrix for the Alpine OpenSSH bypass attack shape over *, !, empty and $6$ hashes with password lengths 0, 1, 72, 256, 257, 1024, plus Argon2id and bcrypt users still accepting the right password and rejecting a wrong one.

Note: a $2x$ hash would get the warning even though bcrypt accepts it at login. The helper follows the prefix set specified in #354; this is a false warning only, not an auth change.

Verification: cargo fmt --all -- --check and cargo clippy --all-targets --all-features -- -D warnings are clean, and cargo test lib passes (1963 passed). The four tests/integration_test.rs failures reproduce on clean main locally (localhost SSH sandbox limitation) and are left to CI.

Closes #354

The UserDefinition::password_hash rustdoc told operators to run `openssl passwd -6`, which yields a SHA-crypt hash the verifier rejects, so a user created that way could never log in. The rustdoc now recommends Argon2id via `bssh-server hash-password`, notes bcrypt is accepted, and states that SHA-crypt and /etc/shadow values are unsupported.

reload_users now warns once per final user whose hash is neither Argon2 (parseable) nor bcrypt, without logging the hash. Loading still succeeds and verify_internal dispatch is unchanged, so auth stays fail-closed.

Adds tests for the format helper, verifier construction with unsupported hashes, and a regression matrix for `*`, `!`, empty, and `$6$` hashes across password lengths 0 to 1024. The config test fixture now uses an Argon2id-style placeholder.

Refs #354
@inureyes inureyes added status:review Under review type:bug Something isn't working priority:low Low priority issue labels Nov 6, 2026
The rewritten rustdoc on UserDefinition::password_hash was a single long line, while every other doc comment in src/server/config/types.rs wraps near 80 columns. Rewrap it without changing the wording. Narrow password and config tests pass.

Refs #354
Document in the server configuration guide that SHA-crypt and /etc/shadow hashes are unsupported and now produce a load-time warning per affected user. Add an Unreleased changelog section covering the warning and the corrected password_hash rustdoc.

Validation:
- cargo fmt --all -- --check: ok
- cargo test --lib server::auth::password: 18 passed

Refs #354
CHANGELOG.md in this repo is written only by release preparation commits, so the entry for #354 belongs to the next release preparation, not this PR.

Refs #354
@inureyes inureyes added status:done Completed and removed status:review Under review labels Nov 6, 2026
@inureyes
inureyes merged commit 5de9c20 into main Nov 6, 2026
5 checks passed
@inureyes
inureyes deleted the fix/issue-354-password-hash-format-warn branch November 6, 2026 06:08
inureyes added a commit that referenced this pull request Nov 9, 2026
…ing (#357)

Follow-up to #354 / #355. Users with a `$2x$` bcrypt hash can log in but triggered the load-time "cannot log in" warning, and users with an unusable stored hash returned faster than users with a real hash, which the 100 ms floor in `verify` only hides on fast hosts. Login outcomes are unchanged for every input; `verify_internal`'s `$2` dispatch is untouched.

- `is_supported_hash_format`, the load-time warning text and the `UserDefinition::password_hash` rustdoc now list `$2x$`.
- `verify_dummy_hash` now runs, matching the invalid-username and unknown-user branches, for: unsupported-format hashes (`*`, `!`, empty, `$6$`), malformed Argon2 hashes (the original `Err` is still returned, so `verify_password` still logs it and rejects), and malformed bcrypt hashes (bad version, truncated).
- Argon2 PHC strings that parse but lack a salt or hash output (for example `$argon2id` or `$argon2id$v=19$m=19456,t=2,p=1`) are now treated as malformed: `is_supported_hash_format` rejects them, so they get the load-time warning, and `verify_argon2` returns the malformed-hash error, so they take the dummy-hash path. Before, argon2 reported them as a wrong password without hashing anything.
- A `#[cfg(test)]` call counter on `PasswordVerifier` lets tests assert exactly one dummy hash per unusable-hash or unknown-user attempt and none for valid users, with no wall-clock assertions. It is absent from non-test builds.

## Changes during review

The incomplete-Argon2 case was found by the security review and folded in here since it is the same unusable-hash timing gap #356 targets. Both tests covering it fail with the check removed.

## Verification

`cargo fmt --all -- --check`, `cargo clippy --all-targets --all-features -- -D warnings` and `cargo clippy --lib -- -D warnings` are clean. `cargo test --no-fail-fast` passes every target except the four `tests/integration_test.rs` tests, which fail identically on clean `main` locally (localhost SSH sandbox) and are left to CI.

Closes #356
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority:low Low priority issue status:done Completed type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(server): align password hash docs with supported formats and warn on unsupported hashes at load

1 participant