Skip to content

Commit

Permalink
Feature/configurable timeout (#385)
Browse files Browse the repository at this point in the history
  • Loading branch information
smessmer authored Nov 14, 2023
1 parent bd3c90b commit c70b1bb
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 10 deletions.
3 changes: 2 additions & 1 deletion webauthn-authenticator-rs/examples/authenticate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern crate tracing;
#[cfg(feature = "softtoken")]
use std::fs::OpenOptions;
use std::io::{stdin, stdout, Write};
use std::time::Duration;

use clap::clap_derive::ValueEnum;
#[cfg(any(feature = "cable", feature = "softtoken"))]
Expand Down Expand Up @@ -236,7 +237,7 @@ async fn main() {
"https://localhost:8080/auth",
"localhost",
vec![url::Url::parse("https://localhost:8080").unwrap()],
Some(1),
Some(Duration::from_millis(1)),
None,
None,
);
Expand Down
5 changes: 3 additions & 2 deletions webauthn-rs-core/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::time::Duration;

// Can this ever change?
pub const CHALLENGE_SIZE_BYTES: usize = 32;
// Allegedly this is milliseconds?
pub const AUTHENTICATOR_TIMEOUT: u32 = 60000;
pub const DEFAULT_AUTHENTICATOR_TIMEOUT: Duration = Duration::from_millis(60000);
19 changes: 13 additions & 6 deletions webauthn-rs-core/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
use rand::prelude::*;
use std::collections::BTreeSet;
use std::convert::TryFrom;
use std::time::Duration;
use url::Url;

use crate::attestation::{
verify_android_key_attestation, verify_android_safetynet_attestation,
verify_apple_anonymous_attestation, verify_attestation_ca_chain, verify_fidou2f_attestation,
verify_packed_attestation, verify_tpm_attestation, AttestationFormat,
};
use crate::constants::{AUTHENTICATOR_TIMEOUT, CHALLENGE_SIZE_BYTES};
use crate::constants::{CHALLENGE_SIZE_BYTES, DEFAULT_AUTHENTICATOR_TIMEOUT};
use crate::crypto::compute_sha256;
use crate::error::WebauthnError;
use crate::internals::*;
Expand Down Expand Up @@ -54,7 +55,7 @@ pub struct WebauthnCore {
rp_id: String,
rp_id_hash: [u8; 32],
allowed_origins: Vec<Url>,
authenticator_timeout: u32,
authenticator_timeout: Duration,
require_valid_counter_value: bool,
#[allow(unused)]
ignore_unsupported_attestation_formats: bool,
Expand Down Expand Up @@ -84,7 +85,7 @@ impl WebauthnCore {
rp_name: &str,
rp_id: &str,
allowed_origins: Vec<Url>,
authenticator_timeout: Option<u32>,
authenticator_timeout: Option<Duration>,
allow_subdomains_origin: Option<bool>,
allow_any_port: Option<bool>,
) -> Self {
Expand All @@ -94,7 +95,7 @@ impl WebauthnCore {
rp_id: rp_id.to_string(),
rp_id_hash,
allowed_origins,
authenticator_timeout: authenticator_timeout.unwrap_or(AUTHENTICATOR_TIMEOUT),
authenticator_timeout: authenticator_timeout.unwrap_or(DEFAULT_AUTHENTICATOR_TIMEOUT),
require_valid_counter_value: true,
ignore_unsupported_attestation_formats: true,
allow_cross_origin: false,
Expand Down Expand Up @@ -213,6 +214,9 @@ impl WebauthnCore {
Some(ResidentKeyRequirement::Discouraged)
};

let timeout_millis =
u32::try_from(self.authenticator_timeout.as_millis()).expect("Timeout too large");

let c = CreationChallengeResponse {
public_key: PublicKeyCredentialCreationOptions {
rp: RelyingParty {
Expand All @@ -232,7 +236,7 @@ impl WebauthnCore {
alg: *alg as i64,
})
.collect(),
timeout: Some(self.authenticator_timeout),
timeout: Some(timeout_millis),
attestation: Some(attestation),
exclude_credentials: exclude_credentials.as_ref().map(|creds| {
creds
Expand Down Expand Up @@ -935,12 +939,15 @@ impl WebauthnCore {
// Extract the appid from the extensions to store it in the AuthenticationState
let appid = extensions.as_ref().and_then(|e| e.appid.clone());

let timeout_millis =
u32::try_from(self.authenticator_timeout.as_millis()).expect("Timeout too large");

// Store the chal associated to the user.
// Now put that into the correct challenge format
let r = RequestChallengeResponse {
public_key: PublicKeyCredentialRequestOptions {
challenge: chal.clone().into(),
timeout: Some(self.authenticator_timeout),
timeout: Some(timeout_millis),
rp_id: self.rp_id.clone(),
allow_credentials: ac,
user_verification: policy,
Expand Down
13 changes: 12 additions & 1 deletion webauthn-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ extern crate tracing;

mod interface;

use std::time::Duration;
use url::Url;
use uuid::Uuid;
use webauthn_rs_core::error::{WebauthnError, WebauthnResult};
Expand Down Expand Up @@ -225,6 +226,7 @@ pub struct WebauthnBuilder<'a> {
allowed_origins: Vec<Url>,
allow_subdomains: bool,
allow_any_port: bool,
timeout: Option<Duration>,
algorithms: Vec<COSEAlgorithm>,
user_presence_only_security_keys: bool,
}
Expand Down Expand Up @@ -280,6 +282,7 @@ impl<'a> WebauthnBuilder<'a> {
allowed_origins: vec![rp_origin.to_owned()],
allow_subdomains: false,
allow_any_port: false,
timeout: None,
algorithms: COSEAlgorithm::secure_algs(),
user_presence_only_security_keys: false,
})
Expand Down Expand Up @@ -315,6 +318,14 @@ impl<'a> WebauthnBuilder<'a> {
self
}

/// Set the timeout value to use for credential creation and authentication challenges.
///
/// If not set, defaults to [webauthn_rs_core::constants::DEFAULT_AUTHENTICATOR_TIMEOUT].
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}

/// Set the relying party name. This may be shown to the user. This value can be changed in
/// the future without affecting credentials that have already registered.
///
Expand Down Expand Up @@ -356,7 +367,7 @@ impl<'a> WebauthnBuilder<'a> {
self.rp_name.unwrap_or(self.rp_id),
self.rp_id,
self.allowed_origins,
None,
self.timeout,
Some(self.allow_subdomains),
Some(self.allow_any_port),
),
Expand Down

0 comments on commit c70b1bb

Please sign in to comment.