README.md (13788B)
1 # `webauthn_rp` 2 3 [<img alt="git" src="https://git.philomathiclife.com/badges/webauthn_rp.svg" height="20">](https://git.philomathiclife.com/webauthn_rp/log.html) 4 [<img alt="crates.io" src="https://img.shields.io/crates/v/webauthn_rp.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/webauthn_rp) 5 [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-webauthn_rp-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/webauthn_rp/latest/webauthn_rp/) 6 7 `webauthn_rp` is a library for _server-side_ 8 [Web Authentication (WebAuthn)](https://www.w3.org/TR/webauthn-3/#sctn-rp-operations) Relying Party 9 (RP) operations. 10 11 The purpose of a server-side RP library is to be modular so that any client can be used with it as a backend 12 _including_ native applications—WebAuthn technically only covers web applications; however it's relatively easy 13 to adapt to native applications as well. It achieves this by not assuming how data is sent to/from the client; 14 having said that, there are pre-defined serialization formats for "common" deployments which can be used when 15 [`serde`](#serde) is enabled. 16 17 ## Cargo "features" 18 19 [`custom`](#custom) or both [`bin`](#bin) and [`serde`](#serde) must be enabled; otherwise a `compile_error` 20 will occur. 21 22 ### `bin` 23 24 Enables binary (de)serialization via `Encode` and `Decode`. Since registered credentials will almost always 25 have to be saved to persistent storage, _some_ form of (de)serialization is necessary. In the event `bin` is 26 unsuitable or only partially suitable (e.g., human-readable output is desired), one will need to enable 27 [`custom`](#custom) to allow construction of certain types (e.g., `AuthenticatedCredential`). 28 29 If possible and desired, one may wish to save the data "directly" to avoid any potential temporary allocations. 30 For example `StaticState::encode` will return a `Vec` containing hundreds (and possibly thousands in the 31 extreme case) of bytes if the underlying public key is an RSA key. This additional allocation and copy of data 32 is obviously avoided if `StaticState` is stored as a 33 [composite type](https://www.postgresql.org/docs/current/rowtypes.html) or its fields are stored in separate 34 columns when written to a relational database (RDB). 35 36 ### `custom` 37 38 Exposes functions (e.g., `AuthenticatedCredential::new`) that allows one to construct instances of types that 39 cannot be constructed when [`bin`](#bin) or [`serde`](#serde) is not enabled. 40 41 ### `serde` 42 43 This feature _strictly_ adheres to the JSON-motivated definitions. You _will_ encounter clients that send data that 44 cannot be deserialized using this feature. For many [`serde_relaxed`](#serde_relaxed) should be used instead. 45 46 Enables (de)serialization of data sent to/from the client via [`serde`](https://docs.rs/serde/latest/serde/) 47 based on the JSON-motivated definitions (e.g., 48 [`RegistrationResponseJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-registrationresponsejson)). Since 49 data has to be sent to/from the client, _some_ form of (de)serialization is necessary. In the event `serde` 50 is unsuitable or only partially suitable, one will need to enable [`custom`](#custom) to allow construction 51 of certain types (e.g., `Registration`). 52 53 Code is _strongly_ encouraged to rely on the `Deserialize` implementations as much as possible to reduce the 54 chances of improperly deserializing the client data. 55 56 Note that clients are free to send data in whatever form works best, so there is no requirement the 57 JSON-motivated definitions are used even when JSON is sent. This is especially relevant since the JSON-motivated 58 definitions were only added in [WebAuthn Level 3](https://www.w3.org/TR/webauthn-3/); thus many deployments only 59 partially conform. Some specific deviations that may require partial customization of deserialization are the 60 following: 61 62 * [`ArrayBuffer`](https://webidl.spec.whatwg.org/#idl-ArrayBuffer)s encoded using something other than 63 base64url. 64 * `ArrayBuffer`s that are encoded multiple times (including the use of different encodings each time). 65 * Missing fields (e.g., 66 [`transports`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-transports)). 67 * Different field names (e.g., `extensions` instead of 68 [`clientExtensionResults`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-clientextensionresults)). 69 70 ### `serde_relaxed` 71 72 Automatically enables [`serde`](#serde) in addition to "relaxed" `Deserialize` implementations 73 (e.g., `RegistrationRelaxed`). Roughly "relaxed" translates to unknown fields being ignored and only 74 the fields necessary for construction of the type are required. Case still matters, duplicate fields are still 75 forbidden, and interrelated data validation is still performed when applicable. This can be useful when one 76 wants to accommodate non-conforming clients or clients that implement older versions of the spec. 77 78 ### `serializable_server_state` 79 80 Automatically enables [`bin`](#bin) in addition to `Encode` and `Decode` implementations for 81 `RegistrationServerState` and `AuthenticationServerState`. Less accurate `SystemTime` is used instead of 82 `Instant` for timeout enforcement. This should be enabled if you don't desire to use in-memory collections to 83 store the instances of those types. 84 85 Note even when written to persistent storage, an application should still periodically remove expired ceremonies. 86 If one is using a relational database (RDB); then one can achieve this by storing `ServerState::sent_challenge`, 87 the `Vec` returned from `Encode::encode`, and `ServerState::expiration` and periodically remove all rows 88 whose expiration exceeds the current date and time. 89 90 ## Registration and authentication 91 92 Both [registration](https://www.w3.org/TR/webauthn-3/#registration-ceremony) and 93 [authentication](https://www.w3.org/TR/webauthn-3/#authentication-ceremony) ceremonies rely on "challenges", and 94 these challenges are inherently temporary. For this reason the data associated with challenge completion can 95 often be stored in memory without concern for out-of-memory (OOM) conditions. There are several benefits to 96 storing such data in memory: 97 98 * No data manipulation 99 * By leveraging move semantics, the data sent to the client cannot be mutated once the ceremony begins. 100 * Improved timeout enforcement 101 * By ensuring the same machine that started the ceremony is also used to finish the ceremony, deviation of 102 system clocks is not a concern. Additionally, allowing serialization requires the use of some form of 103 cross-platform "timestamp" (e.g., [Unix time](https://en.wikipedia.org/wiki/Unix_time)) which differ in 104 implementation (e.g., platforms implement leap seconds in different ways) and are often not monotonically 105 increasing. If data resides in memory, a monotonic `Instant` can be used instead. 106 107 It is for those reasons data like `RegistrationServerState` are not serializable by default and require the 108 use of in-memory collections (e.g., `FixedCapHashSet`). To better ensure OOM is not a concern, RPs should set 109 reasonable timeouts. Since ceremonies can only be completed by moving data (e.g., 110 `RegistrationServerState::verify`), ceremony completion is guaranteed to free up the memory used— 111 `RegistrationServerState` instances are only 48 bytes on `x86_64-unknown-linux-gnu` platforms. To avoid issues 112 related to incomplete ceremonies, RPs can periodically iterate the collection for expired ceremonies and remove 113 such data. Other techniques can be employed as well to mitigate OOM, but they are application specific and 114 out-of-scope. If this is undesirable, one can enable [`serializable_server_state`](#serializable_server_state) 115 so that `RegistrationServerState` and `AuthenticationServerState` implement `Encode` and `Decode`. Another 116 reason one may need to store this information persistently is for load-balancing purposes where the server that 117 started the ceremony is not guaranteed to be the server that finishes the ceremony. 118 119 ## Supported signature algorithms 120 121 The only supported signature algorithms are the following: 122 123 * Ed25519 as defined in [RFC 8032 § 5.1](https://www.rfc-editor.org/rfc/rfc8032#section-5.1). This corresponds 124 to `CoseAlgorithmIdentifier::Eddsa`. 125 * ECDSA as defined in [SEC 1 Version 2.0 § 4.1](https://www.secg.org/sec1-v2.pdf#subsection.4.1) using SHA-256 126 as the hash function and NIST P-256 as defined in 127 [NIST SP 800-186 § 3.2.1.3](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf#%5B%7B%22num%22%3A229%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C70%2C275%2C0%5D) 128 for the underlying elliptic curve. This corresponds to `CoseAlgorithmIdentifier::Es256`. 129 * ECDSA as defined in SEC 1 Version 2.0 § 4.1 using SHA-384 as the hash function and NIST P-384 as defined in 130 [NIST SP 800-186 § 3.2.1.4](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf#%5B%7B%22num%22%3A232%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C70%2C264%2C0%5D) 131 for the underlying elliptic curve. This corresponds to `CoseAlgorithmIdentifier::Es384`. 132 * RSASSA-PKCS1-v1_5 as defined in [RFC 8017 § 8.2](https://www.rfc-editor.org/rfc/rfc8017#section-8.2) using 133 SHA-256 as the hash function. This corresponds to `CoseAlgorithmIdentifier::Rs256`. 134 135 ## Correctness of code 136 137 This library more strictly adheres to the spec than many other similar libraries including but not limited to 138 the following ways: 139 140 * [CTAP2 canonical CBOR encoding form](https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#ctap2-canonical-cbor-encoding-form). 141 * `Deserialize` implementations requiring _exact_ conformance (e.g., not allowing unknown data). 142 * More thorough interrelated data validation (e.g., all places a Credential ID exists must match). 143 * Implement a lot of recommended (i.e., SHOULD) criteria (e.g., 144 [User display names conforming to the Nickname Profile as defined in RFC 8266](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialentity-name)). 145 146 Unfortunately like almost all software, this library has not been formally verified; however great care is 147 employed in the following ways: 148 149 * Leverage move semantics to prevent mutation of data once in a static state. 150 * Ensure a great many invariants via types. 151 * Reduce code duplication. 152 * Reduce variable mutation allowing for simpler algebraic reasoning. 153 * `panic`-free code[^note] (i.e., define true/total functions). 154 * Ensure arithmetic "side effects" don't occur (e.g., overflow). 155 * Aggressive use of compiler and [Clippy](https://doc.rust-lang.org/stable/clippy/lints.html) lints. 156 * Unit tests for common cases, edge cases, and error cases. 157 158 ## Cryptographic libraries 159 160 This library does not rely on _any_ sensitive data (e.g., private keys) as only signature verification is 161 ever performed. This means that the only thing that matters with the libraries used is their algorithmic 162 correctness and not other normally essential aspects like susceptibility to side-channel attacks. While I 163 personally believe the libraries that are used are at least as "secure" as alternatives even when dealing with 164 sensitive data, one only needs to audit the correctness of the libraries to be confident in their use. In fact 165 [`curve25519_dalek`](https://docs.rs/curve25519-dalek/latest/curve25519_dalek/#backends) has been formally 166 verified when the [`fiat`](https://github.com/mit-plv/fiat-crypto) backend is used making it _objectively_ 167 better than many other libraries whose correctness has not been proven. Two additional benefits of the library 168 choices are simpler APIs making it more likely their use is correct and better cross-platform compatibility. 169 170 ## Minimum Supported Rust Version (MSRV) 171 172 This will frequently be updated to be the same as stable. Specifically, any time stable is updated and that 173 update has "useful" features or compilation no longer succeeds (e.g., due to new compiler lints), then MSRV 174 will be updated. 175 176 MSRV changes will correspond to a SemVer patch version bump pre-`1.0.0`; otherwise a minor version bump. 177 178 ## SemVer Policy 179 180 * All on-by-default features of this library are covered by SemVer 181 * MSRV is considered exempt from SemVer as noted above 182 183 ## License 184 185 Licensed under either of 186 187 * Apache License, Version 2.0 ([LICENSE-APACHE](https://www.apache.org/licenses/LICENSE-2.0)) 188 * MIT license ([LICENSE-MIT](https://opensource.org/licenses/MIT)) 189 190 at your option. 191 192 ## Contribution 193 194 Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, 195 as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. 196 197 Before any PR is sent, `cargo clippy` and `cargo t` should be run _for each possible combination of "features"_ 198 using stable Rust. One easy way to achieve this is by building `ci` and invoking it with no commands in the 199 `webauthn_rp` directory or sub-directories. You can fetch `ci` via `git clone https://git.philomathiclife.com/repos/ci`, 200 and it can be built with `cargo build --release`. Additionally, 201 `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features` should be run to ensure documentation can be built. 202 203 ### Status 204 205 This package is actively maintained and will conform to the 206 [latest WebAuthn API version](https://www.w3.org/TR/webauthn-3/). Previous versions will not be supported—excluding 207 bug fixes of course—however functionality will exist to facilitate the migration process from the previous version. 208 209 The crate is only tested on `x86_64-unknown-linux-gnu` and `x86_64-unknown-openbsd` targets, but it should work 210 on most platforms. 211 212 [^note]: `panic`s related to memory allocations or stack overflow are possible since such issues are not 213 formally guarded against.