webauthn_rp

Crates.iowebauthn_rp
lib.rswebauthn_rp
version
sourcesrc
created_at2023-12-29 18:56:39.866901
updated_at2024-12-07 17:18:48.194392
descriptionServer-side Web Authentication (WebAuthn) Relying Party (RP) API.
homepage
repositoryhttps://git.philomathiclife.com/repos/webauthn_rp/
max_upload_size
id1083560
Cargo.toml error:TOML parse error at line 19, column 1 | 19 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include`
size0
philomathic_life (zacknewman)

documentation

https://docs.rs/webauthn_rp/latest/webauthn_rp/

README

webauthn_rp

git crates.io docs.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:

  • Ed25519 as defined in RFC 8032 § 5.1. This corresponds to CoseAlgorithmIdentifier::Eddsa.
  • ECDSA as defined in SEC 1 Version 2.0 § 4.1 using SHA-256 as the hash function and NIST P-256 as defined in NIST SP 800-186 § 3.2.1.3 for the underlying elliptic curve. This corresponds to CoseAlgorithmIdentifier::Es256.
  • 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 NIST SP 800-186 § 3.2.1.4 for the underlying elliptic curve. This corresponds to CoseAlgorithmIdentifier::Es384.
  • RSASSA-PKCS1-v1_5 as defined in RFC 8017 § 8.2 using SHA-256 as the hash function. This corresponds to CoseAlgorithmIdentifier::Rs256.

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.

Minimum Supported Rust Version (MSRV)

This will frequently be updated to be the same as stable. Specifically, any time stable is updated and that update has "useful" features or compilation no longer succeeds (e.g., due to new compiler lints), then MSRV will be updated.

MSRV changes will correspond to a SemVer patch version bump pre-1.0.0; otherwise a minor version bump.

SemVer Policy

  • All on-by-default features of this library are covered by SemVer
  • MSRV is considered exempt from SemVer as noted above

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Before any PR is sent, cargo clippy and cargo t should be run for each possible combination of "features" using stable Rust. One easy way to achieve this is by building ci and invoking it with no commands in the webauthn_rp directory or sub-directories. You can fetch ci via git clone https://git.philomathiclife.com/repos/ci, and it can be built with cargo build --release. Additionally, RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features should be run to ensure documentation can be built.

Status

This package is actively maintained and will conform to the latest WebAuthn API version. Previous versions will not be supported—excluding bug fixes of course—however functionality will exist to facilitate the migration process from the previous version.

The crate is only tested on x86_64-unknown-linux-gnu and x86_64-unknown-openbsd targets, but it should work on most platforms.

Footnotes

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

Commit count: 0

cargo fmt