Skip to content

Commit

Permalink
Update docs, move to 5.0 dev, and change security key feature property (
Browse files Browse the repository at this point in the history
  • Loading branch information
Firstyear authored Dec 14, 2022
1 parent 72ce003 commit e6912ed
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 33 deletions.
4 changes: 2 additions & 2 deletions fido-mds-tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fido-mds-tool"
version = "0.4.8"
version = "0.5.0-dev"
authors = ["William Brown <william@blackhats.net.au>"]
edition = "2021"
description = "Fido Metadata Service parsing tool"
Expand All @@ -11,7 +11,7 @@ categories = ["authentication", "web-programming"]
license = "MPL-2.0"

[dependencies]
fido-mds = { version = "0.4.6", path = "../fido-mds" }
fido-mds = { version = "0.5.0-dev", path = "../fido-mds" }

clap = { version = "^3.2", features = ["derive", "env"] }

Expand Down
2 changes: 1 addition & 1 deletion fido-mds/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fido-mds"
version = "0.4.8"
version = "0.5.0-dev"
authors = ["William Brown <william@blackhats.net.au>"]
edition = "2021"
description = "Fido Metadata Service parser"
Expand Down
4 changes: 2 additions & 2 deletions webauthn-authenticator-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "webauthn-authenticator-rs"
version = "0.4.9"
version = "0.5.0-dev"
authors = ["William Brown <william@blackhats.net.au>"]
edition = "2021"
license = "MPL-2.0"
Expand All @@ -21,7 +21,7 @@ all-features = true

[dependencies]
base64urlsafedata = { version = "0.1", path = "../base64urlsafedata" }
webauthn-rs-proto = { version = "0.4.8", path = "../webauthn-rs-proto" }
webauthn-rs-proto = { version = "0.5.0-dev", path = "../webauthn-rs-proto" }

tracing = "0.1"
url = "2"
Expand Down
4 changes: 2 additions & 2 deletions webauthn-rs-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "webauthn-rs-core"
version = "0.4.9"
version = "0.5.0-dev"
authors = ["William Brown <william@blackhats.net.au>"]
edition = "2021"
description = "Webauthn Cryptographic Operation Handling"
Expand All @@ -17,7 +17,7 @@ default = []

[dependencies]
base64urlsafedata = { version = "0.1.2", path = "../base64urlsafedata" }
webauthn-rs-proto = { version = "0.4.8", path = "../webauthn-rs-proto" }
webauthn-rs-proto = { version = "0.5.0-dev", path = "../webauthn-rs-proto" }
serde = { version = "1", features = ["derive"] }
serde_cbor = { version = "0.12.0-dev", package = "serde_cbor_2" }
serde_json = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion webauthn-rs-proto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "webauthn-rs-proto"
version = "0.4.9"
version = "0.5.0-dev"
authors = ["William Brown <william@blackhats.net.au>"]
edition = "2021"
description = "Webauthn Specification Bindings"
Expand Down
9 changes: 6 additions & 3 deletions webauthn-rs-proto/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ impl ToString for AuthenticatorTransport {
Internal => "internal",
Test => "test",
Hybrid => "hybrid",
}.to_string()
}
.to_string()
}
}

Expand Down Expand Up @@ -275,7 +276,6 @@ pub struct TokenBinding {
pub id: Option<String>,
}


#[cfg(test)]
mod test {
use std::str::FromStr;
Expand All @@ -294,7 +294,10 @@ mod test {
];

for (s, t) in cases {
assert_eq!(t, AuthenticatorTransport::from_str(s).expect("unknown authenticatorTransport"));
assert_eq!(
t,
AuthenticatorTransport::from_str(s).expect("unknown authenticatorTransport")
);
assert_eq!(s, AuthenticatorTransport::to_string(&t));
}

Expand Down
7 changes: 5 additions & 2 deletions webauthn-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "webauthn-rs"
version = "0.4.9"
version = "0.5.0-dev"
authors = ["William Brown <william@blackhats.net.au>"]
edition = "2021"
description = "Webauthn Framework for Rust Web Servers"
Expand All @@ -10,6 +10,9 @@ keywords = ["webauthn", "authentication"]
categories = ["authentication", "web-programming"]
license = "MPL-2.0"

[package.metadata.docs.rs]
features = ["danger-allow-state-serialisation", "danger-user-presence-only-security-keys", "danger-credential-internals"]

[features]
resident-key-support = []
preview-features = []
Expand All @@ -20,7 +23,7 @@ danger-user-presence-only-security-keys = []

[dependencies]
base64urlsafedata = { version = "0.1", path = "../base64urlsafedata" }
webauthn-rs-core = { version = "0.4.8", path = "../webauthn-rs-core" }
webauthn-rs-core = { version = "0.5.0-dev", path = "../webauthn-rs-core" }
url = { version = "2", features = ["serde"] }
tracing = "0.1"
serde = { version = "1", features = ["derive"] }
Expand Down
37 changes: 30 additions & 7 deletions webauthn-rs/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ pub struct PasskeyAuthentication {
pub(crate) ast: AuthenticationState,
}

/// A Passkey for a user.
/// A Passkey for a user. A passkey is a term that covers all possible authenticators that may exist.
/// These could be roaming credentials such as Apple's Account back passkeys, they could be a users
/// Yubikey, a Windows Hello TPM, or even a password manager softtoken.
///
/// These can be safely serialised and deserialised from a database for use.
/// Passkeys *may* opportunistically have some properties such as discoverability (residence). This
/// is not a guarantee since enforcing residence on devices like yubikeys that have limited storage
/// and no administration of resident keys may break the device.
///
/// These can be safely serialised and deserialised from a database for persistance.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Passkey {
pub(crate) cred: Credential,
Expand All @@ -66,7 +72,7 @@ impl Passkey {
///
/// To determine if this is required, you can inspect the result of
/// `authentication_result.needs_update()`. Counter intuitively, most passkeys
/// will never need their properties updated! This is because passkeys lack an
/// will never need their properties updated! This is because many passkeys lack an
/// internal device activation counter (due to their synchronisation), and the
/// backup-state flags are rarely if ever changed.
///
Expand Down Expand Up @@ -163,7 +169,9 @@ pub struct PasswordlessKeyAuthentication {
pub(crate) ast: AuthenticationState,
}

/// A passwordless key for a user
/// A passwordless key for a user. This is a specialisation of [Passkey] as you can
/// limit the make and models of authenticators that a user may register. Additionally
/// these keys will always enforce userverification.
///
/// These can be safely serialised and deserialised from a database for use.
#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -275,7 +283,9 @@ pub struct SecurityKeyAuthentication {
pub(crate) ast: AuthenticationState,
}

/// A Security Key for a user.
/// A Security Key for a user. These are the legacy "second factor" method of security tokens.
///
/// You should avoid this type in favour of [Passkey] or [PasswordlessKey]
///
/// These can be safely serialised and deserialised from a database for use.
#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -391,7 +401,16 @@ pub struct DeviceKeyAuthentication {
pub(crate) ast: AuthenticationState,
}

/// A device key belonging to a user
/// A device key belonging to a user. These are a specialisation of [PasswordlessKey] where
/// the devices in use can be attested. In addition this type enforces keys to be resident on the
/// authenticator.
///
/// Since most authenticators have very limited key residence support, this should only be used in
/// tightly controlled enterprise environments where you have strict access over the makes and models
/// of keys in use.
///
/// Key residence is *not* a security property. The general reason for the usage of key residence is
/// to allow the device to identify the user in addition to authenticating them.
///
/// These can be safely serialised and deserialised from a database for use.
#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -491,7 +510,11 @@ pub struct DiscoverableAuthentication {
pub(crate) ast: AuthenticationState,
}

/// A key that can be used in discoverable workflows.
/// A key that can be used in discoverable workflows. Within this library [Passkey]s may be
/// discoverable on an opportunistic bases, and [DeviceKey]s will always be discoverable.
///
/// Generally this is used as part of conditional ui which allows autofill of discovered
/// credentials in username fields.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg(feature = "preview-features")]
pub struct DiscoverableKey {
Expand Down
51 changes: 38 additions & 13 deletions webauthn-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
//!
//! # Getting started
//!
//! In the simplest case where you just want a password replacement, you should use our passkey flow.
//! In the simplest case where you just want to replace passwords with strong self contained multifactor
//! authentication, you should use our passkey flow.
//!
//! ```
//! use webauthn_rs::prelude::*;
Expand All @@ -40,39 +41,41 @@
//! After this point you then need to use `finish_passkey_registration`, followed by
//! `start_passkey_authentication` and `finish_passkey_authentication`
//!
//! No other authentication factors are needed!
//! No other authentication factors are needed! A passkey combines inbuilt user verification (pin, biometrics, etc)
//! with a hardware cryptographic authenticator.
//!
//! # Tutorial
//!
//! A tutorial on how to use this library is on the project github <https://github.com/kanidm/webauthn-rs/tree/master/tutorial>
//! Tutorials and examples on how to use this library in your website project is on the project github <https://github.com/kanidm/webauthn-rs/tree/master/tutorial>
//!
//! # Features
//!
//! This library supports some optional features that you may wish to use. These are all
//! disabled by default as they have risks associated that you need to be aware of as an
//! authentication provider.
//!
//! ## Allow Serialising Registration and Authentication State
//!
//! During a webauthn registration or authentication ceremony, a random challenge is produced and
//! provided to the client. The full content of what is needed for the server to validate this
//! challenge is stored in the associated registration or authentication state types. This value
//! *MUST* be persisted on the server. If you store this in a cookie or some other form of client
//! side stored value, the client can replay a previous authentication state and signature without
//! possession of, or interaction with the authenticator, bypassing pretty much all of the guarantees
//! possession of, or interaction with the authenticator, bypassing pretty much all of the security guarantees
//! of webauthn. Because of this risk by default these states are *not* allowed to be serialised
//! which prevents them from accidentally being placed into a cookie.
//!
//! However there are some *safe* cases of serialising these values. This includes serialising to
//! a database, or using a cookie "memory store" where the client side cookie is a key into a server-side
//! map or similar. Both of these prevent the replay attack threat.
//! map or similar. Any of these prevent the replay attack threat.
//!
//! An alternate but "less good" method to mitigate replay attacks is to associate a very short
//! expiry window to the cookie if you need full client side state, but this may still allow some
//! forms of real time replay attacks to occur.
//! forms of real time replay attacks to occur. We do not recommend this.
//!
//! Enabling the feature `danger-allow-state-serialisation` allows you to re-enable serialisation
//! of these types, provided you accept and understand the handling risks associated.
//!
//! This library supports some optional features that you may wish to use. These are all
//! disabled by default as they have risks associated.
//!
//! ## Allow Insecure RSA_SHA1
//!
//! Many Windows Hello credentials are signed with RSA and SHA1. SHA1 is considered broken
Expand All @@ -82,9 +85,12 @@
//! trust the integrity of the authenticator.
//!
//! For the broadest compatibility, and if you do not use attestation (such as passkey only users)
//! you may choose to use RSA SHA1 signed credentials with `danger-insecure-rs1` as this has no impact
//! on your system security. For users who use attestation, you should NOT enable this feature as it
//! undermines attestation.
//! then you do not need to enable this feature since attestation is not requested.
//!
//! If you require attestation of authenticators,
//! you may choose to use RSA SHA1 attestation signed credentials with `danger-insecure-rs1`.
//!
//! If in doubt, do not enable this feature.
//!
//! ## Credential Internals and Type Changes
//!
Expand All @@ -95,6 +101,10 @@
//! [Credential] type via Into and From by enabling the feature `danger-credential-internals`. The
//! [Credential] type is exposed via the [prelude] when this feature is enabled.
//!
//! However, you should be aware that manipulating the internals of a [Credential] may affect the usage
//! of that [Credential] in certain use cases. You should be careful when enabling this feature that
//! you do not change [Credential] values.
//!
//! ## User-Presence only SecurityKeys
//!
//! By default, SecurityKeys will opportunistically enforce User Verification (Such as a PIN or
Expand All @@ -110,6 +120,7 @@
//! unreliable and not verified correctly. In these cases you MUST communicate to the user that
//! the UV *may* occur on registration and then will not occur again, and that is *by design*.
//!
//! If in doubt, do not enable this feature.

#![deny(warnings)]
#![warn(unused_extern_crates)]
Expand Down Expand Up @@ -166,6 +177,7 @@ pub struct WebauthnBuilder<'a> {
allow_subdomains: bool,
allow_any_port: bool,
algorithms: Vec<COSEAlgorithm>,
user_presence_only_security_keys: bool,
}

impl<'a> WebauthnBuilder<'a> {
Expand Down Expand Up @@ -220,6 +232,7 @@ impl<'a> WebauthnBuilder<'a> {
allow_subdomains: false,
allow_any_port: false,
algorithms: COSEAlgorithm::secure_algs(),
user_presence_only_security_keys: false,
})
} else {
error!("rp_id is not an effective_domain of rp_origin");
Expand Down Expand Up @@ -262,6 +275,16 @@ impl<'a> WebauthnBuilder<'a> {
self
}

/// Enable security keys to only require user presence, rather than enforcing
/// their user-verification state.
///
/// *requires feature danger-user-presence-only-security-keys*
#[cfg(feature = "danger-user-presence-only-security-keys")]
pub fn danger_set_user_presence_only_security_keys(mut self, enable: bool) -> Self {
self.user_presence_only_security_keys = enable;
self
}

/// Complete the construction of the [Webauthn] instance. If an invalid configuration setting
/// is found, an Error may be returned.
///
Expand Down Expand Up @@ -289,6 +312,7 @@ impl<'a> WebauthnBuilder<'a> {
Some(self.allow_any_port),
),
algorithms: self.algorithms,
user_presence_only_security_keys: self.user_presence_only_security_keys,
})
}
}
Expand Down Expand Up @@ -332,6 +356,7 @@ impl<'a> WebauthnBuilder<'a> {
pub struct Webauthn {
core: WebauthnCore,
algorithms: Vec<COSEAlgorithm>,
user_presence_only_security_keys: bool,
}

impl Webauthn {
Expand Down Expand Up @@ -658,7 +683,7 @@ impl Webauthn {
let extensions = None;
let credential_algorithms = self.algorithms.clone();
let require_resident_key = false;
let policy = if cfg!(feature = "danger-user-presence-only-security-keys") {
let policy = if self.user_presence_only_security_keys {
Some(UserVerificationPolicy::Discouraged_DO_NOT_USE)
} else {
Some(UserVerificationPolicy::Preferred)
Expand Down

0 comments on commit e6912ed

Please sign in to comment.