atproto-pds: a WebAuthn relying-party verifier on ring #669

Merged ngerakines.me
targeting main from passkeys
Merged opened by and assigned to ngerakines.me
targeting main from passkeys

passkey::webauthn::RelyingParty builds the creation and request options a browser needs and verifies what comes back, following WebAuthn Level 3 sections 7.1 and 7.2 for a relying party that asks for attestation "none". ES256, Ed25519 and RS256 verify with ring (already in the release graph through rustls), so the server gains no OpenSSL and no rsa crate.

Registration checks the client data (webauthn.create, the challenge in constant time, exactly one origin, not framed), the RP ID hash, UP and UV, consistent backup flags, the credential ID in all three places, and a COSE key that fits its algorithm (a P-256 point on the curve, an RSA modulus of 2048-8192 bits). A none statement must be empty and packed self-attestation is verified; any other format is recorded and not evaluated. Assertions check the same client data and flags, backup eligibility unchanged since registration, the signature, and a counter that must increase unless both sides are zero.

passkey::cbor reads the CBOR subset WebAuthn uses, refusing indefinite lengths, tags, repeated map keys and lengths the input cannot hold, and reports bytes consumed so authenticator data can find where the credential key ends. passkey::config::validate_rp_id holds an RP ID to the host or a parent domain of it.

The tests run the specification's own test vectors (section 16): the ten supported vectors register and authenticate, the ES384, ES512 and Ed448 ones are refused, the framed ones are refused at both steps, and each check is shown to refuse on its own. PasskeyError takes the passkey domain, numbers 1-16.

Refs: atproto-crates#zzsr

Commits 0