Crate webauthn_rp

Source
Expand description

gitcrates-iodocs-rs

webauthn_rp is a library for server-side Web Authentication (WebAuthn) Relying Party (RP) operations.

The purpose of a server-side RP library is to be modular so that any client can be used with it as a backend including native applications—WebAuthn technically only covers web applications; however it’s relatively easy to adapt to native applications as well. It achieves this by not assuming how data is sent to/from the client; having said that, there are pre-defined serialization formats for “common” deployments which can be used when serde is enabled.

§Cargo “features”

custom or both bin and serde must be enabled; otherwise a compile_error will occur.

§bin

Enables binary (de)serialization via Encode and Decode. Since registered credentials will almost always have to be saved to persistent storage, some form of (de)serialization is necessary. In the event bin is unsuitable or only partially suitable (e.g., human-readable output is desired), one will need to enable custom to allow construction of certain types (e.g., AuthenticatedCredential).

If possible and desired, one may wish to save the data “directly” to avoid any potential temporary allocations. For example StaticState::encode will return a Vec containing hundreds (and possibly thousands in the extreme case) of bytes if the underlying public key is an RSA key. This additional allocation and copy of data is obviously avoided if StaticState is stored as a composite type or its fields are stored in separate columns when written to a relational database (RDB).

§custom

Exposes functions (e.g., AuthenticatedCredential::new) that allows one to construct instances of types that cannot be constructed when bin or serde is not enabled.

§serde

Enables (de)serialization of data sent to/from the client via serde based on the JSON-motivated definitions (e.g., RegistrationResponseJSON). Since data has to be sent to/from the client, some form of (de)serialization is necessary. In the event serde is unsuitable or only partially suitable, one will need to enable custom to allow construction of certain types (e.g., Registration).

Code is strongly encouraged to rely on the Deserialize implementations as much as possible to reduce the chances of improperly deserializing the client data.

Note that clients are free to send data in whatever form works best, so there is no requirement the JSON-motivated definitions are used even when JSON is sent. This is especially relevant since the JSON-motivated definitions were only added in WebAuthn Level 3; thus many deployments only partially conform. Some specific deviations that may require partial customization of deserialization are the following:

  • ArrayBuffers encoded using something other than base64url.
  • ArrayBuffers that are encoded multiple times (including the use of different encodings each time).
  • Missing fields (e.g., transports).
  • Different field names (e.g., extensions instead of clientExtensionResults).

§serde_relaxed

Automatically enables serde in addition to “relaxed” Deserialize implementations (e.g., RegistrationRelaxed). Roughly “relaxed” translates to unknown fields being ignored and only the fields necessary for construction of the type are required. Case still matters, duplicate fields are still forbidden, and interrelated data validation is still performed when applicable. This can be useful when one wants to accommodate non-conforming clients or clients that implement older versions of the spec.

§serializable_server_state

Automatically enables bin in addition to Encode and Decode implementations for RegistrationServerState and AuthenticationServerState. Less accurate SystemTime is used instead of Instant for timeout enforcement. This should be enabled if you don’t desire to use in-memory collections to store the instances of those types.

Note even when written to persistent storage, an application should still periodically remove expired ceremonies. If one is using a relational database (RDB); then one can achieve this by storing ServerState::sent_challenge, the Vec returned from Encode::encode, and ServerState::expiration and periodically remove all rows whose expiration exceeds the current date and time.

§Registration and authentication

Both registration and authentication ceremonies rely on “challenges”, and these challenges are inherently temporary. For this reason the data associated with challenge completion can often be stored in memory without concern for out-of-memory (OOM) conditions. There are several benefits to storing such data in memory:

  • No data manipulation
    • By leveraging move semantics, the data sent to the client cannot be mutated once the ceremony begins.
  • Improved timeout enforcement
    • By ensuring the same machine that started the ceremony is also used to finish the ceremony, deviation of system clocks is not a concern. Additionally, allowing serialization requires the use of some form of cross-platform “timestamp” (e.g., Unix time) which differ in implementation (e.g., platforms implement leap seconds in different ways) and are often not monotonically increasing. If data resides in memory, a monotonic Instant can be used instead.

It is for those reasons data like RegistrationServerState are not serializable by default and require the use of in-memory collections (e.g., FixedCapHashSet). To better ensure OOM is not a concern, RPs should set reasonable timeouts. Since ceremonies can only be completed by moving data (e.g., RegistrationServerState::verify), ceremony completion is guaranteed to free up the memory used— RegistrationServerState instances are only 48 bytes on x86_64-unknown-linux-gnu platforms. To avoid issues related to incomplete ceremonies, RPs can periodically iterate the collection for expired ceremonies and remove such data. Other techniques can be employed as well to mitigate OOM, but they are application specific and out-of-scope. If this is undesirable, one can enable serializable_server_state so that RegistrationServerState and AuthenticationServerState implement Encode and Decode. Another reason one may need to store this information persistently is for load-balancing purposes where the server that started the ceremony is not guaranteed to be the server that finishes the ceremony.

§Supported signature algorithms

The only supported signature algorithms are the following:

§Correctness of code

This library more strictly adheres to the spec than many other similar libraries including but not limited to the following ways:

Unfortunately like almost all software, this library has not been formally verified; however great care is employed in the following ways:

  • Leverage move semantics to prevent mutation of data once in a static state.
  • Ensure a great many invariants via types.
  • Reduce code duplication.
  • Reduce variable mutation allowing for simpler algebraic reasoning.
  • panic-free code1 (i.e., define true/total functions).
  • Ensure arithmetic “side effects” don’t occur (e.g., overflow).
  • Aggressive use of compiler and Clippy lints.
  • Unit tests for common cases, edge cases, and error cases.

§Cryptographic libraries

This library does not rely on any sensitive data (e.g., private keys) as only signature verification is ever performed. This means that the only thing that matters with the libraries used is their algorithmic correctness and not other normally essential aspects like susceptibility to side-channel attacks. While I personally believe the libraries that are used are at least as “secure” as alternatives even when dealing with sensitive data, one only needs to audit the correctness of the libraries to be confident in their use. In fact curve25519_dalek has been formally verified when the fiat backend is used making it objectively better than many other libraries whose correctness has not been proven. Two additional benefits of the library choices are simpler APIs making it more likely their use is correct and better cross-platform compatibility.


  1. panics related to memory allocations or stack overflow are possible since such issues are not formally guarded against. 

Modules§

  • binbin
    Contains functionality to (de)serialize data to a data store.
  • Functionality for starting ceremonies.
  • Functionality for completing ceremonies.

Structs§

Enums§