+81
−6
Loading
Build the assertion (login) half of the WebAuthn ceremony crypto in the internal/passkey adapter, Oracle-verified against a virtual authenticator. - BeginLogin/FinishLogin over go-webauthn BeginLogin/ValidateLogin, username-first (allowCredentials scoped to the known user's bound passkeys). Discoverable/usernameless login stays out of scope: the enrolled credentials are non-resident and the challenge store is user-keyed (migration 0007), so it would need a future migration. - WebAuthnCredentials() now populates the stored COSE public key and signature counter (assertion validation needs both to verify the signature and detect clones); enrollment ignores them, so the change is backward-compatible and the enrollment tests guard it. - VerifiedAssertion seam output: which credential signed plus the raw signature counter. Clone/regression policy is deliberately NOT here — the counter is a ceremony fact and the future handler, which holds the previously stored counter, decides reject/warn. Scope: crypto adapter only. The login HTTP handlers, session minting, and the panel.* relying-party boundary/tier decision remain a deferred slice (no unauthenticated login route is added). BeginLogin/FinishLogin live on the concrete adapter, not the api.PasskeyVerifier interface, which grows only when a handler consumes them. Tests (virtualwebauthn): a real enrollment chained into a real assertion exercises the COSE public-key decode path and surfaces the advanced signature counter, plus origin-mismatch and unbound-credential rejection.