Expand description
§webauthn-kit
Standalone WebAuthn / FIDO2 passkey verification kit: real CTAP2/COSE
cryptographic verification with zero framework coupling. This is not a
wrapper around navigator.credentials server emulation — it implements
the server side of the protocol directly on ring.
§What it does
- Full CTAP2 authenticator data parsing (rpIdHash, flags, signCount,
attested credential data incl. AAGUID) —
protocol verify_registration/verify_authenticationceremonies —protocol- Attestation statement verification for the
none,packed(self- and x5c-based basic/AttCA), andfido-u2fformats, with X.509 chain verification against caller-configured trust anchors —attestation - COSE public key parsing and signature verification for ES256
(ECDSA P-256 + SHA-256), ES384 (ECDSA P-384 + SHA-384), EdDSA
(Ed25519), and RS256 (RSA PKCS#1 v1.5 + SHA-256) via
ring—crypto - Enforceable credential policies — user verification (UV), multi-device
/ backup eligibility (BE/BS), and registration algorithm allowlists —
policy - Challenge generation from the OS CSPRNG, single-use consumption
(replay protection), freshness/expiry enforcement, and the sign-count
clone-detection state machine —
challenge - Storage-free credential record + browser wire DTOs —
credential
§Quick start
use webauthn_kit::{
SignCountPolicy, SignCountVerdict, check_sign_count, classify_sign_count,
verify_authentication, verify_registration, AttestationPolicy,
AuthenticationParams, ChallengeStore, CredentialPolicy, UserVerificationPolicy,
WebauthnConfig,
};
let config = WebauthnConfig {
rp_id: "example.com".into(),
rp_name: "Example".into(),
rp_origins: vec!["https://example.com".into()],
allowed_algorithms: vec![-7, -35, -257], // ES256, ES384, RS256
challenge_timeout_secs: 300,
attestation: AttestationPolicy::default(),
// Server-side enforcement: UV required, synced passkeys rejected.
credential_policy: CredentialPolicy {
user_verification: UserVerificationPolicy::Required,
..CredentialPolicy::default()
},
resident_key: Default::default(),
attestation_conveyance: Default::default(),
};
// 1. Issue a challenge (single-use; store the (id, bytes) pair).
let store = ChallengeStore::new();
let (challenge_b64, create_options) =
store.generate_registration_challenge(&config, "alice", "Alice", &[]);
// ... send `create_options` to the browser, receive RegistrationResponse ...
// 2. Verify a registration response (see tests/vectors.rs for a full
// roundtrip with a synthetic keypair).
// let result = verify_registration(&challenge, &client_data_json_b64,
// &attestation_object_b64, "", &config.rp_id, &config.rp_origins,
// &config.attestation)?;
// 3. Verify an assertion; persist result.new_sign_count afterwards.
// let result = verify_authentication(&AuthenticationParams { ... })?;§Storage contract (what this crate does NOT do)
This crate is deliberately storage-free. The integrator owns:
- Credential persistence: after
verify_registrationsucceeds, store acredential::WebauthnCredential(credential ID, COSE public key, sign count, timestamps). After each successfulverify_authentication, atomically persistcredential::AuthenticationResult::new_sign_count. - Challenge durability:
ChallengeStoreholds pending challenges in memory; they are lost on restart (users simply retry). Keep the consume-then-verify ordering so restarts can never enable replays. - User mapping and session issuance (cookies, JWTs, …).
- UI / HTTP layer: the
credentialDTOs serialize with theserdefeature but no HTTP types are included.
§Security notes
#![forbid(unsafe_code)]; all cryptography viaring.- Every parser accepts hostile input and returns
Errinstead of panicking (property/fuzz-tested intests/fuzz.rs). - Challenge bytes are 32 bytes from the OS CSPRNG; consumption is single-use and freshness-bounded.
- Attestation is verified for
none,packed, andfido-u2f; unknown formats are rejected unless theAttestationPolicy::allow_unknown_formatsescape hatch is set (trust-weakening). Provenance claims are bounded by the configured trust anchors: with none configured, unanchored certificate chains are accepted but flagged (TrustLevel::BasicAtt+ warning) and must be treated as self-attested. OnlyTrustLevel::AttCaattests device provenance. Other formats (android-key,tpm, …) are tranche-2 work — seeattestation. - Supported algorithms: ES256 (COSE −7), ES384 (COSE −35), EdDSA
(Ed25519, COSE −8), and RS256 (COSE −257). Curve/algorithm bindings are
enforced at parse time (a P-256 key claiming ES384 is rejected); other
algorithms are rejected with
WebauthnError::UnsupportedAlgorithm. - Sign-count policy: a stored counter of 0 disables the check (authenticators without counters); otherwise a strictly decreasing counter is rejected. Equal counters are allowed by design.
- User verification (
policy::UserVerificationPolicy):Requiredis enforced server-side — ceremonies whose authenticator UV flag is clear fail withWebauthnError::UserVerificationRequired. The default (Preferred) reports the flag without rejecting, preserving per-caller policy decisions. - Multi-device credentials (
policy::BackupPolicy): the BE/BS flags are parsed from signed authenticator data and reported on both ceremony results;BackupPolicy::RequireDeviceBoundrejects syncable (BE=1) credentials. See the policy module docs for account-recovery implications before allowing synced passkeys on sensitive flows.
Re-exports§
pub use aaguid::known_aaguid;pub use attestation::verify_attestation;pub use attestation::AttestationFormat;pub use attestation::AttestationPolicy;pub use attestation::AttestationResult;pub use attestation::TrustLevel;pub use challenge::check_sign_count;pub use challenge::classify_sign_count;pub use challenge::ChallengeStore;pub use challenge::DeferredSignCountUpdate;pub use challenge::OnRegression;pub use challenge::SignCountPolicy;pub use challenge::SignCountVerdict;pub use config::WebauthnConfig;pub use credential::AllowCredential;pub use credential::AuthenticationOptions;pub use credential::AuthenticationResponse;pub use credential::AuthenticationResult;pub use credential::AuthenticatorSelection;pub use credential::ExcludeCredential;pub use credential::PubKeyCredParam;pub use credential::RegistrationOptions;pub use credential::RegistrationResponse;pub use credential::RegistrationResult;pub use credential::RelyingParty;pub use credential::WebauthnCredential;pub use credential::WebauthnUser;pub use crypto::alg_to_name;pub use crypto::base64_decode_urlsafe;pub use crypto::base64_encode_urlsafe;pub use crypto::cbor_bytes;pub use crypto::cbor_map_entries;pub use crypto::generate_challenge_bytes;pub use crypto::parse_cose_key;pub use crypto::verify_cose_signature;pub use crypto::CosePublicKey;pub use crypto::COSE_ALG_EDDSA;pub use crypto::COSE_ALG_ES256;pub use crypto::COSE_ALG_ES384;pub use crypto::COSE_ALG_RS256;pub use crypto::COSE_CRV_ED25519;pub use crypto::COSE_CRV_P384;pub use crypto::COSE_KTY_EC2;pub use crypto::COSE_KTY_OKP;pub use crypto::COSE_KTY_RSA;pub use error::WebauthnError;pub use policy::AttestationConveyance;pub use policy::BackupPolicy;pub use policy::CredentialPolicy;pub use policy::ResidentKeyPolicy;pub use policy::UserVerificationPolicy;pub use protocol::verify_authentication;pub use protocol::verify_registration;pub use protocol::AuthenticationParams;pub use ciborium;
Modules§
- aaguid
- Well-known authenticator AAGUIDs (informational registry).
- attestation
- Attestation statement parsing and verification (WebAuthn Level 2 §8).
- challenge
- Challenge generation, single-use consumption (replay protection), freshness/expiry enforcement, and the sign-count clone-detection state machine.
- config
- Relying-party configuration.
- credential
WebAuthncredential descriptor and protocol DTOs (options, responses, results).- crypto
- COSE key parsing and signature verification (ES256 / ES384 / RS256 /
EdDSA) via
ring, plus base64url helpers and CSPRNG challenge generation. - error
- Error type for all
webauthn-kitoperations. - policy
- Caller-enforceable credential policies for the registration and authentication ceremonies.
- protocol
- CTAP2 protocol parsing and ceremony verification.