Skip to content

feat(core): crypto-agility + post-quantum readiness for passkey algorithms#78

Merged
wolpert merged 1 commit into
mainfrom
feat/crypto-agility-pq-readiness
Jun 18, 2026
Merged

feat(core): crypto-agility + post-quantum readiness for passkey algorithms#78
wolpert merged 1 commit into
mainfrom
feat/crypto-agility-pq-readiness

Conversation

@wolpert

@wolpert wolpert commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What & why

Improves the project's post-quantum readiness through crypto-agility and honest documentation. This is not an addition of real post-quantum signature algorithms — none are standardized in the WebAuthn/COSE/FIDO2 ecosystem or supported by WebAuthn4J yet, so none could be added without inventing fake COSE identifiers. The goal is to make the algorithm choices configurable and to document the posture accurately.

No default signing or verify behavior changes, and no stored credential or issued token can stop validating.

Findings addressed

  • Two divergent, hardcoded COSE algorithm lists: create-options (-7, -8, -257) in DefaultPasskeyAuthenticationService vs the verify list DEFAULT_PUB_KEY_PARAMS (ES256, EdDSA, RS256, ES384, RS384) in WebAuthn4JConverters.
  • No way to report which stored credentials use which algorithm.
  • No post-quantum/crypto-agility documentation anywhere.

Changes

1. One injectable source of truth for COSE algorithms

  • New framework-neutral CoseAlgorithm enum.
  • CeremonyConfig now carries offeredAlgorithms (advertised in create-options) and acceptedAlgorithms (enforced on verify). Both the create-options ceremony and the WebAuthn4J verify path derive their lists from this config — the two hardcoded lists are removed.
  • acceptedAlgorithms is authoritative; offeredAlgorithms must be a subset and may be narrower. Operators can narrow either without code changes.
  • Backward-compatible defaults: accepted = the union of everything historically accepted (ES256, EdDSA, RS256, ES384, RS384); offered = the historical create subset (ES256, EdDSA, RS256). A new 5-arg CeremonyConfig convenience constructor keeps every existing call site compiling and behaving identically.

2. Per-credential algorithm visibility (no schema change)

  • CredentialAlgorithms.coseAlgorithm(record) decodes the COSE algorithm already embedded in the stored public key.
  • AdminService.listCredentialsByAlgorithm(actor, target, coseAlgorithm) reports which credentials use a given (e.g. quantum-vulnerable) algorithm — the read side a future re-enrollment campaign drives off.

3. Honest JWT framing (docs/comments only)

  • Replaced the misleading "HS256 dev / ES256 production" framing in pk-auth-jwt package-info and JwtKeyset.hs256: HMAC-SHA256 with a ≥256-bit key is not Shor-broken (~128-bit under Grover) and is the quantum-conservative choice for a single-issuer/single-verifier deployment; ES256 exists for untrusted third-party verification and is Shor-vulnerable but bounded by the short token TTL. No signing behavior or defaults changed.

4–6. Docs

  • docs/threat-model.md: new Post-quantum readiness section (Shor-vulnerable signatures gated by hardware/CTAP/WebAuthn/COSE/WebAuthn4J; why exposure is bounded; the crypto-agility hooks; symmetric secrets already 256-bit/Grover-resistant).
  • docs/operator-guide.md: new Transport security & post-quantum section — the genuine harvest-now/decrypt-later risk is recorded TLS sessions; recommend a hybrid PQC KEM (e.g. X25519MLKEM768) at the TLS terminator/CDN. Framed explicitly as an operator action, not a library change.
  • BackupCodeService: short comment noting ~50-bit code entropy and that CODE_LENGTH is the lever (default unchanged).

7. ADR

  • docs/adr/0019-crypto-agility-post-quantum-readiness.md (+ README index row).

Tests

  • DefaultPasskeyAuthenticationServiceAlgorithmTest — (a) defaults still offer/accept the historical algorithms, (b) a custom config flows into both create options and verify params, (c) an algorithm absent from config is excluded from the verify params (so WebAuthn4J rejects it).
  • CredentialAlgorithmsTest — decode ES256 from a stored key; undecodable key throws.
  • DefaultAdminServiceTestlistCredentialsByAlgorithm matching/empty + authorization.

Verification

./gradlew check passes (spotless + tests + JaCoCo coverage gates), Docker available for the Testcontainers persistence suites.

🤖 Generated with Claude Code

…ithms

Unify the two divergent hardcoded COSE algorithm lists into one injectable
source of truth and document the post-quantum posture honestly. No new
signature algorithms are added (none are standardized in WebAuthn/COSE/FIDO2
or supported by WebAuthn4J yet) and no default signing/verify behavior changes.

- Introduce CoseAlgorithm enum and carry offeredAlgorithms / acceptedAlgorithms
  on CeremonyConfig. Both the create-options ceremony and the WebAuthn4J verify
  path now derive their lists from this config; the two hardcoded lists are gone.
  Defaults preserve exact behavior: offered = ES256/EdDSA/RS256, accepted = the
  historical union ES256/EdDSA/RS256/ES384/RS384. A backward-compatible 5-arg
  CeremonyConfig constructor keeps existing call sites unchanged.
- Add CredentialAlgorithms (decodes the COSE algorithm already stored on each
  credential, no schema change) and AdminService.listCredentialsByAlgorithm to
  report which credentials use a given (quantum-vulnerable) algorithm for a
  future re-enrollment campaign.
- Reframe the misleading "HS256 dev / ES256 production" JWT comments: HS256 with
  a strong key is the quantum-conservative choice for single-issuer/verifier;
  ES256 is for untrusted third-party verification and is Shor-vulnerable but
  TTL-bounded. Docs/comments only.
- Docs: Post-quantum readiness section in threat-model, TLS hybrid-KEM
  (harvest-now/decrypt-later) note in operator-guide, backup-code entropy
  comment, and ADR 0019.

Tests cover the config plumbing into both create and verify, algorithm
rejection on verify, COSE-algorithm decode, and the admin report.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@wolpert
wolpert merged commit a85c309 into main Jun 18, 2026
8 checks passed
@wolpert
wolpert deleted the feat/crypto-agility-pq-readiness branch June 18, 2026 01:04
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