chore: update passwap v0.12.1 and align hash validation defaults/errors (#12179)

# Which Problems Are Solved

- Upgrading to `zitadel/passwap` v0.12.1 introduced new encoded-hash
validation paths that still had review feedback open.
- Secret hasher defaults were internally inconsistent (`Hasher.Cost: 4`
vs `Limits.Bcrypt.MinCost: 10`), which could reject hashes created by
the configured hasher.
- New validation error IDs/messages and test coverage needed to be
aligned with project conventions and expected behavior branches.

# How the Problems Are Solved

- Kept the dependency upgrade to `zitadel/passwap` v0.12.1 and completed
the validation integration.
- Updated `ValidateEncodedHash` error handling in
`internal/crypto/passwap.go` to:
  - use unique random-style error IDs,
  - return `Errors.Hash.NotSupported` for no-verifier cases,
  - keep invalid-hash branches mapped to invalid argument errors.
- Expanded `TestHasher_ValidateEncodedHash` in
`internal/crypto/passwap_test.go` to cover and assert:
  - bounds error branch,
  - no-verifier branch,
  - generic invalid-hash branch,
  - expected ZITADEL error IDs/messages.
- Restored lost inline verifier-context comments for argon2 and md5plain
verifier entries.

# Additional Changes

- Added the missing explanatory `Limits` comment for `SecretHasher` in
`cmd/defaults.yaml`.
- Corrected `SecretHasher.Limits.Bcrypt.MinCost` from `10` to `4` to
match the configured default bcrypt cost and avoid configuration
footguns.

# Additional Context

- Follow-up for PR review feedback in
https://github.com/zitadel/zitadel/pull/12179#pullrequestreview-4313121965

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
This commit is contained in:
Tim Möhlmann
2026-06-05 14:48:35 +02:00
committed by GitHub
co-authored by copilot-swe-agent[bot] <198982749+[email protected]> Livio Spring
parent f85a2373c5
commit 25e263394e
12 changed files with 421 additions and 75 deletions
+68 -2
View File
@@ -859,7 +859,7 @@ SystemDefaults:
# Supported algorithms: "argon2i", "argon2id", "bcrypt", "scrypt", "pbkdf2", "sha2"
# Depending on the algorithm, different configuration options take effect.
Algorithm: bcrypt # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_ALGORITHM
# Cost takes effect for the algorithms bcrypt and scrypt
# Cost takes effect for bcrypt (work factor) and scrypt (LN, log2 of N)
Cost: 14 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_COST
# Time takes effect for the algorithms argon2i and argon2id
Time: 3 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_TIME
@@ -873,6 +873,39 @@ SystemDefaults:
# Can be "sha1", "sha224", "sha256", "sha384" or "sha512" for pbkdf2
# Can be "sha256" or "sha512" for sha2
Hash: sha256 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_HASH
# Limits bound cost parameters of imported or pre-encoded password hashes.
Limits:
Bcrypt:
MinCost: 10 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_BCRYPT_MINCOST
MaxCost: 16 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_BCRYPT_MAXCOST
Argon2:
MinTime: 1 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_ARGON2_MINTIME
MaxTime: 10 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_ARGON2_MAXTIME
MinMemory: 8192 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_ARGON2_MINMEMORY
MaxMemory: 524288 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_ARGON2_MAXMEMORY
MinThreads: 1 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_ARGON2_MINTHREADS
MaxThreads: 16 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_ARGON2_MAXTHREADS
Scrypt:
MinLN: 14 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SCRYPT_MINLN
MaxLN: 20 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SCRYPT_MAXLN
MinR: 8 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SCRYPT_MINR
MaxR: 32 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SCRYPT_MAXR
MinP: 1 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SCRYPT_MINP
MaxP: 16 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SCRYPT_MAXP
PBKDF2:
MinRounds: 1000 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_PBKDF2_MINROUNDS
MaxRounds: 10000000 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_PBKDF2_MAXROUNDS
Sha2:
MinSha256Rounds: 1000 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SHA2_MINSHA256ROUNDS
MaxSha256Rounds: 999999999 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SHA2_MAXSHA256ROUNDS
MinSha512Rounds: 1000 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SHA2_MINSHA512ROUNDS
MaxSha512Rounds: 999999999 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_SHA2_MAXSHA512ROUNDS
PHPass:
MinRounds: 7 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_PHPASS_MINROUNDS
MaxRounds: 31 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_PHPASS_MAXROUNDS
Drupal7:
MinIterations: 1000 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_DRUPAL7_MINITERATIONS
MaxIterations: 500000 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_LIMITS_DRUPAL7_MAXITERATIONS
# Verifiers enable the possibility of verifying
# passwords that are previously hashed using another
@@ -903,7 +936,7 @@ SystemDefaults:
# Supported algorithms: "argon2i", "argon2id", "bcrypt", "scrypt", "pbkdf2"
# Depending on the algorithm, different configuration options take effect.
Algorithm: bcrypt # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_HASHER_ALGORITHM
# Cost takes effect for the algorithms bcrypt and scrypt
# Cost takes effect for bcrypt (work factor) and scrypt (LN, log2 of N)
Cost: 4 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_HASHER_COST
# Time takes effect for the algorithms argon2i and argon2id
Time: 3 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_HASHER_TIME
@@ -916,6 +949,39 @@ SystemDefaults:
# Hash takes effect for the algorithm pbkdf2
# Can be "sha1", "sha224", "sha256", "sha384" or "sha512"
Hash: sha256 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_HASHER_HASH
# Limits bound cost parameters of imported or pre-encoded secret hashes.
Limits:
Bcrypt:
MinCost: 4 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_BCRYPT_MINCOST
MaxCost: 16 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_BCRYPT_MAXCOST
Argon2:
MinTime: 1 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_ARGON2_MINTIME
MaxTime: 10 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_ARGON2_MAXTIME
MinMemory: 8192 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_ARGON2_MINMEMORY
MaxMemory: 524288 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_ARGON2_MAXMEMORY
MinThreads: 1 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_ARGON2_MINTHREADS
MaxThreads: 16 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_ARGON2_MAXTHREADS
Scrypt:
MinLN: 14 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SCRYPT_MINLN
MaxLN: 20 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SCRYPT_MAXLN
MinR: 8 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SCRYPT_MINR
MaxR: 32 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SCRYPT_MAXR
MinP: 1 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SCRYPT_MINP
MaxP: 16 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SCRYPT_MAXP
PBKDF2:
MinRounds: 1000 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_PBKDF2_MINROUNDS
MaxRounds: 10000000 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_PBKDF2_MAXROUNDS
Sha2:
MinSha256Rounds: 1000 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SHA2_MINSHA256ROUNDS
MaxSha256Rounds: 999999999 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SHA2_MAXSHA256ROUNDS
MinSha512Rounds: 1000 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SHA2_MINSHA512ROUNDS
MaxSha512Rounds: 999999999 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_SHA2_MAXSHA512ROUNDS
PHPass:
MinRounds: 7 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_PHPASS_MINROUNDS
MaxRounds: 31 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_PHPASS_MAXROUNDS
Drupal7:
MinIterations: 1000 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_DRUPAL7_MINITERATIONS
MaxIterations: 500000 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_LIMITS_DRUPAL7_MAXITERATIONS
Verifiers: # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_VERIFIERS
Multifactors:
OTP: