1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Safety: This library handles security-critical operations. Unsafe code
// is forbidden to eliminate entire classes of memory safety vulnerabilities.
// All cryptographic operations are delegated to the `ring` crate which
// manages its own unsafe code behind a safe API.
// Security libraries must not panic on any input — a panic in a security
// check aborts the ceremony rather than returning a typed error, potentially
// allowing callers to misinterpret the outcome. Use ? and explicit error
// variants everywhere; reserve .expect() for invariants guaranteed by the
// surrounding bounds checks (e.g. try_into() on a slice whose length was
// just verified). .unwrap() is unconditionally forbidden in library code.
//! # webauthn — WebAuthn relying-party library
//!
//! Server-side (relying party) verification for the two core WebAuthn ceremonies:
//!
//! - **Registration** (`navigator.credentials.create`) — the authenticator generates
//! a public/private keypair. The relying party verifies the attestation and stores
//! the public key and credential ID.
//! - **Authentication** (`navigator.credentials.get`) — the authenticator signs a
//! challenge with the stored private key. The relying party verifies the signature
//! and sign count.
//!
//! ## Quick start
//!
//! ```rust,no_run
//! use webauthn::{
//! AuthenticatorAssertionResponse, AuthenticatorAttestationResponse,
//! Challenge, RelyingParty,
//! };
//!
//! // Configure the relying party once at startup.
//! let rp = RelyingParty::new("example.com", "https://example.com", "My Service");
//!
//! // ── Registration ──────────────────────────────────────────────────────────
//!
//! // Issue a challenge, send it to the browser, receive the attestation response.
//! let reg_challenge = Challenge::new().expect("RNG failure");
//! # let reg_response = AuthenticatorAttestationResponse {
//! # client_data_json: vec![],
//! # attestation_object: vec![],
//! # };
//!
//! // Verify the registration and persist the returned credential.
//! let reg_result = rp
//! .verify_registration(®_challenge, ®_response, b"user-id-42")
//! .expect("registration failed");
//! let stored_credential = reg_result.credential;
//!
//! // ── Authentication ────────────────────────────────────────────────────────
//!
//! // Issue a new challenge, send it to the browser, receive the assertion response.
//! let auth_challenge = Challenge::new().expect("RNG failure");
//! # let auth_response = AuthenticatorAssertionResponse {
//! # client_data_json: vec![],
//! # authenticator_data: vec![],
//! # signature: vec![],
//! # user_handle: None,
//! # };
//!
//! // Verify the assertion and update the stored sign count.
//! let auth_result = rp
//! .verify_authentication(&stored_credential, &auth_challenge, &auth_response)
//! .expect("authentication failed");
//! // Persist auth_result.new_sign_count to your database.
//! ```
//!
//! ## Supported algorithms
//!
//! | Algorithm | COSE ID | Description |
//! |-----------|---------|-------------|
//! | ES256 | `-7` | ECDSA P-256 with SHA-256 — recommended, most common |
//! | ES384 | `-35` | ECDSA P-384 with SHA-384 |
//! | EdDSA | `-8` | Ed25519 — newer FIDO2 authenticators |
//! | RS256 | `-257` | RSA PKCS#1 v1.5 with SHA-256 — legacy YubiKey 4, Windows Hello |
//!
//! See the [COSE algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml)
//! for the full list of identifiers.
//!
//! ## Security properties
//!
//! - **No unsafe code** — `#![forbid(unsafe_code)]` is enforced at compile time.
//! All cryptographic operations are delegated to [`ring`], which descends from
//! BoringSSL and manages its own unsafe code behind a safe API boundary.
//! - **No panics** — `#![deny(clippy::unwrap_used)]` prevents `.unwrap()` in library
//! code. Every error path returns a typed [`WebAuthnError`] variant.
//! - **No custom crypto** — signature verification, hashing, and random number
//! generation are all inside `ring`'s audited boundary.
//! - **Caller responsibilities** — credential uniqueness checks and FIDO
//! Metadata Service integration are out of scope. Challenge single-use
//! enforcement is opt-in via
//! [`RelyingParty::enforce_single_use_challenges`].
//!
//! > **Learning project** — this library is a portfolio demonstration of a correct
//! > WebAuthn implementation. For production use, consider
//! > [`webauthn-rs`](https://crates.io/crates/webauthn-rs), which includes FIDO MDS
//! > integration and a broader attestation format set.
//!
//! ## Features
//!
//! | Feature | Default | Description |
//! |---------|---------|-------------|
//! | `serde` | off | Derives [`serde::Serialize`] and [`serde::Deserialize`] on [`Credential`], [`PublicKey`], [`Challenge`], [`RegistrationResult`], [`AuthenticationResult`], [`AttestationType`], and [`WebAuthnError`]. `Vec<u8>` fields are encoded as compact byte sequences via [`serde_bytes`](https://docs.rs/serde_bytes) rather than arrays of integers. Enable with `features = ["serde"]` in `Cargo.toml`. |
//!
//! Note: `serde` and `serde_json` are unconditional dependencies used internally
//! for `clientDataJSON` parsing. The `serde` feature only controls whether the
//! public-facing types implement `Serialize`/`Deserialize`.
//!
//! ## Spec references
//!
//! - [W3C WebAuthn Level 2](https://www.w3.org/TR/webauthn-2/)
//! - [FIDO Alliance specifications](https://fidoalliance.org/specifications/)
//! - [RFC 8152 — COSE](https://www.rfc-editor.org/rfc/rfc8152)
// Internal modules
// ─── Public re-exports ────────────────────────────────────────────────────────
pub use ;
pub use AuthenticatorAssertionResponse;
pub use ;
pub use ;
pub use ;
pub use ;
pub use RelyingParty;