From 101441258b8db580cf4ce3ecdd76069f53d6b885 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 27 Jul 2025 21:21:13 +0100 Subject: [PATCH 01/28] [WIP] Web IDL support (make credentials); next: extension parsing --- libwebauthn/Cargo.lock | 20 ++++++ libwebauthn/Cargo.toml | 1 + libwebauthn/src/ops/webauthn/create.rs | 67 +++++++++++++++++ libwebauthn/src/ops/webauthn/get_assertion.rs | 7 ++ libwebauthn/src/ops/webauthn/idl.rs | 71 ++++++++++++++++++ .../src/ops/webauthn/make_credential.rs | 72 ++++++++++++++++++- .../src/ops/{webauthn.rs => webauthn/mod.rs} | 11 ++- libwebauthn/src/ops/webauthn/rpid.rs | 47 ++++++++++++ libwebauthn/src/proto/ctap2/model.rs | 3 +- 9 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 libwebauthn/src/ops/webauthn/create.rs create mode 100644 libwebauthn/src/ops/webauthn/idl.rs rename libwebauthn/src/ops/{webauthn.rs => webauthn/mod.rs} (94%) create mode 100644 libwebauthn/src/ops/webauthn/rpid.rs diff --git a/libwebauthn/Cargo.lock b/libwebauthn/Cargo.lock index 111e557d..9ac037c0 100644 --- a/libwebauthn/Cargo.lock +++ b/libwebauthn/Cargo.lock @@ -1769,6 +1769,7 @@ dependencies = [ "serde_bytes", "serde_cbor_2", "serde_derive", + "serde_json", "serde_repr", "sha2 0.10.9", "snow", @@ -2858,6 +2859,19 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "serde_json" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -4176,3 +4190,9 @@ dependencies = [ "quote", "syn 2.0.106", ] + +[[package]] +name = "zmij" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a" diff --git a/libwebauthn/Cargo.toml b/libwebauthn/Cargo.toml index e39043af..9f623b87 100644 --- a/libwebauthn/Cargo.toml +++ b/libwebauthn/Cargo.toml @@ -71,6 +71,7 @@ snow = { version = "0.10", features = ["use-p256"] } ctap-types = { version = "0.4.0" } btleplug = "0.11.7" thiserror = "2.0.12" +serde_json = "1.0.141" apdu-core = { version = "0.4.0", optional = true } apdu = { version = "0.4.0", optional = true } pcsc = { version = "2.9.0", optional = true } diff --git a/libwebauthn/src/ops/webauthn/create.rs b/libwebauthn/src/ops/webauthn/create.rs new file mode 100644 index 00000000..7943c091 --- /dev/null +++ b/libwebauthn/src/ops/webauthn/create.rs @@ -0,0 +1,67 @@ +use super::idl::Base64UrlString; +use crate::{ + ops::webauthn::{ResidentKeyRequirement, UserVerificationRequirement}, + proto::ctap2::{ + Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, + Ctap2PublicKeyCredentialUserEntity, + }, +}; + +use serde::Deserialize; +use serde_json::{Map as JsonMap, Value as JsonValue}; + +/** + * https://www.w3.org/TR/webauthn-3/#sctn-parseCreationOptionsFromJSON + */ + +#[derive(Debug, Clone, Deserialize)] +pub struct PublicKeyCredentialDescriptorJSON { + pub r#type: String, + pub id: Base64UrlString, + pub transports: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct PublicKeyCredentialParameters { + pub r#type: String, + pub alg: i32, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct AuthenticatorSelectionCriteria { + #[serde(rename = "authenticatorAttachment")] + pub authenticator_attachment: Option, + #[serde(rename = "residentKey")] + pub resident_key: Option, + #[serde(rename = "requireResidentKey")] + #[serde(default)] + pub require_resident_key: bool, + #[serde(rename = "userVerification")] + #[serde(default = "default_user_verification")] + pub user_verification: UserVerificationRequirement, +} + +fn default_user_verification() -> UserVerificationRequirement { + UserVerificationRequirement::Preferred +} + +type JsonObject = JsonMap; + +#[derive(Debug, Clone, Deserialize)] +pub struct PublicKeyCredentialCreationOptionsJSON { + pub rp: Ctap2PublicKeyCredentialRpEntity, + pub user: Ctap2PublicKeyCredentialUserEntity, + pub challenge: Base64UrlString, + #[serde(rename = "pubKeyCredParams")] + pub params: Vec, + pub timeout: u32, + #[serde(rename = "excludeCredentials")] + pub exclude_credentials: Vec, + #[serde(rename = "authenticatorSelection")] + pub authenticator_selection: Option, + pub hints: Vec, + pub attestation: String, + #[serde(rename = "attestationFormats")] + pub attestation_formats: Vec, + pub extensions: JsonObject, +} diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 336ff005..2301057c 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -1,3 +1,5 @@ +use super::idl::WebAuthnIDL; + use std::{collections::HashMap, time::Duration}; use serde::{Deserialize, Serialize}; @@ -6,6 +8,11 @@ use tracing::{debug, error, trace}; use crate::{ fido::AuthenticatorData, + ops::webauthn::{ + create::PublicKeyCredentialCreationOptionsJSON, + idl::{FromInnerModel, JsonError}, + rpid::RelyingPartyId, + }, pin::PinUvAuthProtocol, proto::ctap2::{ Ctap2AttestationStatement, Ctap2GetAssertionResponseExtensions, diff --git a/libwebauthn/src/ops/webauthn/idl.rs b/libwebauthn/src/ops/webauthn/idl.rs new file mode 100644 index 00000000..6a5328b7 --- /dev/null +++ b/libwebauthn/src/ops/webauthn/idl.rs @@ -0,0 +1,71 @@ +use base64_url; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json; + +use super::rpid::RelyingPartyId; + +pub type JsonError = serde_json::Error; + +pub trait WebAuthnIDL: Sized +where + E: std::error::Error, // Validation error type. + Self: FromInnerModel, +{ + /// An error type that can be returned when deserializing from JSON, including + /// JSON parsing errors and any additional validation errors. + type Error: std::error::Error + From + From; + + /// The JSON model that this IDL can deserialize from. + type InnerModel: DeserializeOwned; + + fn from_json(rpid: &RelyingPartyId, json: &str) -> Result { + let inner_model: Self::InnerModel = serde_json::from_str(json)?; + Self::from_inner_model(rpid, inner_model).map_err(From::from) + } +} + +pub trait FromInnerModel: Sized +where + T: DeserializeOwned, + E: std::error::Error, +{ + fn from_inner_model(rpid: &RelyingPartyId, inner: T) -> Result; +} + +// TODO(afresta): Move to ctap2 module. +#[derive(Debug, Clone)] +pub struct Base64UrlString(pub Vec); + +impl<'de> Deserialize<'de> for Base64UrlString { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s: String = Deserialize::deserialize(deserializer)?; + base64_url::decode(&s) + .map_err(serde::de::Error::custom) + .map(|bytes| Base64UrlString(bytes)) + } +} + +impl Serialize for Base64UrlString { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let encoded = base64_url::encode(&self.0); + serializer.serialize_str(&encoded) + } +} + +impl Into> for Base64UrlString { + fn into(self) -> Vec { + self.0 + } +} + +impl Base64UrlString { + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 1526c984..3d670fbb 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -7,6 +7,11 @@ use tracing::{debug, instrument, trace}; use crate::{ fido::AuthenticatorData, + ops::webauthn::{ + create::{AuthenticatorSelectionCriteria, PublicKeyCredentialCreationOptionsJSON}, + idl::{FromInnerModel, JsonError, WebAuthnIDL}, + rpid::RelyingPartyId, + }, proto::{ ctap1::{Ctap1RegisteredKey, Ctap1Version}, ctap2::{ @@ -149,10 +154,13 @@ impl MakeCredentialsResponseUnsignedExtensions { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Deserialize)] pub enum ResidentKeyRequirement { + #[serde(rename = "required")] Required, + #[serde(rename = "preferred")] Preferred, + #[serde(rename = "discouraged", other)] Discouraged, } @@ -175,6 +183,68 @@ pub struct MakeCredentialRequest { pub timeout: Duration, } +impl FromInnerModel + for MakeCredentialRequest +{ + fn from_inner_model( + rpid: &RelyingPartyId, + inner: PublicKeyCredentialCreationOptionsJSON, + ) -> Result { + let resident_key = if inner + .authenticator_selection + .as_ref() + .and_then(|s| Some(s.require_resident_key)) + == Some(true) + { + Some(ResidentKeyRequirement::Required) + } else { + inner.authenticator_selection.and_then(|s| s.resident_key) + }; + + let user_verification = inner + .authenticator_selection + .map_or(UserVerificationRequirement::Discouraged, |s| { + s.user_verification + }); + + let exclude = match inner.exclude_credentials[..] { + [] => None, + _ => Some(inner.exclude_credentials), + }; + + let extensions = serde_json::from_value(serde_json::Value::Object(inner.extensions)) + .map_err(MakeCredentialRequestParsingError::ExtensionError)?; + + Ok(Self { + hash: inner.challenge.into(), + origin: rpid.as_str().to_owned(), + relying_party: inner.rp, + user: inner.user, + resident_key, + user_verification, + algorithms: inner.params, + exclude, + extensions, + timeout: Duration::from_secs(inner.timeout), + }) + } +} + +#[derive(thiserror::Error, Debug)] +pub enum MakeCredentialRequestParsingError { + /// The client must throw an "EncodingError" DOMException. + #[error("Invalid JSON format: {0}")] + EncodingError(#[from] JsonError), + + #[error("Invalid extension: {0}")] + ExtensionError(JsonError), +} + +impl WebAuthnIDL for MakeCredentialRequest { + type Error = MakeCredentialRequestParsingError; + type InnerModel = PublicKeyCredentialCreationOptionsJSON; +} + #[derive(Debug, Default, Clone)] pub enum MakeCredentialHmacOrPrfInput { #[default] diff --git a/libwebauthn/src/ops/webauthn.rs b/libwebauthn/src/ops/webauthn/mod.rs similarity index 94% rename from libwebauthn/src/ops/webauthn.rs rename to libwebauthn/src/ops/webauthn/mod.rs index 55665764..1e7a0f70 100644 --- a/libwebauthn/src/ops/webauthn.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -1,5 +1,8 @@ +mod create; mod get_assertion; +pub(crate) mod idl; mod make_credential; +mod rpid; use super::u2f::{RegisterRequest, SignRequest}; use crate::webauthn::CtapError; @@ -17,12 +20,16 @@ pub use make_credential::{ MakeCredentialResponse, MakeCredentialsRequestExtensions, MakeCredentialsResponseExtensions, MakeCredentialsResponseUnsignedExtensions, ResidentKeyRequirement, }; +use serde::Deserialize; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Deserialize)] pub enum UserVerificationRequirement { + #[serde(rename = "required")] Required, - Preferred, + #[serde(rename = "discouraged")] Discouraged, + #[serde(rename = "preferred", other)] + Preferred, } impl UserVerificationRequirement { diff --git a/libwebauthn/src/ops/webauthn/rpid.rs b/libwebauthn/src/ops/webauthn/rpid.rs new file mode 100644 index 00000000..cd2b8a5b --- /dev/null +++ b/libwebauthn/src/ops/webauthn/rpid.rs @@ -0,0 +1,47 @@ +use serde::Deserialize; +use std::convert::TryFrom; + +#[derive(Clone, Debug)] +pub struct RelyingPartyId(pub String); + +impl Into<&str> for &RelyingPartyId { + fn into(self) -> &str { + self.0.as_str() + } +} + +impl Into for RelyingPartyId { + fn into(self) -> String { + self.0 + } +} + +#[derive(thiserror::Error, Debug, Clone)] +// TODO(#137): Validate RelyingPartyId +pub enum Error { + #[error("Empty Relying Party ID is not allowed")] + EmptyRelyingPartyId, +} + +impl TryFrom<&str> for RelyingPartyId { + type Error = Error; + + fn try_from(value: &str) -> Result { + // TODO(#137): Validate RelyingPartyId, including IDNA normalization + // and checking for valid characters. + match value { + "" => Err(Error::EmptyRelyingPartyId), + _ => Ok(RelyingPartyId(value.to_string())), + } + } +} + +impl<'de> Deserialize<'de> for RelyingPartyId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + RelyingPartyId::try_from(s.as_str()).map_err(serde::de::Error::custom) + } +} diff --git a/libwebauthn/src/proto/ctap2/model.rs b/libwebauthn/src/proto/ctap2/model.rs index ebf219b6..02fe28d3 100644 --- a/libwebauthn/src/proto/ctap2/model.rs +++ b/libwebauthn/src/proto/ctap2/model.rs @@ -1,3 +1,4 @@ +use crate::ops::webauthn::idl::Base64UrlString; use crate::pin::PinUvAuthProtocol; use crate::proto::ctap1::Ctap1Transport; @@ -148,7 +149,7 @@ impl From<&Ctap1Transport> for Ctap2Transport { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Ctap2PublicKeyCredentialDescriptor { - pub id: ByteBuf, + pub id: Base64UrlString, pub r#type: Ctap2PublicKeyCredentialType, #[serde(skip_serializing_if = "Option::is_none")] From b86385d99e3181b9d347b371bcdee85e4186c97e Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Mon, 28 Jul 2025 23:15:56 +0100 Subject: [PATCH 02/28] [WIP] More progress --- libwebauthn/examples/prf_test.rs | 7 +- .../examples/webauthn_extensions_hid.rs | 10 +- .../examples/webauthn_preflight_hid.rs | 7 +- libwebauthn/examples/webauthn_prf_hid.rs | 6 +- libwebauthn/src/fido.rs | 5 +- libwebauthn/src/ops/u2f.rs | 3 +- libwebauthn/src/ops/webauthn/create.rs | 6 +- libwebauthn/src/ops/webauthn/get_assertion.rs | 7 -- libwebauthn/src/ops/webauthn/idl.rs | 24 ++++- .../src/ops/webauthn/make_credential.rs | 96 +++++++++++-------- libwebauthn/src/ops/webauthn/mod.rs | 7 +- libwebauthn/src/ops/webauthn/rpid.rs | 10 +- libwebauthn/src/proto/ctap2/model.rs | 4 +- .../src/proto/ctap2/model/get_assertion.rs | 2 +- .../src/proto/ctap2/model/make_credential.rs | 32 ++++--- 15 files changed, 132 insertions(+), 94 deletions(-) diff --git a/libwebauthn/examples/prf_test.rs b/libwebauthn/examples/prf_test.rs index 5d0178ea..22b2b4dc 100644 --- a/libwebauthn/examples/prf_test.rs +++ b/libwebauthn/examples/prf_test.rs @@ -7,14 +7,13 @@ use std::time::Duration; use libwebauthn::transport::hid::channel::HidChannel; use libwebauthn::UvUpdate; use rand::{thread_rng, Rng}; -use serde_bytes::ByteBuf; use text_io::read; use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, PRFValue, - UserVerificationRequirement, + Base64UrlString, GetAssertionHmacOrPrfInput, GetAssertionRequest, + GetAssertionRequestExtensions, PRFValue, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}; @@ -115,7 +114,7 @@ pub async fn main() -> Result<(), Box> { let credential = Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: ByteBuf::from(credential_id.as_slice()), + id: Base64UrlString::from(credential_id.as_slice()), transports: None, }; diff --git a/libwebauthn/examples/webauthn_extensions_hid.rs b/libwebauthn/examples/webauthn_extensions_hid.rs index 22f6bdd6..ecd79f24 100644 --- a/libwebauthn/examples/webauthn_extensions_hid.rs +++ b/libwebauthn/examples/webauthn_extensions_hid.rs @@ -11,8 +11,7 @@ use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ CredentialProtectionExtension, CredentialProtectionPolicy, GetAssertionHmacOrPrfInput, - GetAssertionRequest, GetAssertionRequestExtensions, HMACGetSecretInput, - MakeCredentialHmacOrPrfInput, MakeCredentialLargeBlobExtension, MakeCredentialRequest, + GetAssertionRequest, GetAssertionRequestExtensions, HMACGetSecretInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; @@ -88,10 +87,11 @@ pub async fn main() -> Result<(), Box> { policy: CredentialProtectionPolicy::UserVerificationRequired, enforce_policy: true, }), - cred_blob: Some(r"My own little blob".into()), - large_blob: MakeCredentialLargeBlobExtension::None, + cred_blob: Some("My own little blob".as_bytes().into()), + large_blob: None, min_pin_length: Some(true), - hmac_or_prf: MakeCredentialHmacOrPrfInput::HmacGetSecret, + hmac_create_secret: Some(true), + prf: None, cred_props: Some(true), }; diff --git a/libwebauthn/examples/webauthn_preflight_hid.rs b/libwebauthn/examples/webauthn_preflight_hid.rs index 98d71657..4c62ec12 100644 --- a/libwebauthn/examples/webauthn_preflight_hid.rs +++ b/libwebauthn/examples/webauthn_preflight_hid.rs @@ -5,14 +5,13 @@ use std::time::Duration; use libwebauthn::UvUpdate; use rand::{thread_rng, Rng}; -use serde_bytes::ByteBuf; use text_io::read; use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, GetAssertionResponse, MakeCredentialRequest, ResidentKeyRequirement, - UserVerificationRequirement, + Base64UrlString, GetAssertionRequest, GetAssertionResponse, MakeCredentialRequest, + ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -225,7 +224,7 @@ async fn get_assertion_call( fn create_credential(id: &[u8]) -> Ctap2PublicKeyCredentialDescriptor { Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: ByteBuf::from(id), + id: Base64UrlString::from(id), transports: None, } } diff --git a/libwebauthn/examples/webauthn_prf_hid.rs b/libwebauthn/examples/webauthn_prf_hid.rs index 35d34a76..2122f691 100644 --- a/libwebauthn/examples/webauthn_prf_hid.rs +++ b/libwebauthn/examples/webauthn_prf_hid.rs @@ -13,8 +13,8 @@ use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, - MakeCredentialHmacOrPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, - PRFValue, ResidentKeyRequirement, UserVerificationRequirement, + MakeCredentialPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue, + ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -85,7 +85,7 @@ pub async fn main() -> Result<(), Box> { let challenge: [u8; 32] = thread_rng().gen(); let extensions = MakeCredentialsRequestExtensions { - hmac_or_prf: MakeCredentialHmacOrPrfInput::Prf, + prf: Some(MakeCredentialPrfInput { _eval: None }), ..Default::default() }; diff --git a/libwebauthn/src/fido.rs b/libwebauthn/src/fido.rs index 55ce46bb..a56a2a98 100644 --- a/libwebauthn/src/fido.rs +++ b/libwebauthn/src/fido.rs @@ -4,7 +4,6 @@ use serde::{ de::{DeserializeOwned, Error as DesError, Visitor}, Deserialize, Deserializer, Serialize, }; -use serde_bytes::ByteBuf; use std::{ fmt, io::{Cursor, Read}, @@ -12,7 +11,7 @@ use std::{ }; use tracing::{error, warn}; -use crate::proto::ctap2::cbor; +use crate::{ops::webauthn::idl::Base64UrlString, proto::ctap2::cbor}; use crate::{ proto::{ ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}, @@ -69,7 +68,7 @@ impl From<&AttestedCredentialData> for Ctap2PublicKeyCredentialDescriptor { fn from(data: &AttestedCredentialData) -> Self { Self { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: ByteBuf::from(data.credential_id.clone()), + id: Base64UrlString::from(data.credential_id.clone()), transports: None, } } diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index c442b81d..1cce9e2a 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -8,6 +8,7 @@ use x509_parser::nom::AsBytes; use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; +use crate::ops::webauthn::idl::Base64UrlString; use crate::ops::webauthn::{ GetAssertionRequest, GetAssertionResponse, MakeCredentialResponse, UserVerificationRequirement, }; @@ -183,7 +184,7 @@ impl UpgradableResponse for SignResponse { let response = Ctap2GetAssertionResponse { credential_id: Some(Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: ByteBuf::from(request.key_handle.clone()), + id: Base64UrlString::from(request.key_handle.clone()), transports: None, }), authenticator_data, diff --git a/libwebauthn/src/ops/webauthn/create.rs b/libwebauthn/src/ops/webauthn/create.rs index 7943c091..86c213af 100644 --- a/libwebauthn/src/ops/webauthn/create.rs +++ b/libwebauthn/src/ops/webauthn/create.rs @@ -1,6 +1,8 @@ use super::idl::Base64UrlString; use crate::{ - ops::webauthn::{ResidentKeyRequirement, UserVerificationRequirement}, + ops::webauthn::{ + MakeCredentialsRequestExtensions, ResidentKeyRequirement, UserVerificationRequirement, + }, proto::ctap2::{ Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, Ctap2PublicKeyCredentialUserEntity, @@ -63,5 +65,5 @@ pub struct PublicKeyCredentialCreationOptionsJSON { pub attestation: String, #[serde(rename = "attestationFormats")] pub attestation_formats: Vec, - pub extensions: JsonObject, + pub extensions: MakeCredentialsRequestExtensions, } diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 2301057c..336ff005 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -1,5 +1,3 @@ -use super::idl::WebAuthnIDL; - use std::{collections::HashMap, time::Duration}; use serde::{Deserialize, Serialize}; @@ -8,11 +6,6 @@ use tracing::{debug, error, trace}; use crate::{ fido::AuthenticatorData, - ops::webauthn::{ - create::PublicKeyCredentialCreationOptionsJSON, - idl::{FromInnerModel, JsonError}, - rpid::RelyingPartyId, - }, pin::PinUvAuthProtocol, proto::ctap2::{ Ctap2AttestationStatement, Ctap2GetAssertionResponseExtensions, diff --git a/libwebauthn/src/ops/webauthn/idl.rs b/libwebauthn/src/ops/webauthn/idl.rs index 6a5328b7..c4ecbdfc 100644 --- a/libwebauthn/src/ops/webauthn/idl.rs +++ b/libwebauthn/src/ops/webauthn/idl.rs @@ -1,3 +1,5 @@ +use std::ops::Deref; + use base64_url; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json; @@ -33,9 +35,29 @@ where } // TODO(afresta): Move to ctap2 module. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Base64UrlString(pub Vec); +impl From> for Base64UrlString { + fn from(bytes: Vec) -> Self { + Base64UrlString(bytes) + } +} + +impl From<&[u8]> for Base64UrlString { + fn from(bytes: &[u8]) -> Self { + Base64UrlString(bytes.to_vec()) + } +} + +impl Deref for Base64UrlString { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &self.0 + } +} + impl<'de> Deserialize<'de> for Base64UrlString { fn deserialize(deserializer: D) -> Result where diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 3d670fbb..089d3902 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -2,14 +2,15 @@ use std::time::Duration; use ctap_types::ctap2::credential_management::CredentialProtectionPolicy as Ctap2CredentialProtectionPolicy; use serde::{Deserialize, Serialize}; +use serde_json::{self, Value as JsonValue}; use sha2::{Digest, Sha256}; use tracing::{debug, instrument, trace}; use crate::{ fido::AuthenticatorData, ops::webauthn::{ - create::{AuthenticatorSelectionCriteria, PublicKeyCredentialCreationOptionsJSON}, - idl::{FromInnerModel, JsonError, WebAuthnIDL}, + create::PublicKeyCredentialCreationOptionsJSON, + idl::{Base64UrlString, FromInnerModel, JsonError, WebAuthnIDL}, rpid::RelyingPartyId, }, proto::{ @@ -68,17 +69,17 @@ impl MakeCredentialsResponseUnsignedExtensions { let mut prf = None; if let Some(signed_extensions) = signed_extensions { (hmac_create_secret, prf) = if let Some(incoming_ext) = &request.extensions { - match &incoming_ext.hmac_or_prf { - MakeCredentialHmacOrPrfInput::None => (None, None), - MakeCredentialHmacOrPrfInput::HmacGetSecret => { - (signed_extensions.hmac_secret, None) - } - MakeCredentialHmacOrPrfInput::Prf => ( + if let Some(hmac_create_secret) = incoming_ext.hmac_create_secret { + (signed_extensions.hmac_secret, None) + } else if let Some(prf) = &incoming_ext.prf { + ( None, Some(MakeCredentialPrfOutput { enabled: signed_extensions.hmac_secret, }), - ), + ) + } else { + (None, None) } } else { (None, None) @@ -131,7 +132,12 @@ impl MakeCredentialsResponseUnsignedExtensions { // largeBlob extension // https://www.w3.org/TR/webauthn-3/#sctn-large-blob-extension - let large_blob = match &request.extensions.as_ref().map(|x| &x.large_blob) { + let large_blob = match &request + .extensions + .as_ref() + .and_then(|x| x.large_blob.as_ref()) + .map(|x| x.support) + { None | Some(MakeCredentialLargeBlobExtension::None) => None, // Not requested, so we don't give an answer Some(MakeCredentialLargeBlobExtension::Preferred) | Some(MakeCredentialLargeBlobExtension::Required) => { @@ -198,11 +204,15 @@ impl FromInnerModel Some(inner.exclude_credentials), }; - let extensions = serde_json::from_value(serde_json::Value::Object(inner.extensions)) - .map_err(MakeCredentialRequestParsingError::ExtensionError)?; - Ok(Self { hash: inner.challenge.into(), - origin: rpid.as_str().to_owned(), + origin: rpid.to_owned().into(), relying_party: inner.rp, user: inner.user, resident_key, user_verification, algorithms: inner.params, exclude, - extensions, - timeout: Duration::from_secs(inner.timeout), + extensions: Some(inner.extensions), + timeout: Duration::from_secs(inner.timeout.into()), }) } } @@ -245,22 +252,10 @@ impl WebAuthnIDL for MakeCredentialRequest { type InnerModel = PublicKeyCredentialCreationOptionsJSON; } -#[derive(Debug, Default, Clone)] -pub enum MakeCredentialHmacOrPrfInput { - #[default] - None, - HmacGetSecret, - Prf, - // The spec tells us that in theory, we could hand in - // an `eval` here, IF the CTAP2 would get an additional - // extension to handle that. There is no such CTAP-extension - // right now, so we don't expose it for now, as it would just - // be ignored anyways. - // https://w3c.github.io/webauthn/#prf - // "If eval is present and a future extension to [FIDO-CTAP] permits evaluation of the PRF at creation time, configure hmac-secret inputs accordingly: .." - // Prf { - // eval: Option, - // }, +#[derive(Debug, Clone, Deserialize)] +pub struct MakeCredentialPrfInput { + #[serde(rename = "eval")] + pub _eval: Option, } #[derive(Debug, Default, Clone, Serialize, PartialEq)] @@ -269,9 +264,11 @@ pub struct MakeCredentialPrfOutput { pub enabled: Option, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Deserialize)] pub struct CredentialProtectionExtension { + #[serde(rename = "credentialProtectionPolicy")] pub policy: CredentialProtectionPolicy, + #[serde(rename = "enforceCredentialProtectionPolicy")] pub enforce_policy: bool, } @@ -324,13 +321,20 @@ pub struct CredentialPropsExtension { pub rk: Option, } -#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default, Clone, Deserialize)] +pub struct MakeCredentialLargeBlobExtensionInput { + pub support: MakeCredentialLargeBlobExtension, +} + +#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] pub enum MakeCredentialLargeBlobExtension { - #[default] - None, + #[serde(rename = "preferred")] Preferred, + #[serde(rename = "required")] Required, + #[default] + #[serde(other)] + None, } #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)] @@ -339,14 +343,22 @@ pub struct MakeCredentialLargeBlobExtensionOutput { pub supported: Option, } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Deserialize)] pub struct MakeCredentialsRequestExtensions { + #[serde(rename = "credProps")] pub cred_props: Option, + #[serde(rename = "credProtect")] pub cred_protect: Option, - pub cred_blob: Option>, - pub large_blob: MakeCredentialLargeBlobExtension, + #[serde(rename = "credBlob")] + pub cred_blob: Option, + #[serde(rename = "largeBlob")] + pub large_blob: Option, + #[serde(rename = "minPinLength")] pub min_pin_length: Option, - pub hmac_or_prf: MakeCredentialHmacOrPrfInput, + #[serde(rename = "hmacCreateSecret")] + pub hmac_create_secret: Option, + #[serde(rename = "prf")] + pub prf: Option, } pub type MakeCredentialsResponseExtensions = Ctap2MakeCredentialsResponseExtensions; diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index 1e7a0f70..cef87b8d 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -13,11 +13,12 @@ pub use get_assertion::{ GetAssertionResponseExtensions, GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, HMACGetSecretOutput, PRFValue, }; +pub use idl::Base64UrlString; pub use make_credential::{ CredentialPropsExtension, CredentialProtectionExtension, CredentialProtectionPolicy, - MakeCredentialHmacOrPrfInput, MakeCredentialLargeBlobExtension, - MakeCredentialLargeBlobExtensionOutput, MakeCredentialPrfOutput, MakeCredentialRequest, - MakeCredentialResponse, MakeCredentialsRequestExtensions, MakeCredentialsResponseExtensions, + MakeCredentialLargeBlobExtension, MakeCredentialLargeBlobExtensionOutput, + MakeCredentialPrfInput, MakeCredentialPrfOutput, MakeCredentialRequest, MakeCredentialResponse, + MakeCredentialsRequestExtensions, MakeCredentialsResponseExtensions, MakeCredentialsResponseUnsignedExtensions, ResidentKeyRequirement, }; use serde::Deserialize; diff --git a/libwebauthn/src/ops/webauthn/rpid.rs b/libwebauthn/src/ops/webauthn/rpid.rs index cd2b8a5b..a92b12be 100644 --- a/libwebauthn/src/ops/webauthn/rpid.rs +++ b/libwebauthn/src/ops/webauthn/rpid.rs @@ -1,12 +1,14 @@ use serde::Deserialize; -use std::convert::TryFrom; +use std::{convert::TryFrom, ops::Deref}; #[derive(Clone, Debug)] pub struct RelyingPartyId(pub String); -impl Into<&str> for &RelyingPartyId { - fn into(self) -> &str { - self.0.as_str() +impl Deref for RelyingPartyId { + type Target = str; + + fn deref(&self) -> &str { + &self.0 } } diff --git a/libwebauthn/src/proto/ctap2/model.rs b/libwebauthn/src/proto/ctap2/model.rs index 02fe28d3..5dbeed27 100644 --- a/libwebauthn/src/proto/ctap2/model.rs +++ b/libwebauthn/src/proto/ctap2/model.rs @@ -228,12 +228,12 @@ pub enum Ctap2UserVerificationOperation { #[cfg(test)] mod tests { + use crate::ops::webauthn::idl::Base64UrlString; use crate::proto::ctap2::cbor; use crate::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; use super::{Ctap2COSEAlgorithmIdentifier, Ctap2CredentialType, Ctap2PublicKeyCredentialType}; use hex; - use serde_bytes::ByteBuf; use serde_cbor_2 as serde_cbor; #[test] @@ -253,7 +253,7 @@ mod tests { /// Verify CBOR serialization conforms to CTAP canonical standard, including ordering (see #95) pub fn credential_descriptor_serialization() { let credential_descriptor = Ctap2PublicKeyCredentialDescriptor { - id: ByteBuf::from(vec![0x42]), + id: Base64UrlString::from(vec![0x42]), r#type: Ctap2PublicKeyCredentialType::PublicKey, transports: None, }; diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index 775d5205..5acb128e 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -302,7 +302,7 @@ impl Ctap2GetAssertionRequestExtensions { .map_err(|_| Error::Platform(PlatformError::SyntaxError))?; // 4.1 If evalByCredential is present and contains an entry whose key is the base64url encoding of the credential ID that will be returned, let ev be the value of that entry. - let found_cred_id = allow_list.iter().find(|x| x.id == cred_id); + let found_cred_id = allow_list.iter().find(|x| x.id.0 == cred_id); if found_cred_id.is_some() { ev = Some(prf_value); break; diff --git a/libwebauthn/src/proto/ctap2/model/make_credential.rs b/libwebauthn/src/proto/ctap2/model/make_credential.rs index afc2d023..739dc9fe 100644 --- a/libwebauthn/src/proto/ctap2/model/make_credential.rs +++ b/libwebauthn/src/proto/ctap2/model/make_credential.rs @@ -7,8 +7,8 @@ use super::{ use crate::{ fido::AuthenticatorData, ops::webauthn::{ - CredentialProtectionPolicy, MakeCredentialHmacOrPrfInput, MakeCredentialLargeBlobExtension, - MakeCredentialRequest, MakeCredentialResponse, MakeCredentialsRequestExtensions, + CredentialProtectionPolicy, MakeCredentialLargeBlobExtension, MakeCredentialRequest, + MakeCredentialResponse, MakeCredentialsRequestExtensions, MakeCredentialsResponseUnsignedExtensions, ResidentKeyRequirement, }, pin::PinUvAuthProtocol, @@ -225,8 +225,12 @@ impl Ctap2MakeCredentialsRequestExtensions { // LargeBlob (NOTE: Not to be confused with LargeBlobKey. LargeBlob has "Preferred" as well) // https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/WebAuthn_extensions#largeblob // - let large_blob_key = match requested_extensions.large_blob { - MakeCredentialLargeBlobExtension::Required => { + let large_blob_key = match requested_extensions + .large_blob + .as_ref() + .map(|info| info.support) + { + Some(MakeCredentialLargeBlobExtension::Required) => { // "required": The credential will be created with an authenticator to store blobs. The create() call will fail if this is impossible. if !info.option_enabled("largeBlobs") { warn!("This request will potentially fail. Large blob extension required, but device does not support it."); @@ -235,7 +239,7 @@ impl Ctap2MakeCredentialsRequestExtensions { // We only add a warning for easier debugging. Some(true) } - MakeCredentialLargeBlobExtension::Preferred => { + Some(MakeCredentialLargeBlobExtension::Preferred) => { if info.option_enabled("largeBlobs") { Some(true) } else { @@ -244,19 +248,23 @@ impl Ctap2MakeCredentialsRequestExtensions { None } } - MakeCredentialLargeBlobExtension::None => None, + _ => None, }; // HMAC Secret - let hmac_secret = match requested_extensions.hmac_or_prf { - MakeCredentialHmacOrPrfInput::None => None, - MakeCredentialHmacOrPrfInput::HmacGetSecret | MakeCredentialHmacOrPrfInput::Prf => { - Some(true) - } + let hmac_secret = if requested_extensions.hmac_create_secret == Some(true) + || requested_extensions.prf.is_some() + { + Some(true) + } else { + None }; Ok(Ctap2MakeCredentialsRequestExtensions { - cred_blob: requested_extensions.cred_blob.clone(), + cred_blob: requested_extensions + .cred_blob + .as_ref() + .map(|inner| inner.0.clone()), hmac_secret, cred_protect: requested_extensions .cred_protect From 4e3ee4243a2845d51ba11fbd66bdc02bf7521742 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 3 Aug 2025 22:41:43 +0100 Subject: [PATCH 03/28] Make Credential parsing seems working; added example --- libwebauthn/Cargo.lock | 111 ++++++++--- libwebauthn/examples/webauthn_json_hid.rs | 175 ++++++++++++++++++ libwebauthn/src/ops/webauthn/create.rs | 21 +-- libwebauthn/src/ops/webauthn/idl.rs | 6 + .../src/ops/webauthn/make_credential.rs | 5 +- libwebauthn/src/ops/webauthn/mod.rs | 3 +- 6 files changed, 276 insertions(+), 45 deletions(-) create mode 100644 libwebauthn/examples/webauthn_json_hid.rs diff --git a/libwebauthn/Cargo.lock b/libwebauthn/Cargo.lock index 9ac037c0..e4f1c316 100644 --- a/libwebauthn/Cargo.lock +++ b/libwebauthn/Cargo.lock @@ -286,7 +286,11 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ +<<<<<<< HEAD "bitflags 1.3.2", +======= + "bitflags 2.9.4", +>>>>>>> 386a777 (Make Credential parsing seems working; added example) "cexpr", "clang-sys", "lazy_static", @@ -508,9 +512,15 @@ dependencies = [ [[package]] name = "cc" +<<<<<<< HEAD version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +======= +version = "1.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "find-msvc-tools", "jobserver", @@ -1169,6 +1179,7 @@ dependencies = [ [[package]] name = "find-msvc-tools" +<<<<<<< HEAD version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" @@ -1183,6 +1194,11 @@ dependencies = [ "serde_derive", "winreg", ] +======= +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) [[package]] name = "flexiber" @@ -1358,7 +1374,11 @@ dependencies = [ "cfg-if", "libc", "r-efi", +<<<<<<< HEAD "wasi 0.14.7+wasi-0.2.4", +======= + "wasi 0.14.4+wasi-0.2.4", +>>>>>>> 386a777 (Make Credential parsing seems working; added example) ] [[package]] @@ -1554,9 +1574,15 @@ dependencies = [ [[package]] name = "indexmap" +<<<<<<< HEAD version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +======= +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -1678,9 +1704,15 @@ dependencies = [ [[package]] name = "js-sys" +<<<<<<< HEAD version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +======= +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "once_cell", "wasm-bindgen", @@ -3209,12 +3241,17 @@ dependencies = [ [[package]] name = "time" +<<<<<<< HEAD version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +======= +version = "0.3.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde", @@ -3575,6 +3612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] +<<<<<<< HEAD name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3584,6 +3622,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" name = "uuid" version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" +======= +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", @@ -3628,6 +3671,7 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" +<<<<<<< HEAD version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" @@ -3641,14 +3685,26 @@ version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ +======= +version = "0.14.4+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" +dependencies = [ +>>>>>>> 386a777 (Make Credential parsing seems working; added example) "wit-bindgen", ] [[package]] name = "wasm-bindgen" +<<<<<<< HEAD version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +======= +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "cfg-if", "once_cell", @@ -3659,9 +3715,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" +<<<<<<< HEAD version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +======= +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "bumpalo", "log", @@ -3673,9 +3735,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" +<<<<<<< HEAD version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +======= +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3683,9 +3751,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" +<<<<<<< HEAD version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +======= +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "proc-macro2", "quote", @@ -3696,9 +3770,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" +<<<<<<< HEAD version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +======= +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "unicode-ident", ] @@ -3715,22 +3795,6 @@ dependencies = [ "rustix 0.38.44", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.11" @@ -3740,12 +3804,6 @@ dependencies = [ "windows-sys 0.61.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows" version = "0.48.0" @@ -4113,6 +4171,7 @@ dependencies = [ ] [[package]] +<<<<<<< HEAD name = "winreg" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4121,6 +4180,12 @@ dependencies = [ "serde", "winapi", ] +======= +name = "wit-bindgen" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +>>>>>>> 386a777 (Make Credential parsing seems working; added example) [[package]] name = "wit-bindgen" diff --git a/libwebauthn/examples/webauthn_json_hid.rs b/libwebauthn/examples/webauthn_json_hid.rs new file mode 100644 index 00000000..0f990242 --- /dev/null +++ b/libwebauthn/examples/webauthn_json_hid.rs @@ -0,0 +1,175 @@ +use std::convert::TryInto; +use std::error::Error; +use std::io::{self, Write}; +use std::time::Duration; + +use ctap_types::ctap2::make_credential; +use libwebauthn::UvUpdate; +use rand::{thread_rng, Rng}; +use text_io::read; +use tokio::sync::broadcast::Receiver; +use tracing_subscriber::{self, EnvFilter}; + +use libwebauthn::ops::webauthn::{ + GetAssertionRequest, MakeCredentialRequest, RelyingPartyId, ResidentKeyRequirement, + UserVerificationRequirement, WebAuthnIDL as _, +}; +use libwebauthn::pin::PinRequestReason; +use libwebauthn::proto::ctap2::{ + Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, + Ctap2PublicKeyCredentialUserEntity, +}; +use libwebauthn::transport::hid::list_devices; +use libwebauthn::transport::{Channel as _, Device}; +use libwebauthn::webauthn::{Error as WebAuthnError, WebAuthn}; + +const TIMEOUT: Duration = Duration::from_secs(10); + +fn setup_logging() { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .without_time() + .init(); +} + +async fn handle_updates(mut state_recv: Receiver) { + while let Ok(update) = state_recv.recv().await { + match update { + UvUpdate::PresenceRequired => println!("Please touch your device!"), + UvUpdate::UvRetry { attempts_left } => { + print!("UV failed."); + if let Some(attempts_left) = attempts_left { + print!(" You have {attempts_left} attempts left."); + } + } + UvUpdate::PinRequired(update) => { + let mut attempts_str = String::new(); + if let Some(attempts) = update.attempts_left { + attempts_str = format!(". You have {attempts} attempts left!"); + }; + + match update.reason { + PinRequestReason::RelyingPartyRequest => println!("RP required a PIN."), + PinRequestReason::AuthenticatorPolicy => { + println!("Your device requires a PIN.") + } + PinRequestReason::FallbackFromUV => { + println!("UV failed too often and is blocked. Falling back to PIN.") + } + } + print!("PIN: Please enter the PIN for your authenticator{attempts_str}: "); + io::stdout().flush().unwrap(); + let pin_raw: String = read!("{}\n"); + + if pin_raw.is_empty() { + println!("PIN: No PIN provided, cancelling operation."); + update.cancel(); + } else { + let _ = update.send_pin(&pin_raw); + } + } + } + } +} + +#[tokio::main] +pub async fn main() -> Result<(), Box> { + setup_logging(); + + let devices = list_devices().await.unwrap(); + println!("Devices found: {:?}", devices); + + let user_id: [u8; 32] = thread_rng().gen(); + let challenge: [u8; 32] = thread_rng().gen(); + + for mut device in devices { + println!("Selected HID authenticator: {}", &device); + let mut channel = device.channel().await?; + channel.wink(TIMEOUT).await?; + + // Relying + let rpid = RelyingPartyId("example.org".to_owned()); + let request_json = r#" + { + "rp": { + "id": "example.org", + "name": "Example Relying Party" + }, + "user": { + "id": "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzg", + "name": "Mario Rossi", + "displayName": "Mario Rossi" + }, + "challenge": "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzg", + "pubKeyCredParams": [ + {"type": "public-key", "alg": -7} + ], + "timeout": 60000, + "excludeCredentials": [], + "authenticatorSelection": { + "residentKey": "discouraged", + "userVerification": "preferred" + }, + "attestation": "none" + } + "#; + let make_credentials_request: MakeCredentialRequest = + MakeCredentialRequest::from_json(&rpid, request_json) + .expect("Failed to parse request JSON"); + println!( + "WebAuthn MakeCredential request: {:?}", + make_credentials_request + ); + + let state_recv = channel.get_ux_update_receiver(); + tokio::spawn(handle_updates(state_recv)); + + let response = loop { + match channel + .webauthn_make_credential(&make_credentials_request) + .await + { + Ok(response) => break Ok(response), + Err(WebAuthnError::Ctap(ctap_error)) => { + if ctap_error.is_retryable_user_error() { + println!("Oops, try again! Error: {}", ctap_error); + continue; + } + break Err(WebAuthnError::Ctap(ctap_error)); + } + Err(err) => break Err(err), + }; + } + .unwrap(); + println!("WebAuthn MakeCredential response: {:?}", response); + + let credential: Ctap2PublicKeyCredentialDescriptor = + (&response.authenticator_data).try_into().unwrap(); + let get_assertion = GetAssertionRequest { + relying_party_id: "example.org".to_owned(), + hash: Vec::from(challenge), + allow: vec![credential], + user_verification: UserVerificationRequirement::Discouraged, + extensions: None, + timeout: TIMEOUT, + }; + + let response = loop { + match channel.webauthn_get_assertion(&get_assertion).await { + Ok(response) => break Ok(response), + Err(WebAuthnError::Ctap(ctap_error)) => { + if ctap_error.is_retryable_user_error() { + println!("Oops, try again! Error: {}", ctap_error); + continue; + } + break Err(WebAuthnError::Ctap(ctap_error)); + } + Err(err) => break Err(err), + }; + } + .unwrap(); + println!("WebAuthn GetAssertion response: {:?}", response); + } + + Ok(()) +} diff --git a/libwebauthn/src/ops/webauthn/create.rs b/libwebauthn/src/ops/webauthn/create.rs index 86c213af..7baf3fdc 100644 --- a/libwebauthn/src/ops/webauthn/create.rs +++ b/libwebauthn/src/ops/webauthn/create.rs @@ -16,19 +16,6 @@ use serde_json::{Map as JsonMap, Value as JsonValue}; * https://www.w3.org/TR/webauthn-3/#sctn-parseCreationOptionsFromJSON */ -#[derive(Debug, Clone, Deserialize)] -pub struct PublicKeyCredentialDescriptorJSON { - pub r#type: String, - pub id: Base64UrlString, - pub transports: Vec, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct PublicKeyCredentialParameters { - pub r#type: String, - pub alg: i32, -} - #[derive(Debug, Clone, Deserialize)] pub struct AuthenticatorSelectionCriteria { #[serde(rename = "authenticatorAttachment")] @@ -61,9 +48,9 @@ pub struct PublicKeyCredentialCreationOptionsJSON { pub exclude_credentials: Vec, #[serde(rename = "authenticatorSelection")] pub authenticator_selection: Option, - pub hints: Vec, - pub attestation: String, + pub hints: Option>, + pub attestation: Option, #[serde(rename = "attestationFormats")] - pub attestation_formats: Vec, - pub extensions: MakeCredentialsRequestExtensions, + pub attestation_formats: Option>, + pub extensions: Option, } diff --git a/libwebauthn/src/ops/webauthn/idl.rs b/libwebauthn/src/ops/webauthn/idl.rs index c4ecbdfc..b7552dd0 100644 --- a/libwebauthn/src/ops/webauthn/idl.rs +++ b/libwebauthn/src/ops/webauthn/idl.rs @@ -58,6 +58,12 @@ impl Deref for Base64UrlString { } } +impl AsRef<[u8]> for Base64UrlString { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + impl<'de> Deserialize<'de> for Base64UrlString { fn deserialize(deserializer: D) -> Result where diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 089d3902..f01f8290 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -231,7 +231,7 @@ impl FromInnerModel for MakeCredentialRequest { diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index cef87b8d..d6846679 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -13,7 +13,7 @@ pub use get_assertion::{ GetAssertionResponseExtensions, GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, HMACGetSecretOutput, PRFValue, }; -pub use idl::Base64UrlString; +pub use idl::{Base64UrlString, WebAuthnIDL}; pub use make_credential::{ CredentialPropsExtension, CredentialProtectionExtension, CredentialProtectionPolicy, MakeCredentialLargeBlobExtension, MakeCredentialLargeBlobExtensionOutput, @@ -21,6 +21,7 @@ pub use make_credential::{ MakeCredentialsRequestExtensions, MakeCredentialsResponseExtensions, MakeCredentialsResponseUnsignedExtensions, ResidentKeyRequirement, }; +pub use rpid::RelyingPartyId; use serde::Deserialize; #[derive(Debug, Clone, Copy, Deserialize)] From 80ba7023e080e14db0995db4e36116c178cd869a Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Fri, 8 Aug 2025 18:22:28 +0100 Subject: [PATCH 04/28] Clean up warnings --- libwebauthn/examples/webauthn_json_hid.rs | 14 ++++---------- libwebauthn/src/ops/webauthn/create.rs | 3 --- libwebauthn/src/ops/webauthn/make_credential.rs | 4 ++-- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/libwebauthn/examples/webauthn_json_hid.rs b/libwebauthn/examples/webauthn_json_hid.rs index 0f990242..4b41fb79 100644 --- a/libwebauthn/examples/webauthn_json_hid.rs +++ b/libwebauthn/examples/webauthn_json_hid.rs @@ -3,7 +3,6 @@ use std::error::Error; use std::io::{self, Write}; use std::time::Duration; -use ctap_types::ctap2::make_credential; use libwebauthn::UvUpdate; use rand::{thread_rng, Rng}; use text_io::read; @@ -11,14 +10,11 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, MakeCredentialRequest, RelyingPartyId, ResidentKeyRequirement, - UserVerificationRequirement, WebAuthnIDL as _, + GetAssertionRequest, MakeCredentialRequest, RelyingPartyId, UserVerificationRequirement, + WebAuthnIDL as _, }; use libwebauthn::pin::PinRequestReason; -use libwebauthn::proto::ctap2::{ - Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, - Ctap2PublicKeyCredentialUserEntity, -}; +use libwebauthn::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; use libwebauthn::transport::hid::list_devices; use libwebauthn::transport::{Channel as _, Device}; use libwebauthn::webauthn::{Error as WebAuthnError, WebAuthn}; @@ -79,9 +75,6 @@ pub async fn main() -> Result<(), Box> { let devices = list_devices().await.unwrap(); println!("Devices found: {:?}", devices); - let user_id: [u8; 32] = thread_rng().gen(); - let challenge: [u8; 32] = thread_rng().gen(); - for mut device in devices { println!("Selected HID authenticator: {}", &device); let mut channel = device.channel().await?; @@ -143,6 +136,7 @@ pub async fn main() -> Result<(), Box> { .unwrap(); println!("WebAuthn MakeCredential response: {:?}", response); + let challenge: [u8; 32] = thread_rng().gen(); let credential: Ctap2PublicKeyCredentialDescriptor = (&response.authenticator_data).try_into().unwrap(); let get_assertion = GetAssertionRequest { diff --git a/libwebauthn/src/ops/webauthn/create.rs b/libwebauthn/src/ops/webauthn/create.rs index 7baf3fdc..7f98ad19 100644 --- a/libwebauthn/src/ops/webauthn/create.rs +++ b/libwebauthn/src/ops/webauthn/create.rs @@ -10,7 +10,6 @@ use crate::{ }; use serde::Deserialize; -use serde_json::{Map as JsonMap, Value as JsonValue}; /** * https://www.w3.org/TR/webauthn-3/#sctn-parseCreationOptionsFromJSON @@ -34,8 +33,6 @@ fn default_user_verification() -> UserVerificationRequirement { UserVerificationRequirement::Preferred } -type JsonObject = JsonMap; - #[derive(Debug, Clone, Deserialize)] pub struct PublicKeyCredentialCreationOptionsJSON { pub rp: Ctap2PublicKeyCredentialRpEntity, diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index f01f8290..7bae1623 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -69,9 +69,9 @@ impl MakeCredentialsResponseUnsignedExtensions { let mut prf = None; if let Some(signed_extensions) = signed_extensions { (hmac_create_secret, prf) = if let Some(incoming_ext) = &request.extensions { - if let Some(hmac_create_secret) = incoming_ext.hmac_create_secret { + if let Some(_hmac_create_secret) = incoming_ext.hmac_create_secret { (signed_extensions.hmac_secret, None) - } else if let Some(prf) = &incoming_ext.prf { + } else if let Some(_prf) = &incoming_ext.prf { ( None, Some(MakeCredentialPrfOutput { From c094136c88851e6a03e40a8e8ef966e431147e4b Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Fri, 15 Aug 2025 11:13:59 +0100 Subject: [PATCH 05/28] GetAssertion IDL implementation --- libwebauthn/examples/prf_test.rs | 13 +- libwebauthn/examples/webauthn_cable.rs | 5 +- .../examples/webauthn_extensions_hid.rs | 16 +- libwebauthn/examples/webauthn_hid.rs | 5 +- libwebauthn/examples/webauthn_json_hid.rs | 6 +- .../examples/webauthn_preflight_hid.rs | 6 +- libwebauthn/examples/webauthn_prf_hid.rs | 50 ++-- libwebauthn/src/ops/u2f.rs | 5 +- libwebauthn/src/ops/webauthn/create.rs | 2 +- libwebauthn/src/ops/webauthn/get_assertion.rs | 261 +++++++++++++++++- .../src/ops/webauthn/make_credential.rs | 18 +- libwebauthn/src/ops/webauthn/mod.rs | 2 +- libwebauthn/src/ops/webauthn/timeout.rs | 3 + .../src/proto/ctap2/model/get_assertion.rs | 112 ++++---- 14 files changed, 373 insertions(+), 131 deletions(-) create mode 100644 libwebauthn/src/ops/webauthn/timeout.rs diff --git a/libwebauthn/examples/prf_test.rs b/libwebauthn/examples/prf_test.rs index 22b2b4dc..d0098f77 100644 --- a/libwebauthn/examples/prf_test.rs +++ b/libwebauthn/examples/prf_test.rs @@ -13,7 +13,7 @@ use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ Base64UrlString, GetAssertionHmacOrPrfInput, GetAssertionRequest, - GetAssertionRequestExtensions, PRFValue, UserVerificationRequirement, + GetAssertionRequestExtensions, PRFValue, PrfInput, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}; @@ -125,10 +125,11 @@ pub async fn main() -> Result<(), Box> { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); + run_success_test( &mut channel, &credential, @@ -153,10 +154,10 @@ async fn run_success_test( hash: Vec::from(challenge), allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, - extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf, + extensions: GetAssertionRequestExtensions { + hmac_or_prf: Some(hmac_or_prf), ..Default::default() - }), + }, timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_cable.rs b/libwebauthn/examples/webauthn_cable.rs index f6ae8574..d2b933a8 100644 --- a/libwebauthn/examples/webauthn_cable.rs +++ b/libwebauthn/examples/webauthn_cable.rs @@ -19,7 +19,8 @@ use tokio::time::sleep; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, MakeCredentialRequest, ResidentKeyRequirement, UserVerificationRequirement, + GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialRequest, + ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::proto::ctap2::{ Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, @@ -161,7 +162,7 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: None, + extensions: GetAssertionRequestExtensions::default(), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_extensions_hid.rs b/libwebauthn/examples/webauthn_extensions_hid.rs index ecd79f24..4b4c8317 100644 --- a/libwebauthn/examples/webauthn_extensions_hid.rs +++ b/libwebauthn/examples/webauthn_extensions_hid.rs @@ -147,14 +147,16 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: Some(GetAssertionRequestExtensions { - cred_blob: Some(true), - hmac_or_prf: GetAssertionHmacOrPrfInput::HmacGetSecret(HMACGetSecretInput { - salt1: [1; 32], - salt2: None, - }), + extensions: GetAssertionRequestExtensions { + cred_blob: true, + hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( + HMACGetSecretInput { + salt1: [1; 32], + salt2: None, + }, + )), ..Default::default() - }), + }, timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_hid.rs b/libwebauthn/examples/webauthn_hid.rs index e1dd6e23..5ca4a25b 100644 --- a/libwebauthn/examples/webauthn_hid.rs +++ b/libwebauthn/examples/webauthn_hid.rs @@ -10,7 +10,8 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, MakeCredentialRequest, ResidentKeyRequirement, UserVerificationRequirement, + GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialRequest, + ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -128,7 +129,7 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: None, + extensions: GetAssertionRequestExtensions::default(), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_json_hid.rs b/libwebauthn/examples/webauthn_json_hid.rs index 4b41fb79..d9d6d545 100644 --- a/libwebauthn/examples/webauthn_json_hid.rs +++ b/libwebauthn/examples/webauthn_json_hid.rs @@ -10,8 +10,8 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, MakeCredentialRequest, RelyingPartyId, UserVerificationRequirement, - WebAuthnIDL as _, + GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialRequest, RelyingPartyId, + UserVerificationRequirement, WebAuthnIDL as _, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; @@ -144,7 +144,7 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: None, + extensions: GetAssertionRequestExtensions::default(), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_preflight_hid.rs b/libwebauthn/examples/webauthn_preflight_hid.rs index 4c62ec12..3a5e5ec6 100644 --- a/libwebauthn/examples/webauthn_preflight_hid.rs +++ b/libwebauthn/examples/webauthn_preflight_hid.rs @@ -10,8 +10,8 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - Base64UrlString, GetAssertionRequest, GetAssertionResponse, MakeCredentialRequest, - ResidentKeyRequirement, UserVerificationRequirement, + Base64UrlString, GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, + MakeCredentialRequest, ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -201,7 +201,7 @@ async fn get_assertion_call( hash: Vec::from(challenge), allow: allow_list, user_verification: UserVerificationRequirement::Discouraged, - extensions: None, + extensions: GetAssertionRequestExtensions::default(), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_prf_hid.rs b/libwebauthn/examples/webauthn_prf_hid.rs index 2122f691..ce244a2f 100644 --- a/libwebauthn/examples/webauthn_prf_hid.rs +++ b/libwebauthn/examples/webauthn_prf_hid.rs @@ -14,7 +14,7 @@ use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue, - ResidentKeyRequirement, UserVerificationRequirement, + PrfInput, ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -148,10 +148,10 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( &mut channel, &credential, @@ -175,10 +175,10 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( &mut channel, &credential, @@ -195,10 +195,10 @@ pub async fn main() -> Result<(), Box> { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( &mut channel, &credential, @@ -243,10 +243,10 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( &mut channel, &credential, @@ -284,10 +284,10 @@ pub async fn main() -> Result<(), Box> { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( &mut channel, &credential, @@ -322,10 +322,10 @@ pub async fn main() -> Result<(), Box> { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( &mut channel, &credential, @@ -349,10 +349,10 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_failed_test( &mut channel, Some(&credential), @@ -373,10 +373,10 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_failed_test( &mut channel, Some(&credential), @@ -397,10 +397,10 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_failed_test( &mut channel, None, @@ -426,10 +426,10 @@ async fn run_success_test( hash: Vec::from(challenge), allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Discouraged, - extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf, + extensions: GetAssertionRequestExtensions { + hmac_or_prf: Some(hmac_or_prf), ..Default::default() - }), + }, timeout: TIMEOUT, }; @@ -468,10 +468,10 @@ async fn run_failed_test( hash: Vec::from(challenge), allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, - extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf, + extensions: GetAssertionRequestExtensions { + hmac_or_prf: Some(hmac_or_prf), ..Default::default() - }), + }, timeout: TIMEOUT, }; diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index 1cce9e2a..8df32c65 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -10,7 +10,8 @@ use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; use crate::ops::webauthn::idl::Base64UrlString; use crate::ops::webauthn::{ - GetAssertionRequest, GetAssertionResponse, MakeCredentialResponse, UserVerificationRequirement, + GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, + MakeCredentialResponse, UserVerificationRequirement, }; use crate::proto::ctap1::{Ctap1RegisterRequest, Ctap1SignRequest}; use crate::proto::ctap1::{Ctap1RegisterResponse, Ctap1SignResponse}; @@ -207,7 +208,7 @@ impl UpgradableResponse for SignResponse { id: request.key_handle.clone().into(), transports: None, }], - extensions: None, + extensions: GetAssertionRequestExtensions::default(), user_verification: if request.require_user_presence { UserVerificationRequirement::Required } else { diff --git a/libwebauthn/src/ops/webauthn/create.rs b/libwebauthn/src/ops/webauthn/create.rs index 7f98ad19..74a957fa 100644 --- a/libwebauthn/src/ops/webauthn/create.rs +++ b/libwebauthn/src/ops/webauthn/create.rs @@ -40,7 +40,7 @@ pub struct PublicKeyCredentialCreationOptionsJSON { pub challenge: Base64UrlString, #[serde(rename = "pubKeyCredParams")] pub params: Vec, - pub timeout: u32, + pub timeout: Option, #[serde(rename = "excludeCredentials")] pub exclude_credentials: Vec, #[serde(rename = "authenticatorSelection")] diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 336ff005..13a8127b 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -6,6 +6,10 @@ use tracing::{debug, error, trace}; use crate::{ fido::AuthenticatorData, + ops::webauthn::{ + idl::{FromInnerModel, JsonError}, + Base64UrlString, WebAuthnIDL, + }, pin::PinUvAuthProtocol, proto::ctap2::{ Ctap2AttestationStatement, Ctap2GetAssertionResponseExtensions, @@ -14,7 +18,9 @@ use crate::{ webauthn::CtapError, }; -use super::{DowngradableRequest, SignRequest, UserVerificationRequirement}; +use super::{DowngradableRequest, RelyingPartyId, SignRequest, UserVerificationRequirement}; + +pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); #[derive(Debug, Default, Clone, Serialize)] pub struct PRFValue { @@ -29,20 +35,118 @@ pub struct GetAssertionRequest { pub relying_party_id: String, pub hash: Vec, pub allow: Vec, - pub extensions: Option, + pub extensions: GetAssertionRequestExtensions, pub user_verification: UserVerificationRequirement, pub timeout: Duration, } -#[derive(Debug, Default, Clone)] +#[derive(thiserror::Error, Debug)] +pub enum GetAssertionRequestParsingError { + /// The client must throw an "EncodingError" DOMException. + #[error("Invalid JSON format: {0}")] + EncodingError(#[from] JsonError), + + #[error("Unexpected length for {0}: {1}")] + UnexpectedLengthError(String, usize), + + #[error("Not supported: {0}")] + NotSupported(String), +} + +impl WebAuthnIDL for GetAssertionRequest { + type Error = GetAssertionRequestParsingError; + type InnerModel = PublicKeyCredentialRequestOptionsJSON; +} + +/** dictionary PublicKeyCredentialRequestOptionsJSON { + required Base64URLString challenge; + unsigned long timeout; + DOMString rpId; + sequence allowCredentials = []; + DOMString userVerification = "preferred"; + sequence hints = []; + AuthenticationExtensionsClientInputsJSON extensions; +}; */ + +#[derive(Deserialize, Debug, Clone)] +pub struct PublicKeyCredentialRequestOptionsJSON { + pub challenge: Base64UrlString, + pub timeout: Option, + #[serde(rename = "rpId")] + pub relying_party_id: Option, + #[serde(rename = "allowCredentials")] + #[serde(default)] + pub allow_credentials: Vec, + #[serde(rename = "userVerification")] + pub uv_requirement: UserVerificationRequirement, + #[serde(default)] + pub hints: Vec, + pub extensions: Option, +} + +impl FromInnerModel + for GetAssertionRequest +{ + fn from_inner_model( + rpid: &RelyingPartyId, + inner: PublicKeyCredentialRequestOptionsJSON, + ) -> Result { + let hmac_or_prf = match inner.extensions.clone() { + Some(ext) => { + if let Some(prf) = ext.prf { + let prf_input = PrfInput::try_from(prf)?; + Some(GetAssertionHmacOrPrfInput::Prf(prf_input)) + } else if let Some(hmac) = ext.hamc_get_secret { + let hmac_input = HMACGetSecretInput::try_from(hmac)?; + Some(GetAssertionHmacOrPrfInput::HmacGetSecret(hmac_input)) + } else { + None + } + } + None => None, + }; + + let extensions_opt = inner.extensions.clone(); + let extensions = GetAssertionRequestExtensions { + cred_blob: extensions_opt + .as_ref() + .and_then(|ext| ext.cred_blob) + .unwrap_or(false), + large_blob: extensions_opt + .as_ref() + .and_then(|ext| ext.large_blob.clone()) + .map(Option::::try_from) + .transpose()? + .flatten(), + hmac_or_prf, + }; + + let timeout: Duration = inner + .timeout + .map(|s| Duration::from_secs(s.into())) + .unwrap_or(DEFAULT_TIMEOUT); + + Ok(GetAssertionRequest { + relying_party_id: rpid.to_string(), + hash: inner.challenge.into(), + allow: inner.allow_credentials, + extensions, + user_verification: inner.uv_requirement, + timeout, + }) + } +} + +#[derive(Debug, Clone)] pub enum GetAssertionHmacOrPrfInput { - #[default] - None, HmacGetSecret(HMACGetSecretInput), - Prf { - eval: Option, - eval_by_credential: HashMap, - }, + Prf(PrfInput), +} + +#[derive(Debug, Clone)] +pub struct PrfInput { + pub eval: Option, + pub eval_by_credential: HashMap, } #[derive(Debug, Default, Clone, Serialize)] @@ -57,15 +161,132 @@ pub struct HMACGetSecretInput { pub salt2: Option<[u8; 32]>, } -#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Deserialize)] +pub struct HmacGetSecretInputJson { + pub salt1: Base64UrlString, + pub salt2: Option, +} + +impl TryFrom for HMACGetSecretInput { + type Error = GetAssertionRequestParsingError; + + fn try_from(value: HmacGetSecretInputJson) -> Result { + let salt1 = value.salt1.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.hmacCreateSecret.salt1".to_string(), + value.salt1.as_slice().len(), + ) + })?; + let salt2 = match value.salt2 { + Some(s) => Some(s.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.hmacCreateSecret.salt2".to_string(), + s.as_slice().len(), + ) + })?), + None => None, + }; + Ok(HMACGetSecretInput { salt1, salt2 }) + } +} +#[derive(Debug, Clone, Deserialize)] +pub struct LargeBlobInputJson { + pub read: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct PrfInputJson { + pub eval: Option, + pub eval_by_credential: Option>, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct PrfValuesJson { + pub first: Base64UrlString, + pub second: Option, +} + +impl TryFrom for PrfInput { + type Error = GetAssertionRequestParsingError; + + fn try_from(value: PrfInputJson) -> Result { + let eval = match value.eval { + Some(value) => Some(PRFValue { + first: value.first.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.prf.eval.first".to_string(), + value.first.as_slice().len(), + ) + })?, + second: match value.second { + Some(s) => Some(s.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.prf.eval.second".to_string(), + s.as_slice().len(), + ) + })?), + None => None, + }, + }), + None => None, + }; + let eval_by_credential = match value.eval_by_credential { + Some(map) => map + .into_iter() + .map(|(k, v)| { + Ok(( + k, + PRFValue { + first: v.first.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.prf.eval_by_credential[i].first".to_string(), + v.first.as_slice().len(), + ) + })?, + second: match v.second { + Some(s) => Some(s.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.prf.eval_by_credential[i].second".to_string(), + s.as_slice().len(), + ) + })?), + None => None, + }, + }, + )) + }) + .collect::, GetAssertionRequestParsingError>>()?, + None => HashMap::new(), + }; + + Ok(PrfInput { + eval, + eval_by_credential, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] pub enum GetAssertionLargeBlobExtension { - #[default] - None, Read, // Not yet supported // Write(Vec), } +impl TryFrom for Option { + type Error = GetAssertionRequestParsingError; + + fn try_from(value: LargeBlobInputJson) -> Result { + match value.read { + Some(true) => Ok(Some(GetAssertionLargeBlobExtension::Read)), + Some(false) => Err(GetAssertionRequestParsingError::NotSupported( + "largeBlob writes not supported".to_string(), + )), + None => Ok(None), + } + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)] pub struct GetAssertionLargeBlobExtensionOutput { #[serde(skip_serializing_if = "Option::is_none")] @@ -77,9 +298,21 @@ pub struct GetAssertionLargeBlobExtensionOutput { #[derive(Debug, Default, Clone)] pub struct GetAssertionRequestExtensions { + pub cred_blob: bool, + pub hmac_or_prf: Option, + pub large_blob: Option, +} + +#[derive(Debug, Clone, Default, Deserialize)] +pub struct GetAssertionRequestExtensionsJSON { + #[serde(rename = "getCredBlob")] pub cred_blob: Option, - pub hmac_or_prf: GetAssertionHmacOrPrfInput, - pub large_blob: GetAssertionLargeBlobExtension, + #[serde(rename = "largeBlobKey")] + pub large_blob: Option, + #[serde(rename = "hmacCreateSecret")] + pub hamc_get_secret: Option, + #[serde(rename = "prf")] + pub prf: Option, } #[derive(Clone, Debug, Default, Serialize)] diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 7bae1623..d6b49e35 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -26,6 +26,8 @@ use crate::{ use super::{DowngradableRequest, RegisterRequest, UserVerificationRequirement}; +pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); + #[derive(Debug, Clone)] pub struct MakeCredentialResponse { pub format: String, @@ -217,10 +219,10 @@ impl FromInnerModel None, - _ => Some(inner.exclude_credentials), - }; + let timeout: Duration = inner + .timeout + .map(|s| Duration::from_secs(s.into())) + .unwrap_or(DEFAULT_TIMEOUT); Ok(Self { hash: inner.challenge.into(), @@ -230,9 +232,13 @@ impl FromInnerModel Result { // Cloning it, so we can modify it let mut req = req.clone(); - if let Some(ext) = req.extensions.as_mut() { - // LargeBlob (NOTE: Not to be confused with LargeBlobKey) - // https://w3c.github.io/webauthn/#sctn-large-blob-extension - // If read is present and has the value true: - // [..] - // 3. If successful, set blob to the result. - // - // So we silently drop the extension if the device does not support it. - if !info.option_enabled("largeBlobs") { - ext.large_blob = GetAssertionLargeBlobExtension::None; - } + // LargeBlob (NOTE: Not to be confused with LargeBlobKey) + // https://w3c.github.io/webauthn/#sctn-large-blob-extension + // If read is present and has the value true: + // [..] + // 3. If successful, set blob to the result. + // + // So we silently drop the extension if the device does not support it. + if !info.option_enabled("largeBlobs") { + req.extensions.large_blob = None; } + Ok(Ctap2GetAssertionRequest::from(req)) } } @@ -174,7 +173,7 @@ impl From for Ctap2GetAssertionRequest { relying_party_id: op.relying_party_id, client_data_hash: ByteBuf::from(op.hash), allow: op.allow, - extensions: op.extensions.map(|x| x.into()), + extensions: Some(op.extensions.into()), options: Some(Ctap2GetAssertionOptions { require_user_presence: true, require_user_verification: op.user_verification.is_required(), @@ -185,11 +184,11 @@ impl From for Ctap2GetAssertionRequest { } } -#[derive(Debug, Default, Clone, Serialize)] +#[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct Ctap2GetAssertionRequestExtensions { - #[serde(skip_serializing_if = "Option::is_none")] - pub cred_blob: Option, + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub cred_blob: bool, // Thanks, FIDO-spec for this consistent naming scheme... #[serde(rename = "hmac-secret", skip_serializing_if = "Option::is_none")] pub hmac_secret: Option, @@ -197,16 +196,16 @@ pub struct Ctap2GetAssertionRequestExtensions { #[serde(skip_serializing_if = "Option::is_none")] pub large_blob_key: Option, #[serde(skip)] - pub hmac_or_prf: GetAssertionHmacOrPrfInput, + pub hmac_or_prf: Option, } impl From for Ctap2GetAssertionRequestExtensions { fn from(other: GetAssertionRequestExtensions) -> Self { Ctap2GetAssertionRequestExtensions { cred_blob: other.cred_blob, - hmac_secret: None, // Get's calculated later + hmac_secret: None, // Gets calculated later hmac_or_prf: other.hmac_or_prf, - large_blob_key: if other.large_blob == GetAssertionLargeBlobExtension::Read { + large_blob_key: if other.large_blob == Some(GetAssertionLargeBlobExtension::Read) { Some(true) } else { None @@ -217,7 +216,10 @@ impl From for Ctap2GetAssertionRequestExtensions impl Ctap2GetAssertionRequestExtensions { pub fn skip_serializing(&self) -> bool { - self.cred_blob.is_none() && self.hmac_secret.is_none() + !self.cred_blob + && self.hmac_secret.is_none() + && self.large_blob_key.is_none() + && self.hmac_or_prf.is_none() } pub fn calculate_hmac( @@ -226,14 +228,13 @@ impl Ctap2GetAssertionRequestExtensions { auth_data: &AuthTokenData, ) -> Result<(), Error> { let input = match &self.hmac_or_prf { - GetAssertionHmacOrPrfInput::None => None, - GetAssertionHmacOrPrfInput::HmacGetSecret(hmacget_secret_input) => { - Some(hmacget_secret_input.clone()) + None => None, + Some(GetAssertionHmacOrPrfInput::HmacGetSecret(hmac_get_secret_input)) => { + Some(hmac_get_secret_input.clone()) + } + Some(GetAssertionHmacOrPrfInput::Prf(prf_input)) => { + Self::prf_to_hmac_input(&prf_input.eval, &prf_input.eval_by_credential, allow_list)? } - GetAssertionHmacOrPrfInput::Prf { - eval, - eval_by_credential, - } => Self::prf_to_hmac_input(eval, eval_by_credential, allow_list)?, }; let input = match input { @@ -506,44 +507,37 @@ impl Ctap2GetAssertionResponseExtensions { response: &Ctap2GetAssertionResponse, auth_data: Option<&AuthTokenData>, ) -> GetAssertionResponseUnsignedExtensions { - let (hmac_get_secret, prf) = if let Some(orig_ext) = &request.extensions { - // Decrypt the raw HMAC extension - let decrypted_hmac = self.hmac_secret.as_ref().and_then(|x| { - if let Some(auth_data) = auth_data { - let uv_proto = auth_data.protocol_version.create_protocol_object(); - x.decrypt_output(&auth_data.shared_secret, &uv_proto) - } else { - None - } - }); - if let Some(decrypted) = decrypted_hmac { - // Repackaging it into output - match &orig_ext.hmac_or_prf { - GetAssertionHmacOrPrfInput::None => (None, None), - GetAssertionHmacOrPrfInput::HmacGetSecret(..) => (Some(decrypted), None), - GetAssertionHmacOrPrfInput::Prf { .. } => ( - None, - Some(GetAssertionPrfOutput { - results: Some(PRFValue { - first: decrypted.output1, - second: decrypted.output2, - }), - }), - ), - } + let decrypted_hmac = self.hmac_secret.as_ref().and_then(|x| { + if let Some(auth_data) = auth_data { + let uv_proto = auth_data.protocol_version.create_protocol_object(); + x.decrypt_output(&auth_data.shared_secret, &uv_proto) } else { - (None, None) + None + } + }); + + let (hmac_get_secret, prf) = if let Some(decrypted) = decrypted_hmac { + match &request.extensions.hmac_or_prf { + None => (None, None), + Some(GetAssertionHmacOrPrfInput::HmacGetSecret(..)) => (Some(decrypted), None), + Some(GetAssertionHmacOrPrfInput::Prf(..)) => ( + None, + Some(GetAssertionPrfOutput { + results: Some(PRFValue { + first: decrypted.output1, + second: decrypted.output2, + }), + }), + ), } } else { (None, None) }; // LargeBlobs was requested - let large_blob = request - .extensions - .as_ref() - .filter(|x| x.large_blob != GetAssertionLargeBlobExtension::None) - .map(|_| { + let large_blob = match request.extensions.large_blob { + None => None, + Some(GetAssertionLargeBlobExtension::Read) => { Some(GetAssertionLargeBlobExtensionOutput { blob: response .large_blob_key @@ -552,8 +546,8 @@ impl Ctap2GetAssertionResponseExtensions { // Not yet supported // written: None, }) - }) - .unwrap_or_default(); + } + }; GetAssertionResponseUnsignedExtensions { hmac_get_secret, From 560cf98ceca6b5caf2421a3fa55365f57b4afc63 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 24 Aug 2025 16:48:58 +0100 Subject: [PATCH 06/28] Change back CTAP2 credential model to ByteBuf --- libwebauthn/examples/prf_test.rs | 7 +++-- .../examples/webauthn_preflight_hid.rs | 5 +-- libwebauthn/src/fido.rs | 31 +++++++------------ libwebauthn/src/ops/u2f.rs | 3 +- libwebauthn/src/proto/ctap2/model.rs | 7 ++--- .../src/proto/ctap2/model/get_assertion.rs | 2 +- 6 files changed, 23 insertions(+), 32 deletions(-) diff --git a/libwebauthn/examples/prf_test.rs b/libwebauthn/examples/prf_test.rs index d0098f77..fc61e498 100644 --- a/libwebauthn/examples/prf_test.rs +++ b/libwebauthn/examples/prf_test.rs @@ -7,13 +7,14 @@ use std::time::Duration; use libwebauthn::transport::hid::channel::HidChannel; use libwebauthn::UvUpdate; use rand::{thread_rng, Rng}; +use serde_bytes::ByteBuf; use text_io::read; use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - Base64UrlString, GetAssertionHmacOrPrfInput, GetAssertionRequest, - GetAssertionRequestExtensions, PRFValue, PrfInput, UserVerificationRequirement, + GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, PRFValue, + PrfInput, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}; @@ -114,7 +115,7 @@ pub async fn main() -> Result<(), Box> { let credential = Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: Base64UrlString::from(credential_id.as_slice()), + id: ByteBuf::from(credential_id.as_slice()), transports: None, }; diff --git a/libwebauthn/examples/webauthn_preflight_hid.rs b/libwebauthn/examples/webauthn_preflight_hid.rs index 3a5e5ec6..5fd54b59 100644 --- a/libwebauthn/examples/webauthn_preflight_hid.rs +++ b/libwebauthn/examples/webauthn_preflight_hid.rs @@ -5,12 +5,13 @@ use std::time::Duration; use libwebauthn::UvUpdate; use rand::{thread_rng, Rng}; +use serde_bytes::ByteBuf; use text_io::read; use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - Base64UrlString, GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, + GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, MakeCredentialRequest, ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; @@ -224,7 +225,7 @@ async fn get_assertion_call( fn create_credential(id: &[u8]) -> Ctap2PublicKeyCredentialDescriptor { Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: Base64UrlString::from(id), + id: ByteBuf::from(id), transports: None, } } diff --git a/libwebauthn/src/fido.rs b/libwebauthn/src/fido.rs index a56a2a98..532a08a1 100644 --- a/libwebauthn/src/fido.rs +++ b/libwebauthn/src/fido.rs @@ -4,6 +4,7 @@ use serde::{ de::{DeserializeOwned, Error as DesError, Visitor}, Deserialize, Deserializer, Serialize, }; +use serde_bytes::ByteBuf; use std::{ fmt, io::{Cursor, Read}, @@ -11,7 +12,7 @@ use std::{ }; use tracing::{error, warn}; -use crate::{ops::webauthn::idl::Base64UrlString, proto::ctap2::cbor}; +use crate::proto::ctap2::cbor; use crate::{ proto::{ ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}, @@ -68,7 +69,7 @@ impl From<&AttestedCredentialData> for Ctap2PublicKeyCredentialDescriptor { fn from(data: &AttestedCredentialData) -> Self { Self { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: Base64UrlString::from(data.credential_id.clone()), + id: ByteBuf::from(data.credential_id.clone()), transports: None, } } @@ -272,11 +273,10 @@ mod tests { 0x86, 0xce, 0x19, 0x47, ]; let flag_bits = 0b1100_0101; - let flags = - AuthenticatorDataFlags::USER_PRESENT | - AuthenticatorDataFlags::USER_VERIFIED | - AuthenticatorDataFlags::ATTESTED_CREDENTIALS | - AuthenticatorDataFlags::EXTENSION_DATA; + let flags = AuthenticatorDataFlags::USER_PRESENT + | AuthenticatorDataFlags::USER_VERIFIED + | AuthenticatorDataFlags::ATTESTED_CREDENTIALS + | AuthenticatorDataFlags::EXTENSION_DATA; assert_eq!(flag_bits, flags.bits()); let signature_count = 0; let aaguid = [ @@ -315,7 +315,7 @@ mod tests { flags, signature_count, attested_credential: Some(attested_credential.clone()), - extensions: Some(extensions.clone()) + extensions: Some(extensions.clone()), }; let webauthn_auth_data = auth_data.to_response_bytes().unwrap(); assert_eq!(rp_id_hash, &webauthn_auth_data[..32]); @@ -340,14 +340,8 @@ mod tests { let authdata_wrapped = cbor::to_vec(&ByteBuf::from(webauthn_auth_data)).unwrap(); let auth_data_reparsed: AuthenticatorData = cbor::from_slice(authdata_wrapped.as_slice()).unwrap(); - assert_eq!( - auth_data.rp_id_hash, - auth_data_reparsed.rp_id_hash - ); - assert_eq!( - auth_data.flags.bits(), - auth_data_reparsed.flags.bits() - ); + assert_eq!(auth_data.rp_id_hash, auth_data_reparsed.rp_id_hash); + assert_eq!(auth_data.flags.bits(), auth_data_reparsed.flags.bits()); assert_eq!( auth_data.signature_count, auth_data_reparsed.signature_count @@ -365,9 +359,6 @@ mod tests { attested_credential.credential_public_key, attested_credential_reparsed.credential_public_key ); - assert_eq!( - extensions, - auth_data_reparsed.extensions.unwrap() - ); + assert_eq!(extensions, auth_data_reparsed.extensions.unwrap()); } } diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index 8df32c65..0b6b43f5 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -8,7 +8,6 @@ use x509_parser::nom::AsBytes; use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; -use crate::ops::webauthn::idl::Base64UrlString; use crate::ops::webauthn::{ GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, MakeCredentialResponse, UserVerificationRequirement, @@ -185,7 +184,7 @@ impl UpgradableResponse for SignResponse { let response = Ctap2GetAssertionResponse { credential_id: Some(Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: Base64UrlString::from(request.key_handle.clone()), + id: ByteBuf::from(request.key_handle.clone()), transports: None, }), authenticator_data, diff --git a/libwebauthn/src/proto/ctap2/model.rs b/libwebauthn/src/proto/ctap2/model.rs index 5dbeed27..ebf219b6 100644 --- a/libwebauthn/src/proto/ctap2/model.rs +++ b/libwebauthn/src/proto/ctap2/model.rs @@ -1,4 +1,3 @@ -use crate::ops::webauthn::idl::Base64UrlString; use crate::pin::PinUvAuthProtocol; use crate::proto::ctap1::Ctap1Transport; @@ -149,7 +148,7 @@ impl From<&Ctap1Transport> for Ctap2Transport { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Ctap2PublicKeyCredentialDescriptor { - pub id: Base64UrlString, + pub id: ByteBuf, pub r#type: Ctap2PublicKeyCredentialType, #[serde(skip_serializing_if = "Option::is_none")] @@ -228,12 +227,12 @@ pub enum Ctap2UserVerificationOperation { #[cfg(test)] mod tests { - use crate::ops::webauthn::idl::Base64UrlString; use crate::proto::ctap2::cbor; use crate::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; use super::{Ctap2COSEAlgorithmIdentifier, Ctap2CredentialType, Ctap2PublicKeyCredentialType}; use hex; + use serde_bytes::ByteBuf; use serde_cbor_2 as serde_cbor; #[test] @@ -253,7 +252,7 @@ mod tests { /// Verify CBOR serialization conforms to CTAP canonical standard, including ordering (see #95) pub fn credential_descriptor_serialization() { let credential_descriptor = Ctap2PublicKeyCredentialDescriptor { - id: Base64UrlString::from(vec![0x42]), + id: ByteBuf::from(vec![0x42]), r#type: Ctap2PublicKeyCredentialType::PublicKey, transports: None, }; diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index fc2897c0..b0589a39 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -303,7 +303,7 @@ impl Ctap2GetAssertionRequestExtensions { .map_err(|_| Error::Platform(PlatformError::SyntaxError))?; // 4.1 If evalByCredential is present and contains an entry whose key is the base64url encoding of the credential ID that will be returned, let ev be the value of that entry. - let found_cred_id = allow_list.iter().find(|x| x.id.0 == cred_id); + let found_cred_id = allow_list.iter().find(|x| x.id == cred_id); if found_cred_id.is_some() { ev = Some(prf_value); break; From 56f3436f97d57f1142c48e61a4c8ba649cd477ff Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 24 Aug 2025 19:05:20 +0100 Subject: [PATCH 07/28] Fixes and test for MC --- libwebauthn/src/ops/webauthn/client_data.rs | 36 ++++++ .../ops/webauthn/{idl.rs => idl/base64url.rs} | 34 +---- .../src/ops/webauthn/{ => idl}/create.rs | 13 +- libwebauthn/src/ops/webauthn/idl/mod.rs | 38 ++++++ .../src/ops/webauthn/{ => idl}/rpid.rs | 0 .../src/ops/webauthn/make_credential.rs | 117 ++++++++++++++++-- libwebauthn/src/ops/webauthn/mod.rs | 16 ++- libwebauthn/src/proto/ctap2/model.rs | 14 ++- 8 files changed, 212 insertions(+), 56 deletions(-) create mode 100644 libwebauthn/src/ops/webauthn/client_data.rs rename libwebauthn/src/ops/webauthn/{idl.rs => idl/base64url.rs} (56%) rename libwebauthn/src/ops/webauthn/{ => idl}/create.rs (86%) create mode 100644 libwebauthn/src/ops/webauthn/idl/mod.rs rename libwebauthn/src/ops/webauthn/{ => idl}/rpid.rs (100%) diff --git a/libwebauthn/src/ops/webauthn/client_data.rs b/libwebauthn/src/ops/webauthn/client_data.rs new file mode 100644 index 00000000..9145a480 --- /dev/null +++ b/libwebauthn/src/ops/webauthn/client_data.rs @@ -0,0 +1,36 @@ +use crate::ops::webauthn::Operation; + +use serde::Deserialize; +use sha2::{Digest, Sha256}; + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct ClientData { + pub operation: Operation, + pub challenge: Vec, + pub origin: String, + #[serde(rename = "crossOrigin")] + pub cross_origin: Option, +} + +impl ClientData { + pub fn hash(&self) -> Vec { + let op_str = match &self.operation { + Operation::MakeCredential => "webauthn.create", + Operation::GetAssertion => "webauthn.get", + }; + let challenge_str = base64_url::encode(&self.challenge); + let origin_str = &self.origin; + let cross_origin_str = if self.cross_origin.unwrap_or(false) { + "true" + } else { + "false" + }; + let json = + format!("{{\"type\":\"{op_str}\",\"challenge\":\"{challenge_str}\",\"origin\":\"{origin_str}\",\"crossOrigin\":{cross_origin_str}}}"); + + let mut hasher = Sha256::new(); + hasher.update(json.as_bytes()); + hasher.finalize().to_vec() + } +} + diff --git a/libwebauthn/src/ops/webauthn/idl.rs b/libwebauthn/src/ops/webauthn/idl/base64url.rs similarity index 56% rename from libwebauthn/src/ops/webauthn/idl.rs rename to libwebauthn/src/ops/webauthn/idl/base64url.rs index b7552dd0..8d5e43e4 100644 --- a/libwebauthn/src/ops/webauthn/idl.rs +++ b/libwebauthn/src/ops/webauthn/idl/base64url.rs @@ -1,40 +1,8 @@ use std::ops::Deref; use base64_url; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json; +use serde::{Deserialize, Serialize}; -use super::rpid::RelyingPartyId; - -pub type JsonError = serde_json::Error; - -pub trait WebAuthnIDL: Sized -where - E: std::error::Error, // Validation error type. - Self: FromInnerModel, -{ - /// An error type that can be returned when deserializing from JSON, including - /// JSON parsing errors and any additional validation errors. - type Error: std::error::Error + From + From; - - /// The JSON model that this IDL can deserialize from. - type InnerModel: DeserializeOwned; - - fn from_json(rpid: &RelyingPartyId, json: &str) -> Result { - let inner_model: Self::InnerModel = serde_json::from_str(json)?; - Self::from_inner_model(rpid, inner_model).map_err(From::from) - } -} - -pub trait FromInnerModel: Sized -where - T: DeserializeOwned, - E: std::error::Error, -{ - fn from_inner_model(rpid: &RelyingPartyId, inner: T) -> Result; -} - -// TODO(afresta): Move to ctap2 module. #[derive(Debug, Clone, PartialEq)] pub struct Base64UrlString(pub Vec); diff --git a/libwebauthn/src/ops/webauthn/create.rs b/libwebauthn/src/ops/webauthn/idl/create.rs similarity index 86% rename from libwebauthn/src/ops/webauthn/create.rs rename to libwebauthn/src/ops/webauthn/idl/create.rs index 74a957fa..c2bf23c4 100644 --- a/libwebauthn/src/ops/webauthn/create.rs +++ b/libwebauthn/src/ops/webauthn/idl/create.rs @@ -1,11 +1,10 @@ -use super::idl::Base64UrlString; +use super::Base64UrlString; use crate::{ ops::webauthn::{ MakeCredentialsRequestExtensions, ResidentKeyRequirement, UserVerificationRequirement, }, proto::ctap2::{ Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, - Ctap2PublicKeyCredentialUserEntity, }, }; @@ -33,10 +32,18 @@ fn default_user_verification() -> UserVerificationRequirement { UserVerificationRequirement::Preferred } +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct PublicKeyCredentialUserEntity { + pub id: Base64UrlString, + pub name: String, + #[serde(rename = "displayName")] + pub display_name: String, +} + #[derive(Debug, Clone, Deserialize)] pub struct PublicKeyCredentialCreationOptionsJSON { pub rp: Ctap2PublicKeyCredentialRpEntity, - pub user: Ctap2PublicKeyCredentialUserEntity, + pub user: PublicKeyCredentialUserEntity, pub challenge: Base64UrlString, #[serde(rename = "pubKeyCredParams")] pub params: Vec, diff --git a/libwebauthn/src/ops/webauthn/idl/mod.rs b/libwebauthn/src/ops/webauthn/idl/mod.rs new file mode 100644 index 00000000..bee20f31 --- /dev/null +++ b/libwebauthn/src/ops/webauthn/idl/mod.rs @@ -0,0 +1,38 @@ +mod base64url; +pub mod create; +pub mod rpid; + +pub use base64url::Base64UrlString; + +use rpid::RelyingPartyId; + +use serde::de::DeserializeOwned; +use serde_json; + +pub type JsonError = serde_json::Error; + +pub trait WebAuthnIDL: Sized +where + E: std::error::Error, // Validation error type. + Self: FromInnerModel, +{ + /// An error type that can be returned when deserializing from JSON, including + /// JSON parsing errors and any additional validation errors. + type Error: std::error::Error + From + From; + + /// The JSON model that this IDL can deserialize from. + type InnerModel: DeserializeOwned; + + fn from_json(rpid: &RelyingPartyId, json: &str) -> Result { + let inner_model: Self::InnerModel = serde_json::from_str(json)?; + Self::from_inner_model(rpid, inner_model).map_err(From::from) + } +} + +pub trait FromInnerModel: Sized +where + T: DeserializeOwned, + E: std::error::Error, +{ + fn from_inner_model(rpid: &RelyingPartyId, inner: T) -> Result; +} diff --git a/libwebauthn/src/ops/webauthn/rpid.rs b/libwebauthn/src/ops/webauthn/idl/rpid.rs similarity index 100% rename from libwebauthn/src/ops/webauthn/rpid.rs rename to libwebauthn/src/ops/webauthn/idl/rpid.rs diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index d6b49e35..f35f6e41 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -9,9 +9,12 @@ use tracing::{debug, instrument, trace}; use crate::{ fido::AuthenticatorData, ops::webauthn::{ - create::PublicKeyCredentialCreationOptionsJSON, - idl::{Base64UrlString, FromInnerModel, JsonError, WebAuthnIDL}, - rpid::RelyingPartyId, + client_data::ClientData, + idl::{ + create::PublicKeyCredentialCreationOptionsJSON, Base64UrlString, FromInnerModel, + JsonError, WebAuthnIDL, + }, + Operation, RelyingPartyId, }, proto::{ ctap1::{Ctap1RegisteredKey, Ctap1Version}, @@ -162,7 +165,7 @@ impl MakeCredentialsResponseUnsignedExtensions { } } -#[derive(Debug, Clone, Copy, Deserialize)] +#[derive(Debug, Clone, Copy, Deserialize, PartialEq)] pub enum ResidentKeyRequirement { #[serde(rename = "required")] Required, @@ -172,7 +175,7 @@ pub enum ResidentKeyRequirement { Discouraged, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct MakeCredentialRequest { pub hash: Vec, pub origin: String, @@ -221,14 +224,21 @@ impl FromInnerModel for MakeCredentialRequest { type InnerModel = PublicKeyCredentialCreationOptionsJSON; } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, PartialEq)] pub struct MakeCredentialPrfInput { #[serde(rename = "eval")] pub _eval: Option, @@ -267,7 +277,7 @@ pub struct MakeCredentialPrfOutput { pub enabled: Option, } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, PartialEq)] pub struct CredentialProtectionExtension { #[serde(rename = "credentialProtectionPolicy")] pub policy: CredentialProtectionPolicy, @@ -324,7 +334,7 @@ pub struct CredentialPropsExtension { pub rk: Option, } -#[derive(Debug, Default, Clone, Deserialize)] +#[derive(Debug, Default, Clone, Deserialize, PartialEq)] pub struct MakeCredentialLargeBlobExtensionInput { pub support: MakeCredentialLargeBlobExtension, } @@ -346,7 +356,7 @@ pub struct MakeCredentialLargeBlobExtensionOutput { pub supported: Option, } -#[derive(Debug, Default, Clone, Deserialize)] +#[derive(Debug, Default, Clone, Deserialize, PartialEq)] pub struct MakeCredentialsRequestExtensions { #[serde(rename = "credProps")] pub cred_props: Option, @@ -452,3 +462,86 @@ impl DowngradableRequest for MakeCredentialRequest { Ok(downgraded) } } + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use crate::ops::webauthn::MakeCredentialRequest; + use crate::ops::webauthn::RelyingPartyId; + + use super::*; + + pub const REQUEST_BASE_JSON: &str = r#" + { + "rp": { + "id": "example.org", + "name": "example.org" + }, + "user": { + "id": "dXNlcmlk", + "name": "mario.rossi", + "displayName": "Mario Rossi" + }, + "challenge": "Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu", + "pubKeyCredParams": [ + { + "type": "public-key", + "alg": -7 + } + ], + "timeout": 30000, + "excludeCredentials": [], + "authenticatorSelection": { + "residentKey": "discouraged", + "userVerification": "preferred" + }, + "attestation": "none", + "attestationFormats": ["packed", "fido-u2f"] + } + "#; + + fn request_base() -> MakeCredentialRequest { + MakeCredentialRequest { + origin: "example.org".to_string(), + hash: ClientData { + operation: Operation::MakeCredential, + challenge: base64_url::decode("Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu") + .unwrap(), + origin: "example.org".to_string(), + cross_origin: None, + } + .hash(), + relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), + user: Ctap2PublicKeyCredentialUserEntity::new(b"userid", "mario.rossi", "Mario Rossi"), + resident_key: Some(ResidentKeyRequirement::Discouraged), + user_verification: UserVerificationRequirement::Preferred, + algorithms: vec![Ctap2CredentialType::default()], + exclude: None, + extensions: None, + timeout: Duration::from_secs(30), + } + } + + fn json_field_add(str: &str, field: &str, value: &str) -> String { + let mut v: serde_json::Value = serde_json::from_str(str).unwrap(); + v.as_object_mut() + .unwrap() + .insert(field.to_owned(), serde_json::from_str(value).unwrap()); + serde_json::to_string(&v).unwrap() + } + + fn json_field_rm(str: &str, field: &str) -> String { + let mut v: serde_json::Value = serde_json::from_str(str).unwrap(); + v.as_object_mut().unwrap().remove(field); + serde_json::to_string(&v).unwrap() + } + + #[test] + fn test_request_from_json_base() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req: MakeCredentialRequest = + MakeCredentialRequest::from_json(&rpid, REQUEST_BASE_JSON).unwrap(); + assert_eq!(req, request_base()); + } +} diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index 4a6d861d..208d03b3 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -1,8 +1,7 @@ -mod create; +mod client_data; mod get_assertion; -pub(crate) mod idl; +pub mod idl; mod make_credential; -mod rpid; use super::u2f::{RegisterRequest, SignRequest}; use crate::webauthn::CtapError; @@ -13,7 +12,7 @@ pub use get_assertion::{ GetAssertionResponseExtensions, GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, HMACGetSecretOutput, PRFValue, PrfInput, }; -pub use idl::{Base64UrlString, WebAuthnIDL}; +pub use idl::{rpid::RelyingPartyId, Base64UrlString, WebAuthnIDL}; pub use make_credential::{ CredentialPropsExtension, CredentialProtectionExtension, CredentialProtectionPolicy, MakeCredentialLargeBlobExtension, MakeCredentialLargeBlobExtensionOutput, @@ -21,10 +20,15 @@ pub use make_credential::{ MakeCredentialsRequestExtensions, MakeCredentialsResponseExtensions, MakeCredentialsResponseUnsignedExtensions, ResidentKeyRequirement, }; -pub use rpid::RelyingPartyId; use serde::Deserialize; -#[derive(Debug, Clone, Copy, Deserialize)] +#[derive(Debug, Clone, Copy, Deserialize, PartialEq)] +pub enum Operation { + MakeCredential, + GetAssertion, +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq)] pub enum UserVerificationRequirement { #[serde(rename = "required")] Required, diff --git a/libwebauthn/src/proto/ctap2/model.rs b/libwebauthn/src/proto/ctap2/model.rs index ebf219b6..84373b4a 100644 --- a/libwebauthn/src/proto/ctap2/model.rs +++ b/libwebauthn/src/proto/ctap2/model.rs @@ -1,5 +1,5 @@ -use crate::pin::PinUvAuthProtocol; use crate::proto::ctap1::Ctap1Transport; +use crate::{ops::webauthn::idl::create::PublicKeyCredentialUserEntity, pin::PinUvAuthProtocol}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use serde_bytes::ByteBuf; @@ -116,6 +116,16 @@ impl Ctap2PublicKeyCredentialUserEntity { } } +impl From for Ctap2PublicKeyCredentialUserEntity { + fn from(user: PublicKeyCredentialUserEntity) -> Self { + Self { + id: ByteBuf::from(user.id), + name: Some(user.name), + display_name: Some(user.display_name), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum Ctap2PublicKeyCredentialType { #[serde(rename = "public-key")] @@ -146,7 +156,7 @@ impl From<&Ctap1Transport> for Ctap2Transport { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Ctap2PublicKeyCredentialDescriptor { pub id: ByteBuf, pub r#type: Ctap2PublicKeyCredentialType, From e12fe3f596cb95ab8dcb58bc6304b66a71dabb50 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 7 Sep 2025 21:41:03 +0100 Subject: [PATCH 08/28] Minor fix to test --- libwebauthn/src/tests/basic_ctap2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libwebauthn/src/tests/basic_ctap2.rs b/libwebauthn/src/tests/basic_ctap2.rs index c1344103..d868f70d 100644 --- a/libwebauthn/src/tests/basic_ctap2.rs +++ b/libwebauthn/src/tests/basic_ctap2.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use crate::ops::webauthn::GetAssertionRequest; +use crate::ops::webauthn::{GetAssertionRequest, GetAssertionRequestExtensions}; use crate::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; use crate::transport::hid::get_virtual_device; use crate::transport::{Channel, Device}; @@ -66,7 +66,7 @@ async fn test_webauthn_basic_ctap2() { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: None, + extensions: GetAssertionRequestExtensions::default(), timeout: TIMEOUT, }; From 294eed642443380644c4c6d6f069108265fc8cec Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 7 Sep 2025 21:45:40 +0100 Subject: [PATCH 09/28] Rebase: Fix use of HmacOrPrf::None variant --- libwebauthn/src/proto/ctap2/model/get_assertion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index b0589a39..843b7169 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -452,7 +452,7 @@ impl Ctap2UserVerifiableRequest for Ctap2GetAssertionRequest { let hmac_requested = self .extensions .as_ref() - .map(|e| !matches!(e.hmac_or_prf, GetAssertionHmacOrPrfInput::None)) + .map(|e| e.hmac_or_prf.is_some()) .unwrap_or_default(); hmac_requested && hmac_supported } From fa44ab84e173b5107e5dd578e2150a815cd256db Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 7 Sep 2025 22:10:19 +0100 Subject: [PATCH 10/28] Adds basic parsing tests --- .../src/ops/webauthn/make_credential.rs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index f35f6e41..622e981e 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -469,6 +469,7 @@ mod tests { use crate::ops::webauthn::MakeCredentialRequest; use crate::ops::webauthn::RelyingPartyId; + use crate::proto::ctap2::Ctap2PublicKeyCredentialType; use super::*; @@ -537,6 +538,17 @@ mod tests { serde_json::to_string(&v).unwrap() } + fn test_request_from_json_required_field(field: &str) { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_rm(REQUEST_BASE_JSON, field); + + let result = MakeCredentialRequest::from_json(&rpid, &req_json); + assert!(matches!( + result, + Err(MakeCredentialRequestParsingError::EncodingError(_)) + )); + } + #[test] fn test_request_from_json_base() { let rpid = RelyingPartyId::try_from("example.org").unwrap(); @@ -544,4 +556,84 @@ mod tests { MakeCredentialRequest::from_json(&rpid, REQUEST_BASE_JSON).unwrap(); assert_eq!(req, request_base()); } + + #[test] + fn test_request_from_json_require_rp() { + test_request_from_json_required_field("rp"); + } + + #[test] + fn test_request_from_json_require_user() { + test_request_from_json_required_field("user"); + } + + #[test] + fn test_request_from_json_require_pub_key_cred_params() { + test_request_from_json_required_field("pubKeyCredParams"); + } + + #[test] + fn test_request_from_json_require_challenge() { + test_request_from_json_required_field("challenge"); + } + + #[test] + #[ignore] // FIXME(#134): Add validation for challenges + fn test_request_from_json_challenge_empty() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json: String = json_field_rm(REQUEST_BASE_JSON, "challenge"); + let req_json = json_field_add(&req_json, "challenge", r#""""#); + + let result = MakeCredentialRequest::from_json(&rpid, &req_json); + assert!(matches!( + result, + Err(MakeCredentialRequestParsingError::EncodingError(_)) + )); + } + + #[test] + fn test_request_from_json_prf_extension() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_add( + REQUEST_BASE_JSON, + "extensions", + r#"{"prf": {"eval": {"first": "second"}}}"#, + ); + + let req: MakeCredentialRequest = + MakeCredentialRequest::from_json(&rpid, &req_json).unwrap(); + assert!(matches!( + req.extensions, + Some(MakeCredentialsRequestExtensions { prf: Some(_), .. }) + )); + } + + #[test] + fn test_request_from_json_unknown_pub_key_cred_params() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_add( + REQUEST_BASE_JSON, + "pubKeyCredParams", + r#"[{"type": "something", "alg": -12345}]"#, + ); + let req: MakeCredentialRequest = + MakeCredentialRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!( + req.algorithms, + vec![Ctap2CredentialType { + algorithm: Ctap2COSEAlgorithmIdentifier::Unknown, // FIXME(#148): Passhtrough unknown algorithms + public_key_type: Ctap2PublicKeyCredentialType::Unknown, + }] + ); + } + + #[test] + fn test_request_from_json_default_timeout() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_rm(REQUEST_BASE_JSON, "timeout"); + + let req: MakeCredentialRequest = + MakeCredentialRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!(req.timeout, DEFAULT_TIMEOUT); + } } From 9fc6f61c35e4655bef3cd2edad999fe6b9733082 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 7 Sep 2025 22:47:49 +0100 Subject: [PATCH 11/28] Add tests for get assertion --- libwebauthn/src/ops/webauthn/get_assertion.rs | 302 ++++++++++++------ libwebauthn/src/ops/webauthn/idl/get.rs | 81 +++++ libwebauthn/src/ops/webauthn/idl/mod.rs | 1 + 3 files changed, 289 insertions(+), 95 deletions(-) create mode 100644 libwebauthn/src/ops/webauthn/idl/get.rs diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 13a8127b..5043a7e1 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -7,8 +7,15 @@ use tracing::{debug, error, trace}; use crate::{ fido::AuthenticatorData, ops::webauthn::{ - idl::{FromInnerModel, JsonError}, - Base64UrlString, WebAuthnIDL, + client_data::ClientData, + idl::{ + get::{ + HmacGetSecretInputJson, LargeBlobInputJson, PrfInputJson, + PublicKeyCredentialRequestOptionsJSON, + }, + FromInnerModel, JsonError, + }, + Operation, WebAuthnIDL, }, pin::PinUvAuthProtocol, proto::ctap2::{ @@ -22,7 +29,7 @@ use super::{DowngradableRequest, RelyingPartyId, SignRequest, UserVerificationRe pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); -#[derive(Debug, Default, Clone, Serialize)] +#[derive(Debug, Default, Clone, Serialize, PartialEq)] pub struct PRFValue { #[serde(with = "serde_bytes")] pub first: [u8; 32], @@ -30,7 +37,7 @@ pub struct PRFValue { pub second: Option<[u8; 32]>, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct GetAssertionRequest { pub relying_party_id: String, pub hash: Vec, @@ -68,22 +75,6 @@ impl WebAuthnIDL for GetAssertionRequest { AuthenticationExtensionsClientInputsJSON extensions; }; */ -#[derive(Deserialize, Debug, Clone)] -pub struct PublicKeyCredentialRequestOptionsJSON { - pub challenge: Base64UrlString, - pub timeout: Option, - #[serde(rename = "rpId")] - pub relying_party_id: Option, - #[serde(rename = "allowCredentials")] - #[serde(default)] - pub allow_credentials: Vec, - #[serde(rename = "userVerification")] - pub uv_requirement: UserVerificationRequirement, - #[serde(default)] - pub hints: Vec, - pub extensions: Option, -} - impl FromInnerModel for GetAssertionRequest { @@ -123,13 +114,24 @@ impl FromInnerModel, pub eval_by_credential: HashMap, } -#[derive(Debug, Default, Clone, Serialize)] -pub struct GetAssertionPrfOutput { - #[serde(skip_serializing_if = "Option::is_none")] - pub results: Option, -} - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct HMACGetSecretInput { - pub salt1: [u8; 32], - pub salt2: Option<[u8; 32]>, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct HmacGetSecretInputJson { - pub salt1: Base64UrlString, - pub salt2: Option, -} - -impl TryFrom for HMACGetSecretInput { - type Error = GetAssertionRequestParsingError; - - fn try_from(value: HmacGetSecretInputJson) -> Result { - let salt1 = value.salt1.as_slice().try_into().map_err(|_| { - GetAssertionRequestParsingError::UnexpectedLengthError( - "extensions.hmacCreateSecret.salt1".to_string(), - value.salt1.as_slice().len(), - ) - })?; - let salt2 = match value.salt2 { - Some(s) => Some(s.as_slice().try_into().map_err(|_| { - GetAssertionRequestParsingError::UnexpectedLengthError( - "extensions.hmacCreateSecret.salt2".to_string(), - s.as_slice().len(), - ) - })?), - None => None, - }; - Ok(HMACGetSecretInput { salt1, salt2 }) - } -} -#[derive(Debug, Clone, Deserialize)] -pub struct LargeBlobInputJson { - pub read: Option, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct PrfInputJson { - pub eval: Option, - pub eval_by_credential: Option>, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct PrfValuesJson { - pub first: Base64UrlString, - pub second: Option, -} - impl TryFrom for PrfInput { type Error = GetAssertionRequestParsingError; @@ -266,6 +211,41 @@ impl TryFrom for PrfInput { } } +#[derive(Debug, Default, Clone, Serialize)] +pub struct GetAssertionPrfOutput { + #[serde(skip_serializing_if = "Option::is_none")] + pub results: Option, +} + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct HMACGetSecretInput { + pub salt1: [u8; 32], + pub salt2: Option<[u8; 32]>, +} + +impl TryFrom for HMACGetSecretInput { + type Error = GetAssertionRequestParsingError; + + fn try_from(value: HmacGetSecretInputJson) -> Result { + let salt1 = value.salt1.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.hmacCreateSecret.salt1".to_string(), + value.salt1.as_slice().len(), + ) + })?; + let salt2 = match value.salt2 { + Some(s) => Some(s.as_slice().try_into().map_err(|_| { + GetAssertionRequestParsingError::UnexpectedLengthError( + "extensions.hmacCreateSecret.salt2".to_string(), + s.as_slice().len(), + ) + })?), + None => None, + }; + Ok(HMACGetSecretInput { salt1, salt2 }) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum GetAssertionLargeBlobExtension { Read, @@ -296,25 +276,13 @@ pub struct GetAssertionLargeBlobExtensionOutput { // pub written: Option, } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, PartialEq)] pub struct GetAssertionRequestExtensions { pub cred_blob: bool, pub hmac_or_prf: Option, pub large_blob: Option, } -#[derive(Debug, Clone, Default, Deserialize)] -pub struct GetAssertionRequestExtensionsJSON { - #[serde(rename = "getCredBlob")] - pub cred_blob: Option, - #[serde(rename = "largeBlobKey")] - pub large_blob: Option, - #[serde(rename = "hmacCreateSecret")] - pub hamc_get_secret: Option, - #[serde(rename = "prf")] - pub prf: Option, -} - #[derive(Clone, Debug, Default, Serialize)] #[serde(rename_all = "camelCase")] pub struct HMACGetSecretOutput { @@ -460,3 +428,147 @@ impl DowngradableRequest> for GetAssertionRequest { Ok(downgraded_requests) } } + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use serde_bytes::ByteBuf; + + use crate::ops::webauthn::GetAssertionRequest; + use crate::ops::webauthn::RelyingPartyId; + use crate::proto::ctap2::Ctap2PublicKeyCredentialType; + + use super::*; + + pub const REQUEST_BASE_JSON: &str = r#" + { + "challenge": "Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu", + "timeout": 30000, + "rpId": "example.org", + "allowCredentials": [ + { + "type": "public-key", + "id": "bXktY3JlZGVudGlhbC1pZA" + } + ], + "userVerification": "preferred" + } + "#; + + fn request_base() -> GetAssertionRequest { + let client_data_json = ClientData { + operation: Operation::GetAssertion, + challenge: base64_url::decode("Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu").unwrap(), + origin: "example.org".to_string(), + cross_origin: None, + }; + GetAssertionRequest { + relying_party_id: "example.org".to_owned(), + hash: client_data_json.hash(), + allow: vec![Ctap2PublicKeyCredentialDescriptor { + r#type: Ctap2PublicKeyCredentialType::PublicKey, + id: ByteBuf::from(base64_url::decode("bXktY3JlZGVudGlhbC1pZA").unwrap()), + transports: None, + }], + extensions: GetAssertionRequestExtensions::default(), + user_verification: UserVerificationRequirement::Preferred, + timeout: Duration::from_secs(30), + } + } + + fn json_field_add(str: &str, field: &str, value: &str) -> String { + let mut v: serde_json::Value = serde_json::from_str(str).unwrap(); + v.as_object_mut() + .unwrap() + .insert(field.to_owned(), serde_json::from_str(value).unwrap()); + serde_json::to_string(&v).unwrap() + } + + fn json_field_rm(str: &str, field: &str) -> String { + let mut v: serde_json::Value = serde_json::from_str(str).unwrap(); + v.as_object_mut().unwrap().remove(field); + serde_json::to_string(&v).unwrap() + } + + #[test] + fn test_request_from_json_base() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req: GetAssertionRequest = + GetAssertionRequest::from_json(&rpid, REQUEST_BASE_JSON).unwrap(); + assert_eq!(req, request_base()); + } + + #[test] + fn test_request_from_json_ignore_missing_rp_id() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_rm(REQUEST_BASE_JSON, "rpId"); + + let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!(req, request_base()); + } + + #[test] + fn test_request_from_json_ignore_request_rp_id() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_rm(REQUEST_BASE_JSON, "rpId"); + let req_json = json_field_add(&req_json, "rpId", r#""another-example.org""#); + + let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!(req, request_base()); + } + + #[test] + fn test_request_from_json_ignore_missing_allow_credentials() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_rm(REQUEST_BASE_JSON, "allowCredentials"); + + let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!( + req, + GetAssertionRequest { + allow: vec![], + ..request_base() + } + ); + } + + #[test] + fn test_request_from_json_default_timeout() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_rm(REQUEST_BASE_JSON, "timeout"); + + let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!(req.timeout, DEFAULT_TIMEOUT); + } + + #[test] + #[ignore] // FIXME(#134) allow arbitrary size input + fn test_request_from_json_prf_extension() { + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_add( + REQUEST_BASE_JSON, + "extensions", + r#"{"prf":{"eval":{"first": "second"}}}"#, + ); + + let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); + if let GetAssertionRequestExtensions { + hmac_or_prf: + Some(GetAssertionHmacOrPrfInput::Prf(PrfInput { + eval: Some(ref prf_value), + .. + })), + .. + } = &req.extensions + { + assert_eq!(&prf_value.first[..], b"first"); + assert_eq!( + prf_value.second.as_ref().map(|s| &s[..]), + Some(&b"second"[..]) + ); + } else { + panic!("Expected PRF extension with correct values"); + } + } +} diff --git a/libwebauthn/src/ops/webauthn/idl/get.rs b/libwebauthn/src/ops/webauthn/idl/get.rs new file mode 100644 index 00000000..3267a69b --- /dev/null +++ b/libwebauthn/src/ops/webauthn/idl/get.rs @@ -0,0 +1,81 @@ +use std::collections::HashMap; + +use serde::Deserialize; +use serde_bytes::ByteBuf; + +use crate::{ + ops::webauthn::{Base64UrlString, UserVerificationRequirement}, + proto::ctap2::{ + Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType, Ctap2Transport, + }, +}; + +#[derive(Deserialize, Debug, Clone)] +pub struct PublicKeyCredentialRequestOptionsJSON { + pub challenge: Base64UrlString, + pub timeout: Option, + #[serde(rename = "rpId")] + pub relying_party_id: Option, + #[serde(rename = "allowCredentials")] + #[serde(default)] + pub allow_credentials: Vec, + #[serde(rename = "userVerification")] + pub uv_requirement: UserVerificationRequirement, + #[serde(default)] + pub hints: Vec, + pub extensions: Option, +} + +#[derive(Debug, Clone, Deserialize, PartialEq)] +pub struct PublicKeyCredentialDescriptorJSON { + pub id: Base64UrlString, + pub r#type: Ctap2PublicKeyCredentialType, + + #[serde(skip_serializing_if = "Option::is_none")] + pub transports: Option>, +} + +impl Into for PublicKeyCredentialDescriptorJSON { + fn into(self) -> Ctap2PublicKeyCredentialDescriptor { + Ctap2PublicKeyCredentialDescriptor { + r#type: self.r#type, + id: ByteBuf::from(self.id), + transports: self.transports, + } + } +} + +#[derive(Debug, Clone, Default, Deserialize)] +pub struct GetAssertionRequestExtensionsJSON { + #[serde(rename = "getCredBlob")] + pub cred_blob: Option, + #[serde(rename = "largeBlobKey")] + pub large_blob: Option, + #[serde(rename = "hmacCreateSecret")] + pub hamc_get_secret: Option, + #[serde(rename = "prf")] + pub prf: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct LargeBlobInputJson { + pub read: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct PrfInputJson { + pub eval: Option, + pub eval_by_credential: Option>, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct PrfValuesJson { + pub first: Base64UrlString, + pub second: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct HmacGetSecretInputJson { + pub salt1: Base64UrlString, + pub salt2: Option, +} diff --git a/libwebauthn/src/ops/webauthn/idl/mod.rs b/libwebauthn/src/ops/webauthn/idl/mod.rs index bee20f31..c392756b 100644 --- a/libwebauthn/src/ops/webauthn/idl/mod.rs +++ b/libwebauthn/src/ops/webauthn/idl/mod.rs @@ -1,5 +1,6 @@ mod base64url; pub mod create; +pub mod get; pub mod rpid; pub use base64url::Base64UrlString; From e948e2c32a292fcaa35b7ae30a0149b2efc54c44 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 7 Sep 2025 22:52:52 +0100 Subject: [PATCH 12/28] Update example to use JSON --- libwebauthn/examples/webauthn_json_hid.rs | 29 ++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/libwebauthn/examples/webauthn_json_hid.rs b/libwebauthn/examples/webauthn_json_hid.rs index d9d6d545..4b08ac24 100644 --- a/libwebauthn/examples/webauthn_json_hid.rs +++ b/libwebauthn/examples/webauthn_json_hid.rs @@ -1,20 +1,16 @@ -use std::convert::TryInto; use std::error::Error; use std::io::{self, Write}; use std::time::Duration; use libwebauthn::UvUpdate; -use rand::{thread_rng, Rng}; use text_io::read; use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialRequest, RelyingPartyId, - UserVerificationRequirement, WebAuthnIDL as _, + GetAssertionRequest, MakeCredentialRequest, RelyingPartyId, WebAuthnIDL as _, }; use libwebauthn::pin::PinRequestReason; -use libwebauthn::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; use libwebauthn::transport::hid::list_devices; use libwebauthn::transport::{Channel as _, Device}; use libwebauthn::webauthn::{Error as WebAuthnError, WebAuthn}; @@ -136,17 +132,18 @@ pub async fn main() -> Result<(), Box> { .unwrap(); println!("WebAuthn MakeCredential response: {:?}", response); - let challenge: [u8; 32] = thread_rng().gen(); - let credential: Ctap2PublicKeyCredentialDescriptor = - (&response.authenticator_data).try_into().unwrap(); - let get_assertion = GetAssertionRequest { - relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), - allow: vec![credential], - user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions::default(), - timeout: TIMEOUT, - }; + let request_json = r#" + { + "challenge": "Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu", + "timeout": 30000, + "rpId": "example.org", + "userVerification": "discouraged" + } + "#; + let get_assertion: GetAssertionRequest = + GetAssertionRequest::from_json(&rpid, request_json) + .expect("Failed to parse request JSON"); + println!("WebAuthn GetAssertion request: {:?}", get_assertion); let response = loop { match channel.webauthn_get_assertion(&get_assertion).await { From 437c6afc333de7deb6809e6b542e4b704315405d Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Thu, 18 Dec 2025 22:39:50 +0000 Subject: [PATCH 13/28] Address PR comments (AI assisted) --- libwebauthn/examples/prf_test.rs | 6 +-- libwebauthn/examples/webauthn_cable.rs | 2 +- .../examples/webauthn_extensions_hid.rs | 4 +- libwebauthn/examples/webauthn_hid.rs | 2 +- .../examples/webauthn_preflight_hid.rs | 2 +- libwebauthn/examples/webauthn_prf_hid.rs | 22 ++++---- libwebauthn/src/ops/u2f.rs | 4 +- libwebauthn/src/ops/webauthn/get_assertion.rs | 54 ++++++++++++------- .../src/ops/webauthn/make_credential.rs | 29 +++++----- libwebauthn/src/ops/webauthn/mod.rs | 1 + libwebauthn/src/ops/webauthn/timeout.rs | 2 +- .../src/proto/ctap2/model/get_assertion.rs | 10 ++-- libwebauthn/src/tests/basic_ctap2.rs | 2 +- 13 files changed, 77 insertions(+), 63 deletions(-) diff --git a/libwebauthn/examples/prf_test.rs b/libwebauthn/examples/prf_test.rs index fc61e498..f4e81cd6 100644 --- a/libwebauthn/examples/prf_test.rs +++ b/libwebauthn/examples/prf_test.rs @@ -126,7 +126,7 @@ pub async fn main() -> Result<(), Box> { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -155,10 +155,10 @@ async fn run_success_test( hash: Vec::from(challenge), allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, - extensions: GetAssertionRequestExtensions { + extensions: Some(GetAssertionRequestExtensions { hmac_or_prf: Some(hmac_or_prf), ..Default::default() - }, + }), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_cable.rs b/libwebauthn/examples/webauthn_cable.rs index d2b933a8..5bcb7700 100644 --- a/libwebauthn/examples/webauthn_cable.rs +++ b/libwebauthn/examples/webauthn_cable.rs @@ -162,7 +162,7 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions::default(), + extensions: Some(GetAssertionRequestExtensions::default()), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_extensions_hid.rs b/libwebauthn/examples/webauthn_extensions_hid.rs index 4b4c8317..1feef5f8 100644 --- a/libwebauthn/examples/webauthn_extensions_hid.rs +++ b/libwebauthn/examples/webauthn_extensions_hid.rs @@ -147,7 +147,7 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions { + extensions: Some(GetAssertionRequestExtensions { cred_blob: true, hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( HMACGetSecretInput { @@ -156,7 +156,7 @@ pub async fn main() -> Result<(), Box> { }, )), ..Default::default() - }, + }), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_hid.rs b/libwebauthn/examples/webauthn_hid.rs index 5ca4a25b..d05fb465 100644 --- a/libwebauthn/examples/webauthn_hid.rs +++ b/libwebauthn/examples/webauthn_hid.rs @@ -129,7 +129,7 @@ pub async fn main() -> Result<(), Box> { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions::default(), + extensions: Some(GetAssertionRequestExtensions::default()), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_preflight_hid.rs b/libwebauthn/examples/webauthn_preflight_hid.rs index 5fd54b59..97f876da 100644 --- a/libwebauthn/examples/webauthn_preflight_hid.rs +++ b/libwebauthn/examples/webauthn_preflight_hid.rs @@ -202,7 +202,7 @@ async fn get_assertion_call( hash: Vec::from(challenge), allow: allow_list, user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions::default(), + extensions: Some(GetAssertionRequestExtensions::default()), timeout: TIMEOUT, }; diff --git a/libwebauthn/examples/webauthn_prf_hid.rs b/libwebauthn/examples/webauthn_prf_hid.rs index ce244a2f..e2798152 100644 --- a/libwebauthn/examples/webauthn_prf_hid.rs +++ b/libwebauthn/examples/webauthn_prf_hid.rs @@ -175,7 +175,7 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -195,7 +195,7 @@ pub async fn main() -> Result<(), Box> { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -243,7 +243,7 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -284,7 +284,7 @@ pub async fn main() -> Result<(), Box> { second: Some([8; 32]), }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -322,7 +322,7 @@ pub async fn main() -> Result<(), Box> { second: Some([8; 32]), }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -349,7 +349,7 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -373,7 +373,7 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); @@ -426,10 +426,10 @@ async fn run_success_test( hash: Vec::from(challenge), allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions { + extensions: Some(GetAssertionRequestExtensions { hmac_or_prf: Some(hmac_or_prf), ..Default::default() - }, + }), timeout: TIMEOUT, }; @@ -468,10 +468,10 @@ async fn run_failed_test( hash: Vec::from(challenge), allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions { + extensions: Some(GetAssertionRequestExtensions { hmac_or_prf: Some(hmac_or_prf), ..Default::default() - }, + }), timeout: TIMEOUT, }; diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index 0b6b43f5..f21dd6ad 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -9,7 +9,7 @@ use x509_parser::nom::AsBytes; use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; use crate::ops::webauthn::{ - GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, + GetAssertionRequest, GetAssertionResponse, MakeCredentialResponse, UserVerificationRequirement, }; use crate::proto::ctap1::{Ctap1RegisterRequest, Ctap1SignRequest}; @@ -207,7 +207,7 @@ impl UpgradableResponse for SignResponse { id: request.key_handle.clone().into(), transports: None, }], - extensions: GetAssertionRequestExtensions::default(), + extensions: None, user_verification: if request.require_user_presence { UserVerificationRequirement::Required } else { diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 5043a7e1..dc1e10be 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -25,10 +25,9 @@ use crate::{ webauthn::CtapError, }; +use super::timeout::DEFAULT_TIMEOUT; use super::{DowngradableRequest, RelyingPartyId, SignRequest, UserVerificationRequirement}; -pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); - #[derive(Debug, Default, Clone, Serialize, PartialEq)] pub struct PRFValue { #[serde(with = "serde_bytes")] @@ -42,7 +41,7 @@ pub struct GetAssertionRequest { pub relying_party_id: String, pub hash: Vec, pub allow: Vec, - pub extensions: GetAssertionRequestExtensions, + pub extensions: Option, pub user_verification: UserVerificationRequirement, pub timeout: Duration, } @@ -97,20 +96,22 @@ impl FromInnerModel None, }; - let extensions_opt = inner.extensions.clone(); - let extensions = GetAssertionRequestExtensions { - cred_blob: extensions_opt - .as_ref() - .and_then(|ext| ext.cred_blob) - .unwrap_or(false), - large_blob: extensions_opt + let extensions = + inner + .extensions .as_ref() - .and_then(|ext| ext.large_blob.clone()) - .map(Option::::try_from) - .transpose()? - .flatten(), - hmac_or_prf, - }; + .map(|extensions_opt| GetAssertionRequestExtensions { + cred_blob: extensions_opt.cred_blob.unwrap_or(false), + large_blob: extensions_opt + .large_blob + .clone() + .map(Option::::try_from) + .transpose() + .ok() + .flatten() + .flatten(), + hmac_or_prf: hmac_or_prf.clone(), + }); let timeout: Duration = inner .timeout @@ -471,7 +472,7 @@ mod tests { id: ByteBuf::from(base64_url::decode("bXktY3JlZGVudGlhbC1pZA").unwrap()), transports: None, }], - extensions: GetAssertionRequestExtensions::default(), + extensions: None, // No extensions key in the base JSON user_verification: UserVerificationRequirement::Preferred, timeout: Duration::from_secs(30), } @@ -542,6 +543,21 @@ mod tests { assert_eq!(req.timeout, DEFAULT_TIMEOUT); } + #[test] + fn test_request_from_json_empty_extensions() { + // Test that "extensions": {} results in Some(default) not None + // This is important for strict portals that distinguish between + // no extensions key vs empty extensions object + let rpid = RelyingPartyId::try_from("example.org").unwrap(); + let req_json = json_field_add(REQUEST_BASE_JSON, "extensions", r#"{}"#); + + let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); + assert_eq!( + req.extensions, + Some(GetAssertionRequestExtensions::default()) + ); + } + #[test] #[ignore] // FIXME(#134) allow arbitrary size input fn test_request_from_json_prf_extension() { @@ -553,14 +569,14 @@ mod tests { ); let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); - if let GetAssertionRequestExtensions { + if let Some(GetAssertionRequestExtensions { hmac_or_prf: Some(GetAssertionHmacOrPrfInput::Prf(PrfInput { eval: Some(ref prf_value), .. })), .. - } = &req.extensions + }) = &req.extensions { assert_eq!(&prf_value.first[..], b"first"); assert_eq!( diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 622e981e..0e6dd251 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -27,10 +27,9 @@ use crate::{ }, }; +use super::timeout::DEFAULT_TIMEOUT; use super::{DowngradableRequest, RegisterRequest, UserVerificationRequirement}; -pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); - #[derive(Debug, Clone)] pub struct MakeCredentialResponse { pub format: String, @@ -73,22 +72,18 @@ impl MakeCredentialsResponseUnsignedExtensions { let mut hmac_create_secret = None; let mut prf = None; if let Some(signed_extensions) = signed_extensions { - (hmac_create_secret, prf) = if let Some(incoming_ext) = &request.extensions { - if let Some(_hmac_create_secret) = incoming_ext.hmac_create_secret { - (signed_extensions.hmac_secret, None) - } else if let Some(_prf) = &incoming_ext.prf { - ( - None, - Some(MakeCredentialPrfOutput { - enabled: signed_extensions.hmac_secret, - }), - ) - } else { - (None, None) + if let Some(incoming_ext) = &request.extensions { + // hmacCreateSecret and prf can both be requested and returned independently. + // Both map to the same underlying CTAP2 hmac-secret extension. + if incoming_ext.hmac_create_secret.is_some() { + hmac_create_secret = signed_extensions.hmac_secret; } - } else { - (None, None) - }; + if incoming_ext.prf.is_some() { + prf = Some(MakeCredentialPrfOutput { + enabled: signed_extensions.hmac_secret, + }); + } + } } // credProps extension diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index 208d03b3..382fd9e9 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -2,6 +2,7 @@ mod client_data; mod get_assertion; pub mod idl; mod make_credential; +mod timeout; use super::u2f::{RegisterRequest, SignRequest}; use crate::webauthn::CtapError; diff --git a/libwebauthn/src/ops/webauthn/timeout.rs b/libwebauthn/src/ops/webauthn/timeout.rs index 432e2b11..05ccdb06 100644 --- a/libwebauthn/src/ops/webauthn/timeout.rs +++ b/libwebauthn/src/ops/webauthn/timeout.rs @@ -1,3 +1,3 @@ use std::time::Duration; -pub(crate) const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); +pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60); diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index 843b7169..60996af2 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -160,7 +160,9 @@ impl Ctap2GetAssertionRequest { // // So we silently drop the extension if the device does not support it. if !info.option_enabled("largeBlobs") { - req.extensions.large_blob = None; + if let Some(ref mut ext) = req.extensions { + ext.large_blob = None; + } } Ok(Ctap2GetAssertionRequest::from(req)) @@ -173,7 +175,7 @@ impl From for Ctap2GetAssertionRequest { relying_party_id: op.relying_party_id, client_data_hash: ByteBuf::from(op.hash), allow: op.allow, - extensions: Some(op.extensions.into()), + extensions: op.extensions.map(|ext| ext.into()), options: Some(Ctap2GetAssertionOptions { require_user_presence: true, require_user_verification: op.user_verification.is_required(), @@ -517,7 +519,7 @@ impl Ctap2GetAssertionResponseExtensions { }); let (hmac_get_secret, prf) = if let Some(decrypted) = decrypted_hmac { - match &request.extensions.hmac_or_prf { + match request.extensions.as_ref().and_then(|ext| ext.hmac_or_prf.as_ref()) { None => (None, None), Some(GetAssertionHmacOrPrfInput::HmacGetSecret(..)) => (Some(decrypted), None), Some(GetAssertionHmacOrPrfInput::Prf(..)) => ( @@ -535,7 +537,7 @@ impl Ctap2GetAssertionResponseExtensions { }; // LargeBlobs was requested - let large_blob = match request.extensions.large_blob { + let large_blob = match request.extensions.as_ref().and_then(|ext| ext.large_blob.as_ref()) { None => None, Some(GetAssertionLargeBlobExtension::Read) => { Some(GetAssertionLargeBlobExtensionOutput { diff --git a/libwebauthn/src/tests/basic_ctap2.rs b/libwebauthn/src/tests/basic_ctap2.rs index d868f70d..c383826b 100644 --- a/libwebauthn/src/tests/basic_ctap2.rs +++ b/libwebauthn/src/tests/basic_ctap2.rs @@ -66,7 +66,7 @@ async fn test_webauthn_basic_ctap2() { hash: Vec::from(challenge), allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, - extensions: GetAssertionRequestExtensions::default(), + extensions: Some(GetAssertionRequestExtensions::default()), timeout: TIMEOUT, }; From 39cca529b2d8a5dfb06ef3c44f8ca93b5783ac98 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Fri, 26 Dec 2025 20:30:49 +0000 Subject: [PATCH 14/28] Rebased --- libwebauthn/Cargo.lock | 867 +++++++----------- libwebauthn/src/tests/prf.rs | 46 +- libwebauthn/src/webauthn/pin_uv_auth_token.rs | 50 +- 3 files changed, 389 insertions(+), 574 deletions(-) diff --git a/libwebauthn/Cargo.lock b/libwebauthn/Cargo.lock index e4f1c316..cd07b690 100644 --- a/libwebauthn/Cargo.lock +++ b/libwebauthn/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aead" version = "0.5.2" @@ -55,18 +40,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -79,9 +64,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -94,22 +79,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -162,7 +147,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] @@ -174,7 +159,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "synstructure 0.13.2", ] @@ -186,7 +171,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -197,7 +182,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -217,9 +202,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.14.0" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" dependencies = [ "aws-lc-sys", "zeroize", @@ -227,32 +212,16 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" dependencies = [ - "bindgen 0.72.1", "cc", "cmake", "dunce", "fs_extra", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base16ct" version = "0.2.0" @@ -267,18 +236,18 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64-url" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2b6c78c06f7288d5e3c3d683bde35a79531127c83b087e5d0d77c974b4b28" +checksum = "f5b428e9fb429c6fda7316e9b006f993e6b4c33005e4659339fb5214479dddec" dependencies = [ "base64", ] [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bindgen" @@ -286,11 +255,7 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ -<<<<<<< HEAD "bitflags 1.3.2", -======= - "bitflags 2.9.4", ->>>>>>> 386a777 (Make Credential parsing seems working; added example) "cexpr", "clang-sys", "lazy_static", @@ -301,9 +266,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", - "syn 2.0.106", + "syn 2.0.111", "which", ] @@ -313,36 +278,16 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.4", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.106", -] - -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", - "log", - "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 2.1.1", + "rustc-hash", "shlex", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -353,9 +298,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blake2" @@ -408,7 +353,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84ae4213cc2a8dc663acecac67bbdad05142be4d8ef372b6903abf878b0c690a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "bluez-generated", "dbus", "dbus-tokio", @@ -417,7 +362,7 @@ dependencies = [ "log", "serde", "serde-xml-rs", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "uuid", ] @@ -438,7 +383,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9a11621cb2c8c024e444734292482b1ad86fb50ded066cf46252e46643c8748" dependencies = [ "async-trait", - "bitflags 2.9.4", + "bitflags 2.10.0", "bluez-async", "dashmap 6.1.0", "dbus", @@ -451,7 +396,7 @@ dependencies = [ "objc2-foundation", "once_cell", "static_assertions", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "uuid", @@ -461,15 +406,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -485,9 +430,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cbc" @@ -500,27 +445,21 @@ dependencies = [ [[package]] name = "cbor-smol" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087b31faa4ad4ba21c9bd0209204eef424dae6424195aafc7242006b69fc8d" +checksum = "0b6dd31f7069836e87169bc5910212571b873cebe389c7c7f2d8b1fb3e55c80d" dependencies = [ "delog", "heapless", "heapless-bytes", - "serde", + "serde_core", ] [[package]] name = "cc" -<<<<<<< HEAD -version = "1.2.38" +version = "1.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" -======= -version = "1.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" dependencies = [ "find-msvc-tools", "jobserver", @@ -545,9 +484,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" @@ -597,9 +536,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] @@ -706,9 +645,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -827,7 +766,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -865,9 +804,9 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dbus" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9" +checksum = "21b3aa68d7e7abee336255bd7248ea965cc393f3e70411135a6f6a4b651345d4" dependencies = [ "futures-channel", "futures-util", @@ -945,9 +884,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -990,7 +929,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1086,9 +1025,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", ] @@ -1118,7 +1057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -1179,10 +1118,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -<<<<<<< HEAD -version = "0.1.2" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" [[package]] name = "find-winsdk" @@ -1194,11 +1132,6 @@ dependencies = [ "serde_derive", "winreg", ] -======= -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) [[package]] name = "flexiber" @@ -1219,16 +1152,10 @@ checksum = "e9985657bc39bae5cb7f4e686b46c67b1ea37390d82fe4bab56d7cd1933429d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "synstructure 0.13.2", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "fragile" version = "2.0.1" @@ -1297,7 +1224,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1362,23 +1289,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", -<<<<<<< HEAD - "wasi 0.14.7+wasi-0.2.4", -======= - "wasi 0.14.4+wasi-0.2.4", ->>>>>>> 386a777 (Make Credential parsing seems working; added example) + "wasip2", ] [[package]] @@ -1391,12 +1314,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "glob" version = "0.3.3" @@ -1427,12 +1344,13 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -1452,9 +1370,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heapless" @@ -1495,9 +1413,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hidapi" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" +checksum = "565dd4c730b8f8b2c0fb36df6be12e5470ae10895ddcc4e9dcfbfb495de202b0" dependencies = [ "cc", "cfg-if", @@ -1536,21 +1454,20 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1562,9 +1479,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "image" -version = "0.25.8" +version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" dependencies = [ "bytemuck", "byteorder-lite", @@ -1574,18 +1491,12 @@ dependencies = [ [[package]] name = "indexmap" -<<<<<<< HEAD -version = "2.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" -======= -version = "2.11.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] @@ -1607,22 +1518,11 @@ dependencies = [ "loom", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "iso7816" @@ -1653,9 +1553,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" [[package]] name = "jni" @@ -1698,21 +1598,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -<<<<<<< HEAD -version = "0.3.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" -======= -version = "0.3.78" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1732,27 +1626,27 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libdbus-sys" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" dependencies = [ "pkg-config", ] [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link 0.2.1", ] [[package]] @@ -1764,7 +1658,7 @@ dependencies = [ "apdu-core", "async-trait", "base64-url", - "bitflags 2.9.4", + "bitflags 2.10.0", "btleplug", "byteorder", "cbc", @@ -1808,7 +1702,7 @@ dependencies = [ "tempfile", "test-log", "text_io", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tokio", "tokio-stream", @@ -1849,11 +1743,11 @@ dependencies = [ [[package]] name = "littlefs2-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a81a4745d38b288b7583fe8ea3736897628df81f4d0f1d0314fa5a3af570de4" +checksum = "0dd2d1cad5532f5e11b0fd871b8a981885efd3fdaec0427c0d637322ae09efbf" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "heapless-bytes", "serde", ] @@ -1870,19 +1764,18 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "loom" @@ -1914,9 +1807,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "minimal-lexical" @@ -1924,24 +1817,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -1967,14 +1851,14 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "moxcms" -version = "0.7.5" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" dependencies = [ "num-traits", "pxfm", @@ -2020,11 +1904,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2051,7 +1935,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2074,9 +1958,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2084,14 +1968,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2116,7 +2000,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a644b62ffb826a5277f536cf0f701493de420b13d40e700c452c36567771111" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2", "objc2-foundation", ] @@ -2133,21 +2017,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2", "libc", "objc2", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "oid-registry" version = "0.8.1" @@ -2165,9 +2040,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "opaque-debug" @@ -2233,9 +2108,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2243,15 +2118,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -2260,7 +2135,7 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd833ecf8967e65934c49d3521a175929839bf6d0e497f3bd0d3a2ca08943da" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "pcsc-sys", ] @@ -2404,7 +2279,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2428,18 +2303,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "pxfm" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55f4fedc84ed39cb7a489322318976425e42a147e2be79d8f878e2884f94e84" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" dependencies = [ "num-traits", ] @@ -2455,9 +2330,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -2524,16 +2399,16 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -2544,9 +2419,9 @@ checksum = "09c30c54dffee5b40af088d5d50aa3455c91a0127164b51f0215efc4cb28fb3c" [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -2556,9 +2431,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -2567,9 +2442,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rfc6979" @@ -2595,24 +2470,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.4.1" @@ -2637,7 +2500,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2646,22 +2509,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "log", @@ -2675,9 +2538,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2687,18 +2550,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.6" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -2739,7 +2602,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2771,11 +2634,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation", "core-foundation-sys", "libc", @@ -2800,9 +2663,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -2825,7 +2688,7 @@ checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2836,19 +2699,19 @@ checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "serde-xml-rs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53630160a98edebde0123eb4dfd0fce6adff091b2305db3154a9e920206eb510" +checksum = "cc2215ce3e6a77550b80a1c37251b7d294febaf42e36e21b7b411e0bf54d540d" dependencies = [ "log", "serde", - "thiserror 1.0.69", - "xml-rs", + "thiserror 2.0.17", + "xml", ] [[package]] @@ -2873,22 +2736,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2912,7 +2775,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2988,10 +2851,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3037,7 +2901,7 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek", - "getrandom 0.3.3", + "getrandom 0.3.4", "p256 0.13.2", "ring", "rustc_version", @@ -3047,12 +2911,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3076,9 +2940,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -3105,9 +2969,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -3134,7 +2998,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3145,15 +3009,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.22.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.0", + "rustix 1.1.3", + "windows-sys 0.61.2", ] [[package]] @@ -3164,9 +3028,9 @@ checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-log" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b" +checksum = "37d53ac171c92a39e4769491c4b4dde7022c60042254b5fc044ae409d34a24d4" dependencies = [ "env_logger", "test-log-macros", @@ -3175,13 +3039,13 @@ dependencies = [ [[package]] name = "test-log-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36" +checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3201,11 +3065,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -3216,18 +3080,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3241,17 +3105,12 @@ dependencies = [ [[package]] name = "time" -<<<<<<< HEAD version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" -======= -version = "0.3.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", @@ -3277,40 +3136,37 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -3346,9 +3202,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -3359,18 +3215,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", "toml_datetime", @@ -3380,18 +3236,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow", ] [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -3400,20 +3256,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -3432,9 +3288,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", @@ -3454,7 +3310,7 @@ version = "0.1.0" source = "git+https://github.com/trussed-dev/trussed.git?rev=024e0eca5fb7dbd2457831f7c7bffe4341e08775#024e0eca5fb7dbd2457831f7c7bffe4341e08775" dependencies = [ "aes", - "bitflags 2.9.4", + "bitflags 2.10.0", "cbc", "cbor-smol", "cfg-if", @@ -3567,21 +3423,21 @@ dependencies = [ "rustls", "rustls-pki-types", "sha1", - "thiserror 2.0.16", + "thiserror 2.0.17", "utf-8", ] [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" @@ -3612,7 +3468,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -<<<<<<< HEAD name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3620,18 +3475,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -======= -name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -3669,42 +3519,20 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -<<<<<<< HEAD -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ -======= -version = "0.14.4+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" -dependencies = [ ->>>>>>> 386a777 (Make Credential parsing seems working; added example) "wit-bindgen", ] [[package]] name = "wasm-bindgen" -<<<<<<< HEAD -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" -======= -version = "0.2.101" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -3713,37 +3541,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -<<<<<<< HEAD -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" -======= -version = "0.2.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -<<<<<<< HEAD -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" -======= -version = "0.2.101" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3751,34 +3553,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -<<<<<<< HEAD -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" -======= -version = "0.2.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -<<<<<<< HEAD -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" -======= -version = "0.2.101" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -3795,15 +3585,37 @@ dependencies = [ "rustix 0.38.44", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows" version = "0.48.0" @@ -3861,24 +3673,24 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3889,9 +3701,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-numerics" @@ -3954,16 +3766,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -3999,19 +3811,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -4037,9 +3849,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -4055,9 +3867,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -4073,9 +3885,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -4085,9 +3897,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -4103,9 +3915,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -4121,9 +3933,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -4139,9 +3951,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -4157,21 +3969,20 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] -<<<<<<< HEAD name = "winreg" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4180,12 +3991,6 @@ dependencies = [ "serde", "winapi", ] -======= -name = "wit-bindgen" -version = "0.45.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" ->>>>>>> 386a777 (Make Credential parsing seems working; added example) [[package]] name = "wit-bindgen" @@ -4206,41 +4011,41 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] [[package]] -name = "xml-rs" -version = "0.8.27" +name = "xml" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" +checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -4253,7 +4058,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] diff --git a/libwebauthn/src/tests/prf.rs b/libwebauthn/src/tests/prf.rs index 97f135a6..95666b4a 100644 --- a/libwebauthn/src/tests/prf.rs +++ b/libwebauthn/src/tests/prf.rs @@ -3,8 +3,8 @@ use std::time::Duration; use crate::ops::webauthn::{ GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, - MakeCredentialHmacOrPrfInput, MakeCredentialPrfOutput, MakeCredentialsRequestExtensions, - PRFValue, + MakeCredentialPrfInput, MakeCredentialPrfOutput, MakeCredentialsRequestExtensions, PRFValue, + PrfInput, }; use crate::pin::PinManagement; use crate::proto::ctap2::{Ctap2PinUvAuthProtocol, Ctap2PublicKeyCredentialDescriptor}; @@ -101,7 +101,7 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { let challenge: [u8; 32] = thread_rng().gen(); let extensions = MakeCredentialsRequestExtensions { - hmac_or_prf: MakeCredentialHmacOrPrfInput::Prf, + prf: Some(MakeCredentialPrfInput { _eval: None }), ..Default::default() }; @@ -192,10 +192,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( channel, &credential, @@ -221,10 +221,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( channel, &credential, @@ -243,10 +243,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( channel, &credential, @@ -293,10 +293,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: Some([7; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( channel, &credential, @@ -336,10 +336,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( channel, &credential, @@ -376,10 +376,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_success_test( channel, &credential, @@ -405,10 +405,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_failed_test( channel, Some(&credential), @@ -429,10 +429,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_failed_test( channel, Some(&credential), @@ -453,10 +453,10 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, - }; + }); run_failed_test( channel, None, @@ -487,7 +487,7 @@ async fn run_success_test( allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf, + hmac_or_prf: Some(hmac_or_prf), ..Default::default() }), timeout: TIMEOUT, @@ -552,7 +552,7 @@ async fn run_failed_test( allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf, + hmac_or_prf: Some(hmac_or_prf), ..Default::default() }), timeout: TIMEOUT, diff --git a/libwebauthn/src/webauthn/pin_uv_auth_token.rs b/libwebauthn/src/webauthn/pin_uv_auth_token.rs index 86bd16d4..0072bf73 100644 --- a/libwebauthn/src/webauthn/pin_uv_auth_token.rs +++ b/libwebauthn/src/webauthn/pin_uv_auth_token.rs @@ -610,10 +610,12 @@ mod test { info_extensions.as_deref(), UserVerificationRequirement::Discouraged, Some(GetAssertionRequestExtensions { - hmac_or_prf: GetAssertionHmacOrPrfInput::HmacGetSecret(HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }), + hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( + HMACGetSecretInput { + salt1: [0; 32], + salt2: None, + }, + )), ..Default::default() }), Ok(UsedPinUvAuthToken::None), @@ -653,10 +655,12 @@ mod test { Some(&["hmac-secret"]), UserVerificationRequirement::Preferred, Some(GetAssertionRequestExtensions { - hmac_or_prf: GetAssertionHmacOrPrfInput::HmacGetSecret(HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }), + hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( + HMACGetSecretInput { + salt1: [0; 32], + salt2: None, + }, + )), ..Default::default() }), Ok(UsedPinUvAuthToken::LegacyUV), @@ -722,10 +726,12 @@ mod test { for (info_options, uv_requirement) in testcases { let extensions = Some(GetAssertionRequestExtensions { - hmac_or_prf: GetAssertionHmacOrPrfInput::HmacGetSecret(HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }), + hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( + HMACGetSecretInput { + salt1: [0; 32], + salt2: None, + }, + )), ..Default::default() }); @@ -789,10 +795,12 @@ mod test { for (info_options, uv_requirement) in testcases { let extensions = Some(GetAssertionRequestExtensions { - hmac_or_prf: GetAssertionHmacOrPrfInput::HmacGetSecret(HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }), + hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( + HMACGetSecretInput { + salt1: [0; 32], + salt2: None, + }, + )), ..Default::default() }); @@ -903,10 +911,12 @@ mod test { for (info_options, uv_requirement) in testcases { let extensions = Some(GetAssertionRequestExtensions { - hmac_or_prf: GetAssertionHmacOrPrfInput::HmacGetSecret(HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }), + hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( + HMACGetSecretInput { + salt1: [0; 32], + salt2: None, + }, + )), ..Default::default() }); From 885b452fc0277dc204f1e8cd1f081545621e4395 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Mon, 28 Jul 2025 23:15:56 +0100 Subject: [PATCH 15/28] [WIP] More progress --- libwebauthn/src/fido.rs | 5 +- libwebauthn/src/ops/u2f.rs | 3 +- libwebauthn/src/ops/webauthn/idl/response.rs | 259 ++++++++++++++++++ libwebauthn/src/proto/ctap2/model.rs | 4 +- .../src/proto/ctap2/model/get_assertion.rs | 2 +- 5 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 libwebauthn/src/ops/webauthn/idl/response.rs diff --git a/libwebauthn/src/fido.rs b/libwebauthn/src/fido.rs index 532a08a1..0fa42181 100644 --- a/libwebauthn/src/fido.rs +++ b/libwebauthn/src/fido.rs @@ -4,7 +4,6 @@ use serde::{ de::{DeserializeOwned, Error as DesError, Visitor}, Deserialize, Deserializer, Serialize, }; -use serde_bytes::ByteBuf; use std::{ fmt, io::{Cursor, Read}, @@ -12,7 +11,7 @@ use std::{ }; use tracing::{error, warn}; -use crate::proto::ctap2::cbor; +use crate::{ops::webauthn::idl::Base64UrlString, proto::ctap2::cbor}; use crate::{ proto::{ ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}, @@ -69,7 +68,7 @@ impl From<&AttestedCredentialData> for Ctap2PublicKeyCredentialDescriptor { fn from(data: &AttestedCredentialData) -> Self { Self { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: ByteBuf::from(data.credential_id.clone()), + id: Base64UrlString::from(data.credential_id.clone()), transports: None, } } diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index f21dd6ad..03dfe8a9 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -8,6 +8,7 @@ use x509_parser::nom::AsBytes; use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; +use crate::ops::webauthn::idl::Base64UrlString; use crate::ops::webauthn::{ GetAssertionRequest, GetAssertionResponse, MakeCredentialResponse, UserVerificationRequirement, @@ -184,7 +185,7 @@ impl UpgradableResponse for SignResponse { let response = Ctap2GetAssertionResponse { credential_id: Some(Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: ByteBuf::from(request.key_handle.clone()), + id: Base64UrlString::from(request.key_handle.clone()), transports: None, }), authenticator_data, diff --git a/libwebauthn/src/ops/webauthn/idl/response.rs b/libwebauthn/src/ops/webauthn/idl/response.rs new file mode 100644 index 00000000..5471c5d0 --- /dev/null +++ b/libwebauthn/src/ops/webauthn/idl/response.rs @@ -0,0 +1,259 @@ +//! JSON response models for WebAuthn responses. +//! +//! These types follow the WebAuthn Level 3 specification for JSON serialization: +//! - `RegistrationResponseJSON` for credential creation responses (§5.1 toJSON()) +//! - `AuthenticationResponseJSON` for assertion responses (§5.1 toJSON()) +//! +//! See: https://www.w3.org/TR/webauthn-3/#sctn-public-key-credential-json + +use serde::Serialize; + +use super::Base64UrlString; + +/// JSON output format options. +#[derive(Debug, Clone, Copy, Default)] +pub enum JsonFormat { + /// Minified JSON (default). + #[default] + Minified, + /// Pretty-printed JSON with indentation. + Prettified, +} + +/// Error type for WebAuthn response serialization. +#[derive(thiserror::Error, Debug)] +pub enum ResponseSerializationError { + /// Failed to serialize authenticator data. + #[error("Failed to serialize authenticator data: {0}")] + AuthenticatorDataError(String), + + /// Failed to serialize attestation object. + #[error("Failed to serialize attestation object: {0}")] + AttestationObjectError(String), + + /// Failed to serialize public key. + #[error("Failed to serialize public key: {0}")] + PublicKeyError(String), + + /// Failed to serialize to JSON. + #[error("Failed to serialize to JSON: {0}")] + JsonError(#[from] serde_json::Error), + + /// Failed to serialize to CBOR. + #[error("Failed to serialize to CBOR: {0}")] + CborError(String), +} + +/// Trait for WebAuthn response types that can be serialized to JSON. +/// +/// This is the inverse of `WebAuthnIDL` - it converts WebAuthn response models +/// to JSON-serializable intermediate models, which can then be serialized to JSON. +pub trait WebAuthnIDLResponse: Sized { + /// The JSON-serializable intermediate model type. + type InnerModel: Serialize; + + /// Context required for serialization (e.g., client data JSON). + type Context; + + /// Converts this response to a JSON-serializable intermediate model. + fn to_inner_model( + &self, + ctx: &Self::Context, + ) -> Result; + + /// Serializes this response to a JSON string. + fn to_json( + &self, + ctx: &Self::Context, + format: JsonFormat, + ) -> Result { + let model = self.to_inner_model(ctx)?; + match format { + JsonFormat::Minified => Ok(serde_json::to_string(&model)?), + JsonFormat::Prettified => Ok(serde_json::to_string_pretty(&model)?), + } + } +} + +/// dictionary RegistrationResponseJSON { +/// required DOMString id; +/// required Base64URLString rawId; +/// required AuthenticatorAttestationResponseJSON response; +/// DOMString authenticatorAttachment; +/// required AuthenticationExtensionsClientOutputsJSON clientExtensionResults; +/// required DOMString type; +/// }; +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RegistrationResponseJSON { + /// The credential ID, base64url-encoded. + pub id: String, + /// The raw credential ID, base64url-encoded. + pub raw_id: Base64UrlString, + /// The authenticator's response. + pub response: AuthenticatorAttestationResponseJSON, + /// The authenticator attachment modality. + #[serde(skip_serializing_if = "Option::is_none")] + pub authenticator_attachment: Option, + /// Client extension results. + pub client_extension_results: AuthenticationExtensionsClientOutputsJSON, + /// The credential type (always "public-key"). + pub r#type: String, +} + +/// dictionary AuthenticatorAttestationResponseJSON { +/// required Base64URLString clientDataJSON; +/// required Base64URLString authenticatorData; +/// required sequence transports; +/// Base64URLString publicKey; +/// required COSEAlgorithmIdentifier publicKeyAlgorithm; +/// required Base64URLString attestationObject; +/// }; +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthenticatorAttestationResponseJSON { + /// The client data JSON, base64url-encoded. + #[serde(rename = "clientDataJSON")] + pub client_data_json: Base64UrlString, + /// The authenticator data, base64url-encoded. + pub authenticator_data: Base64UrlString, + /// The transports the authenticator is believed to support. + pub transports: Vec, + /// The public key in SubjectPublicKeyInfo format, base64url-encoded. + /// May be None if the public key algorithm is not supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub public_key: Option, + /// The COSE algorithm identifier. + pub public_key_algorithm: i64, + /// The attestation object, base64url-encoded. + pub attestation_object: Base64UrlString, +} + +/// dictionary AuthenticationResponseJSON { +/// required DOMString id; +/// required Base64URLString rawId; +/// required AuthenticatorAssertionResponseJSON response; +/// DOMString authenticatorAttachment; +/// required AuthenticationExtensionsClientOutputsJSON clientExtensionResults; +/// required DOMString type; +/// }; +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthenticationResponseJSON { + /// The credential ID, base64url-encoded. + pub id: String, + /// The raw credential ID, base64url-encoded. + pub raw_id: Base64UrlString, + /// The authenticator's response. + pub response: AuthenticatorAssertionResponseJSON, + /// The authenticator attachment modality. + #[serde(skip_serializing_if = "Option::is_none")] + pub authenticator_attachment: Option, + /// Client extension results. + pub client_extension_results: AuthenticationExtensionsClientOutputsJSON, + /// The credential type (always "public-key"). + pub r#type: String, +} + +/// dictionary AuthenticatorAssertionResponseJSON { +/// required Base64URLString clientDataJSON; +/// required Base64URLString authenticatorData; +/// required Base64URLString signature; +/// Base64URLString userHandle; +/// }; +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthenticatorAssertionResponseJSON { + /// The client data JSON, base64url-encoded. + #[serde(rename = "clientDataJSON")] + pub client_data_json: Base64UrlString, + /// The authenticator data, base64url-encoded. + pub authenticator_data: Base64UrlString, + /// The signature, base64url-encoded. + pub signature: Base64UrlString, + /// The user handle, base64url-encoded. + #[serde(skip_serializing_if = "Option::is_none")] + pub user_handle: Option, +} + +/// dictionary AuthenticationExtensionsClientOutputsJSON { +/// }; +/// +/// Client extension outputs, with any ArrayBuffer values encoded as Base64URL. +/// Extensions are optional and may include: +/// - credBlob: bool +/// - largeBlob: { blob: Base64URLString, written: bool } +/// - prf: { results: { first: Base64URLString, second: Base64URLString } } +/// - hmacGetSecret: { output1: Base64URLString, output2: Base64URLString } +/// - credProps: { rk: bool } +#[derive(Debug, Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthenticationExtensionsClientOutputsJSON { + /// The credential properties extension output (for registration). + #[serde(skip_serializing_if = "Option::is_none")] + pub cred_props: Option, + + /// Whether the credential was created with hmac-secret support. + #[serde(skip_serializing_if = "Option::is_none")] + pub hmac_create_secret: Option, + + /// HMAC-secret extension output (for authentication). + #[serde(skip_serializing_if = "Option::is_none")] + pub hmac_get_secret: Option, + + /// Large blob extension output. + #[serde(skip_serializing_if = "Option::is_none")] + pub large_blob: Option, + + /// PRF extension output. + #[serde(skip_serializing_if = "Option::is_none")] + pub prf: Option, +} + +/// Credential properties extension output. +#[derive(Debug, Clone, Serialize)] +pub struct CredentialPropertiesOutputJSON { + #[serde(skip_serializing_if = "Option::is_none")] + pub rk: Option, +} + +/// HMAC-secret extension output for authentication. +#[derive(Debug, Clone, Serialize)] +pub struct HMACGetSecretOutputJSON { + pub output1: Base64UrlString, + #[serde(skip_serializing_if = "Option::is_none")] + pub output2: Option, +} + +/// Large blob extension output. +#[derive(Debug, Clone, Serialize)] +pub struct LargeBlobOutputJSON { + /// For registration: whether large blob storage is supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub supported: Option, + /// For authentication (read): the blob data, base64url-encoded. + #[serde(skip_serializing_if = "Option::is_none")] + pub blob: Option, + /// For authentication (write): whether the write was successful. + #[serde(skip_serializing_if = "Option::is_none")] + pub written: Option, +} + +/// PRF extension output. +#[derive(Debug, Clone, Serialize)] +pub struct PRFOutputJSON { + /// For registration: whether PRF is enabled. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, + /// For authentication: the PRF results. + #[serde(skip_serializing_if = "Option::is_none")] + pub results: Option, +} + +/// PRF values in JSON format. +#[derive(Debug, Clone, Serialize)] +pub struct PRFValuesJSON { + pub first: Base64UrlString, + #[serde(skip_serializing_if = "Option::is_none")] + pub second: Option, +} diff --git a/libwebauthn/src/proto/ctap2/model.rs b/libwebauthn/src/proto/ctap2/model.rs index 84373b4a..7f137e1a 100644 --- a/libwebauthn/src/proto/ctap2/model.rs +++ b/libwebauthn/src/proto/ctap2/model.rs @@ -237,12 +237,12 @@ pub enum Ctap2UserVerificationOperation { #[cfg(test)] mod tests { + use crate::ops::webauthn::idl::Base64UrlString; use crate::proto::ctap2::cbor; use crate::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; use super::{Ctap2COSEAlgorithmIdentifier, Ctap2CredentialType, Ctap2PublicKeyCredentialType}; use hex; - use serde_bytes::ByteBuf; use serde_cbor_2 as serde_cbor; #[test] @@ -262,7 +262,7 @@ mod tests { /// Verify CBOR serialization conforms to CTAP canonical standard, including ordering (see #95) pub fn credential_descriptor_serialization() { let credential_descriptor = Ctap2PublicKeyCredentialDescriptor { - id: ByteBuf::from(vec![0x42]), + id: Base64UrlString::from(vec![0x42]), r#type: Ctap2PublicKeyCredentialType::PublicKey, transports: None, }; diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index 60996af2..33a24cbe 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -305,7 +305,7 @@ impl Ctap2GetAssertionRequestExtensions { .map_err(|_| Error::Platform(PlatformError::SyntaxError))?; // 4.1 If evalByCredential is present and contains an entry whose key is the base64url encoding of the credential ID that will be returned, let ev be the value of that entry. - let found_cred_id = allow_list.iter().find(|x| x.id == cred_id); + let found_cred_id = allow_list.iter().find(|x| x.id.0 == cred_id); if found_cred_id.is_some() { ev = Some(prf_value); break; From 06ee7c04f8e5db428e56558b4c7a74b403a325d6 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 3 Aug 2025 22:41:43 +0100 Subject: [PATCH 16/28] Make Credential parsing seems working; added example --- libwebauthn/Cargo.lock | 4068 ---------------------------------------- 1 file changed, 4068 deletions(-) delete mode 100644 libwebauthn/Cargo.lock diff --git a/libwebauthn/Cargo.lock b/libwebauthn/Cargo.lock deleted file mode 100644 index cd07b690..00000000 --- a/libwebauthn/Cargo.lock +++ /dev/null @@ -1,4068 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", - "heapless", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "apdu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aa1a20ca6e9b354419bd6c2714beb435203b3e942440e09016e6deeffb08ffd" -dependencies = [ - "apdu-core", - "apdu-derive", - "thiserror 1.0.69", -] - -[[package]] -name = "apdu-app" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce391931a2cc4597eaf0d464db9d4d5e1939ccc8dd6eda0f86cda117e914c02d" -dependencies = [ - "iso7816", -] - -[[package]] -name = "apdu-core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5ab921a56bbe68325ba6d3711ee2c681239fe4c9c295c6a1c2fe6992e27f86" - -[[package]] -name = "apdu-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd675f7ce10250005ac39b9ee8e618fe51370ce6f39170559726cdd0ff7fe7c" -dependencies = [ - "apdu-core", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "asn1-rs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror 2.0.17", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", - "synstructure 0.13.2", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-lc-rs" -version = "1.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64-url" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5b428e9fb429c6fda7316e9b006f993e6b4c33005e4659339fb5214479dddec" -dependencies = [ - "base64", -] - -[[package]] -name = "base64ct" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" - -[[package]] -name = "bindgen" -version = "0.65.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.111", - "which", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags 2.10.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.111", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2", -] - -[[package]] -name = "bluez-async" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ae4213cc2a8dc663acecac67bbdad05142be4d8ef372b6903abf878b0c690a" -dependencies = [ - "bitflags 2.10.0", - "bluez-generated", - "dbus", - "dbus-tokio", - "futures", - "itertools 0.14.0", - "log", - "serde", - "serde-xml-rs", - "thiserror 2.0.17", - "tokio", - "uuid", -] - -[[package]] -name = "bluez-generated" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9676783265eadd6f11829982792c6f303f3854d014edfba384685dcf237dd062" -dependencies = [ - "dbus", -] - -[[package]] -name = "btleplug" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a11621cb2c8c024e444734292482b1ad86fb50ded066cf46252e46643c8748" -dependencies = [ - "async-trait", - "bitflags 2.10.0", - "bluez-async", - "dashmap 6.1.0", - "dbus", - "futures", - "jni", - "jni-utils", - "log", - "objc2", - "objc2-core-bluetooth", - "objc2-foundation", - "once_cell", - "static_assertions", - "thiserror 2.0.17", - "tokio", - "tokio-stream", - "uuid", - "windows 0.61.3", - "windows-future", -] - -[[package]] -name = "bumpalo" -version = "3.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" - -[[package]] -name = "bytemuck" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "bytes" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" - -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - -[[package]] -name = "cbor-smol" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6dd31f7069836e87169bc5910212571b873cebe389c7c7f2d8b1fb3e55c80d" -dependencies = [ - "delog", - "heapless", - "heapless-bytes", - "serde_core", -] - -[[package]] -name = "cc" -version = "1.2.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" -dependencies = [ - "cc", -] - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cosey" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75494895fa1a9713ca725ddf2db084ee84fb0c20938fdd7c89293febe732d30a" -dependencies = [ - "heapless-bytes", - "serde", - "serde_repr", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "crypto-bigint" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "ctap-types" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8b105c5e728afd373e99874f0c1911c170b3a56848456cc16feb4506321606" -dependencies = [ - "bitflags 1.3.2", - "cbor-smol", - "cosey", - "delog", - "heapless", - "heapless-bytes", - "iso7816", - "serde", - "serde-indexed 0.1.1", - "serde_bytes", - "serde_repr", -] - -[[package]] -name = "ctaphid" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa622743e1747e48d25170854b552b3ddc753125a39a6732e57c5c7a5ff7fe11" -dependencies = [ - "ctaphid-types", - "hex", - "log", - "rand_core 0.6.4", - "tap", -] - -[[package]] -name = "ctaphid-app" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe93489fe96c998488d0843dffea35c02ed9add2585e55228e1d45988727ecc" -dependencies = [ - "heapless-bytes", - "trussed-core", -] - -[[package]] -name = "ctaphid-dispatch" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38fd4316573df369820c5a9f8285fe522d8871c0b20bcf7d390f73b8e6caee28" -dependencies = [ - "ctaphid-app", - "delog", - "heapless-bytes", - "interchange", - "ref-swap", - "trussed-core", -] - -[[package]] -name = "ctaphid-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4714cdd86d5134532b9decaa6774db0a6851ecd07e96a2f239332ae1f3239350" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "dbus" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b3aa68d7e7abee336255bd7248ea965cc393f3e70411135a6f6a4b651345d4" -dependencies = [ - "futures-channel", - "futures-util", - "libc", - "libdbus-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "dbus-tokio" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "007688d459bc677131c063a3a77fb899526e17b7980f390b69644bdbc41fad13" -dependencies = [ - "dbus", - "libc", - "tokio", -] - -[[package]] -name = "delog" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed991f9823b19e8a0380e198dcbb6aa6ac82727b40bfecd2c6cc634f46b7e01c" -dependencies = [ - "log", -] - -[[package]] -name = "der" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" -dependencies = [ - "crypto-bigint 0.2.5", - "der_derive", -] - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "der_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aed3b3c608dc56cf36c45fe979d04eda51242e6703d8d0bb03426ef7c41db6a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", -] - -[[package]] -name = "deranged" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "des" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" -dependencies = [ - "cipher", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "downcast" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "ecdsa" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" -dependencies = [ - "der 0.4.5", - "elliptic-curve 0.10.4", - "hmac 0.11.0", - "signature 1.3.2", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der 0.7.10", - "digest 0.10.7", - "elliptic-curve 0.13.8", - "rfc6979", - "serdect", - "signature 2.2.0", - "spki", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "signature 2.2.0", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elliptic-curve" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" -dependencies = [ - "crypto-bigint 0.2.5", - "ff 0.10.1", - "generic-array", - "group 0.10.0", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint 0.5.5", - "digest 0.10.7", - "ff 0.13.1", - "generic-array", - "group 0.13.0", - "hkdf", - "pem-rfc7468", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "serdect", - "subtle", - "zeroize", -] - -[[package]] -name = "env_filter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" -dependencies = [ - "log", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "fido-authenticator" -version = "0.1.1" -source = "git+https://github.com/Nitrokey/fido-authenticator.git?tag=v0.1.1-nitrokey.27#5ebb4a48302e4c80a2abe1c2d86201a3df2a1d2d" -dependencies = [ - "apdu-app", - "cbor-smol", - "cosey", - "ctap-types", - "ctaphid-app", - "delog", - "heapless", - "heapless-bytes", - "iso7816", - "littlefs2-core", - "serde", - "serde-indexed 0.1.1", - "serde_bytes", - "sha2 0.10.9", - "trussed-core", - "trussed-fs-info", - "trussed-hkdf", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" - -[[package]] -name = "find-winsdk" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8cbf17b871570c1f8612b763bac3e86290602bcf5dc3c5ce657e0e1e9071d9e" -dependencies = [ - "serde", - "serde_derive", - "winreg", -] - -[[package]] -name = "flexiber" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2510a9088d9557aab93401404fc6786fad82f55705dedf4ee5884a3ace9be9b" -dependencies = [ - "delog", - "flexiber_derive", - "heapless", -] - -[[package]] -name = "flexiber_derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9985657bc39bae5cb7f4e686b46c67b1ea37390d82fe4bab56d7cd1933429d7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", - "synstructure 0.13.2", -] - -[[package]] -name = "fragile" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.48.0", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "group" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" -dependencies = [ - "ff 0.10.1", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff 0.13.1", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heapless-bytes" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7285eba272c6af3e9f15fb9e1c1b6e7d35aa70580ffe0d47af017e97dfb6f48b" -dependencies = [ - "heapless", - "serde", - "typenum", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - -[[package]] -name = "hidapi" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565dd4c730b8f8b2c0fb36df6be12e5470ae10895ddcc4e9dcfbfb495de202b0" -dependencies = [ - "cc", - "cfg-if", - "libc", - "pkg-config", - "windows-sys 0.48.0", -] - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "image" -version = "0.25.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", -] - -[[package]] -name = "indexmap" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "interchange" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc2a6b02f14a47afb0dbccdf96ae4f527ab32b05f78918d9da92e336bcbc222" -dependencies = [ - "loom", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "iso7816" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c7e91da489667bb054f9cd2f1c60cc2ac4478a899f403d11dbc62189215b0" -dependencies = [ - "heapless", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" - -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jni-utils" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "259e9f2c3ead61de911f147000660511f07ab00adeed1d84f5ac4d0386e7a6c4" -dependencies = [ - "dashmap 5.5.3", - "futures", - "jni", - "log", - "once_cell", - "static_assertions", - "uuid", -] - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.178" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" - -[[package]] -name = "libdbus-sys" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" -dependencies = [ - "pkg-config", -] - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - -[[package]] -name = "libwebauthn" -version = "0.2.2" -dependencies = [ - "aes", - "apdu", - "apdu-core", - "async-trait", - "base64-url", - "bitflags 2.10.0", - "btleplug", - "byteorder", - "cbc", - "cosey", - "ctap-types", - "ctaphid", - "ctaphid-dispatch", - "curve25519-dalek", - "dbus", - "delog", - "fido-authenticator", - "futures", - "heapless", - "hex", - "hidapi", - "hkdf", - "hmac 0.12.1", - "interchange", - "littlefs2", - "maplit", - "mockall", - "nfc1", - "nfc1-sys", - "num-derive", - "num-traits", - "num_enum", - "p256 0.13.2", - "pcsc", - "qrcode", - "rand 0.8.5", - "rustls", - "serde", - "serde-indexed 0.2.0", - "serde_bytes", - "serde_cbor_2", - "serde_derive", - "serde_json", - "serde_repr", - "sha2 0.10.9", - "snow", - "tempfile", - "test-log", - "text_io", - "thiserror 2.0.17", - "time", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tracing", - "tracing-subscriber", - "trussed", - "trussed-staging", - "tungstenite", - "uuid", - "x509-parser", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "littlefs2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a43f3c0c6a7d127e3e1241665dd896d8bf1ca31cf9d826a1dc65239bd59868" -dependencies = [ - "delog", - "generic-array", - "heapless", - "littlefs2-core", - "littlefs2-sys", -] - -[[package]] -name = "littlefs2-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd2d1cad5532f5e11b0fd871b8a981885efd3fdaec0427c0d637322ae09efbf" -dependencies = [ - "bitflags 2.10.0", - "heapless-bytes", - "serde", -] - -[[package]] -name = "littlefs2-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f7d54a8325846d818335f6e0a3ce4d4ff1d6a5cea7be989a76913dcb73afdc" -dependencies = [ - "bindgen 0.70.1", - "cc", -] - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "mio" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "mockall" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "mockall_derive", - "predicates", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "moxcms" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" -dependencies = [ - "num-traits", - "pxfm", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nfc1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60d6dc2e4110af159c220d2d004661e380b6c40d93c5b04e839e4944f9d5291d" -dependencies = [ - "nfc1-sys", -] - -[[package]] -name = "nfc1-sys" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6652c6cdf52433ff143439595ffb4b945afafbe5f27cec8d2fc5dfb5832796e8" -dependencies = [ - "bindgen 0.65.1", - "cc", - "find-winsdk", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2-core-bluetooth" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a644b62ffb826a5277f536cf0f701493de420b13d40e700c452c36567771111" -dependencies = [ - "bitflags 2.10.0", - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.10.0", - "block2", - "libc", - "objc2", -] - -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "p256" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" -dependencies = [ - "ecdsa 0.12.4", - "elliptic-curve 0.10.4", - "sha2 0.9.9", -] - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "primeorder", - "serdect", - "sha2 0.10.9", -] - -[[package]] -name = "p256-cortex-m4" -version = "0.1.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "647353e42d97cbbc7018cb27c0258a7f5ec1db69a0ac336bd954f468a66af38a" -dependencies = [ - "der 0.4.5", - "ecdsa 0.12.4", - "elliptic-curve 0.10.4", - "p256 0.9.0", - "p256-cortex-m4-sys", - "rand_core 0.6.4", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "p256-cortex-m4-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a73da4b90c4bb139ff5cca5526f796451cfeea58f5915bc739df36803977de" -dependencies = [ - "cc", - "cty", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link 0.2.1", -] - -[[package]] -name = "pcsc" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd833ecf8967e65934c49d3521a175929839bf6d0e497f3bd0d3a2ca08943da" -dependencies = [ - "bitflags 2.10.0", - "pcsc-sys", -] - -[[package]] -name = "pcsc-sys" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ef017e15d2e5592a9e39a346c1dbaea5120bab7ed7106b210ef58ebd97003" -dependencies = [ - "pkg-config", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.10", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "postcard" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25c0b0ae06fcffe600ad392aabfa535696c8973f2253d9ac83171924c58a858" -dependencies = [ - "heapless", - "postcard-cobs", - "serde", -] - -[[package]] -name = "postcard-cobs" -version = "0.1.5-pre" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c68cb38ed13fd7bc9dd5db8f165b7c8d9c1a315104083a2b10f11354c2af97f" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "predicates" -version = "3.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" -dependencies = [ - "anstyle", - "predicates-core", -] - -[[package]] -name = "predicates-core" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" - -[[package]] -name = "predicates-tree" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" -dependencies = [ - "predicates-core", - "termtree", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.111", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve 0.13.8", - "serdect", -] - -[[package]] -name = "proc-macro-crate" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pxfm" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" -dependencies = [ - "num-traits", -] - -[[package]] -name = "qrcode" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" -dependencies = [ - "image", -] - -[[package]] -name = "quote" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.10.0", -] - -[[package]] -name = "ref-swap" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c30c54dffee5b40af088d5d50aa3455c91a0127164b51f0215efc4cb28fb3c" - -[[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac 0.12.1", - "subtle", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.23.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" -dependencies = [ - "aws-lc-rs", - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pki-types" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "salty" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b947325a585e90733e0e9ec097228f40b637cc346f9bd68f84d5c6297d0fcfef" -dependencies = [ - "cosey", - "ed25519", - "subtle", - "zeroize", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der 0.7.10", - "generic-array", - "pkcs8", - "serdect", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" -dependencies = [ - "bitflags 2.10.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde-byte-array" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63213ee4ed648dbd87db6fa993d4275b46bfb4ddfd95b3756045007c2b28f742" -dependencies = [ - "serde", -] - -[[package]] -name = "serde-indexed" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "serde-indexed" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "serde-xml-rs" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2215ce3e6a77550b80a1c37251b7d294febaf42e36e21b7b411e0bf54d540d" -dependencies = [ - "log", - "serde", - "thiserror 2.0.17", - "xml", -] - -[[package]] -name = "serde_bytes" -version = "0.11.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "serde_cbor_2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aec2709de9078e077090abd848e967abab63c9fb3fdb5d4799ad359d8d482c" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "serde_json" -version = "1.0.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "serdect" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" -dependencies = [ - "base16ct", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "signature" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.4", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "snow" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599b506ccc4aff8cf7844bc42cf783009a434c1e26c964432560fb6d6ad02d82" -dependencies = [ - "aes-gcm", - "blake2", - "chacha20poly1305", - "curve25519-dalek", - "getrandom 0.3.4", - "p256 0.13.2", - "ring", - "rustc_version", - "sha2 0.10.9", - "subtle", -] - -[[package]] -name = "socket2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.10", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" -dependencies = [ - "fastrand", - "getrandom 0.3.4", - "once_cell", - "rustix 1.1.3", - "windows-sys 0.61.2", -] - -[[package]] -name = "termtree" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" - -[[package]] -name = "test-log" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d53ac171c92a39e4769491c4b4dde7022c60042254b5fc044ae409d34a24d4" -dependencies = [ - "env_logger", - "test-log-macros", - "tracing-subscriber", -] - -[[package]] -name = "test-log-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "text_io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d8d3ca3b06292094e03841d8995e910712d2a10b5869c8f9725385b29761115" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl 2.0.17", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "time" -version = "0.3.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" - -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tokio" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" -dependencies = [ - "futures-util", - "log", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.23.10+spec-1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" -dependencies = [ - "indexmap", - "toml_datetime", - "toml_parser", - "winnow", -] - -[[package]] -name = "toml_parser" -version = "1.0.6+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" -dependencies = [ - "winnow", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trussed" -version = "0.1.0" -source = "git+https://github.com/trussed-dev/trussed.git?rev=024e0eca5fb7dbd2457831f7c7bffe4341e08775#024e0eca5fb7dbd2457831f7c7bffe4341e08775" -dependencies = [ - "aes", - "bitflags 2.10.0", - "cbc", - "cbor-smol", - "cfg-if", - "chacha20", - "chacha20poly1305", - "cosey", - "delog", - "des", - "flexiber", - "generic-array", - "heapless", - "heapless-bytes", - "hex-literal", - "hmac 0.12.1", - "interchange", - "littlefs2", - "littlefs2-core", - "nb", - "p256-cortex-m4", - "postcard", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "salty", - "serde", - "sha-1", - "sha2 0.10.9", - "trussed-core", - "zeroize", -] - -[[package]] -name = "trussed-chunked" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9268d9d812440965ce31684e0115ceafa2636b7a8cc04dc117594567c53ff75e" -dependencies = [ - "serde", - "serde-byte-array", - "trussed-core", -] - -[[package]] -name = "trussed-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddad280ae8a5235e1b06408cca909ce9454cdd89f941b94b024c580732b3ce" -dependencies = [ - "heapless-bytes", - "littlefs2-core", - "postcard", - "rand_core 0.6.4", - "serde", - "serde-indexed 0.1.1", -] - -[[package]] -name = "trussed-fs-info" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44822e0abc5a32b3f370f82644ee9cb08aa693847aac0d48f6dc115389157aea" -dependencies = [ - "serde", - "serde-byte-array", - "trussed-core", -] - -[[package]] -name = "trussed-hkdf" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17884daee9214e24c7bb9cf2429d0f53c569cfa4a8d728106e459e60aed5be69" -dependencies = [ - "serde", - "trussed-core", -] - -[[package]] -name = "trussed-staging" -version = "0.3.2" -source = "git+https://github.com/trussed-dev/trussed-staging.git?rev=7922d67e9637a87e5625aaff9e5111f0d4ec0346#7922d67e9637a87e5625aaff9e5111f0d4ec0346" -dependencies = [ - "chacha20poly1305", - "delog", - "digest 0.10.7", - "hkdf", - "littlefs2-core", - "rand_core 0.6.4", - "salty", - "serde", - "serde-byte-array", - "sha2 0.10.9", - "trussed", - "trussed-chunked", - "trussed-fs-info", - "trussed-hkdf", -] - -[[package]] -name = "tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.9.2", - "rustls", - "rustls-pki-types", - "sha1", - "thiserror 2.0.17", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" -dependencies = [ - "getrandom 0.3.4", - "js-sys", - "serde_core", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.111", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link 0.2.1", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "winnow" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" -dependencies = [ - "serde", - "winapi", -] - -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "x509-parser" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" -dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror 2.0.17", - "time", -] - -[[package]] -name = "xml" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" - -[[package]] -name = "zerocopy" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "zmij" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a" From 0ac3bb732527039c12161b2be3188cce4c5834f2 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sun, 24 Aug 2025 16:48:58 +0100 Subject: [PATCH 17/28] Change back CTAP2 credential model to ByteBuf --- libwebauthn/src/fido.rs | 5 +++-- libwebauthn/src/ops/u2f.rs | 3 +-- libwebauthn/src/proto/ctap2/model/get_assertion.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libwebauthn/src/fido.rs b/libwebauthn/src/fido.rs index 0fa42181..532a08a1 100644 --- a/libwebauthn/src/fido.rs +++ b/libwebauthn/src/fido.rs @@ -4,6 +4,7 @@ use serde::{ de::{DeserializeOwned, Error as DesError, Visitor}, Deserialize, Deserializer, Serialize, }; +use serde_bytes::ByteBuf; use std::{ fmt, io::{Cursor, Read}, @@ -11,7 +12,7 @@ use std::{ }; use tracing::{error, warn}; -use crate::{ops::webauthn::idl::Base64UrlString, proto::ctap2::cbor}; +use crate::proto::ctap2::cbor; use crate::{ proto::{ ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}, @@ -68,7 +69,7 @@ impl From<&AttestedCredentialData> for Ctap2PublicKeyCredentialDescriptor { fn from(data: &AttestedCredentialData) -> Self { Self { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: Base64UrlString::from(data.credential_id.clone()), + id: ByteBuf::from(data.credential_id.clone()), transports: None, } } diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index 03dfe8a9..f21dd6ad 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -8,7 +8,6 @@ use x509_parser::nom::AsBytes; use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; -use crate::ops::webauthn::idl::Base64UrlString; use crate::ops::webauthn::{ GetAssertionRequest, GetAssertionResponse, MakeCredentialResponse, UserVerificationRequirement, @@ -185,7 +184,7 @@ impl UpgradableResponse for SignResponse { let response = Ctap2GetAssertionResponse { credential_id: Some(Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, - id: Base64UrlString::from(request.key_handle.clone()), + id: ByteBuf::from(request.key_handle.clone()), transports: None, }), authenticator_data, diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index 33a24cbe..60996af2 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -305,7 +305,7 @@ impl Ctap2GetAssertionRequestExtensions { .map_err(|_| Error::Platform(PlatformError::SyntaxError))?; // 4.1 If evalByCredential is present and contains an entry whose key is the base64url encoding of the credential ID that will be returned, let ev be the value of that entry. - let found_cred_id = allow_list.iter().find(|x| x.id.0 == cred_id); + let found_cred_id = allow_list.iter().find(|x| x.id == cred_id); if found_cred_id.is_some() { ev = Some(prf_value); break; From 53616abc898e9c9a1508d818c45b224d58941b06 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Fri, 19 Dec 2025 00:28:34 +0000 Subject: [PATCH 18/28] feat(idl): Add WebAuthn response JSON serialization This adds the inverse of JSON request parsing - serializing WebAuthn responses back to JSON format per WebAuthn Level 3 specification. Changes: - Add WebAuthnIDLResponse trait for response-to-JSON conversion - Add RegistrationResponseJSON and AuthenticationResponseJSON models - Implement to_json() for MakeCredentialResponse and Assertion - Refactor requests to store challenge/origin/cross_origin separately - Add client_data_hash() and client_data_json() helper methods - Update all examples and tests to use new request structure - Add unit tests for response serialization --- libwebauthn/examples/prf_test.rs | 4 +- libwebauthn/examples/webauthn_cable.rs | 7 +- .../examples/webauthn_extensions_hid.rs | 7 +- libwebauthn/examples/webauthn_hid.rs | 7 +- libwebauthn/examples/webauthn_json_hid.rs | 29 +- .../examples/webauthn_preflight_hid.rs | 7 +- libwebauthn/examples/webauthn_prf_hid.rs | 15 +- libwebauthn/src/ops/u2f.rs | 10 +- libwebauthn/src/ops/webauthn/client_data.rs | 11 +- libwebauthn/src/ops/webauthn/get_assertion.rs | 274 ++++++++++++- libwebauthn/src/ops/webauthn/idl/mod.rs | 8 + .../src/ops/webauthn/make_credential.rs | 388 ++++++++++++++++-- libwebauthn/src/ops/webauthn/mod.rs | 8 +- .../src/proto/ctap2/model/get_assertion.rs | 34 +- .../src/proto/ctap2/model/make_credential.rs | 2 +- libwebauthn/src/tests/basic_ctap2.rs | 7 +- libwebauthn/src/webauthn.rs | 4 +- 17 files changed, 740 insertions(+), 82 deletions(-) diff --git a/libwebauthn/examples/prf_test.rs b/libwebauthn/examples/prf_test.rs index f4e81cd6..9d7b31b5 100644 --- a/libwebauthn/examples/prf_test.rs +++ b/libwebauthn/examples/prf_test.rs @@ -152,7 +152,9 @@ async fn run_success_test( ) { let get_assertion = GetAssertionRequest { relying_party_id: "demo.yubico.com".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "demo.yubico.com".to_string(), + cross_origin: None, allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, extensions: Some(GetAssertionRequestExtensions { diff --git a/libwebauthn/examples/webauthn_cable.rs b/libwebauthn/examples/webauthn_cable.rs index 5bcb7700..f42595c2 100644 --- a/libwebauthn/examples/webauthn_cable.rs +++ b/libwebauthn/examples/webauthn_cable.rs @@ -120,8 +120,9 @@ pub async fn main() -> Result<(), Box> { // Make Credentials ceremony let make_credentials_request = MakeCredentialRequest { + challenge: Vec::from(challenge), origin: "example.org".to_owned(), - hash: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -159,7 +160,9 @@ pub async fn main() -> Result<(), Box> { let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions::default()), diff --git a/libwebauthn/examples/webauthn_extensions_hid.rs b/libwebauthn/examples/webauthn_extensions_hid.rs index 1feef5f8..f956883d 100644 --- a/libwebauthn/examples/webauthn_extensions_hid.rs +++ b/libwebauthn/examples/webauthn_extensions_hid.rs @@ -105,8 +105,9 @@ pub async fn main() -> Result<(), Box> { // Make Credentials ceremony let make_credentials_request = MakeCredentialRequest { + challenge: Vec::from(challenge), origin: "example.org".to_owned(), - hash: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Required), @@ -144,7 +145,9 @@ pub async fn main() -> Result<(), Box> { (&response.authenticator_data).try_into().unwrap(); let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { diff --git a/libwebauthn/examples/webauthn_hid.rs b/libwebauthn/examples/webauthn_hid.rs index d05fb465..982042db 100644 --- a/libwebauthn/examples/webauthn_hid.rs +++ b/libwebauthn/examples/webauthn_hid.rs @@ -88,8 +88,9 @@ pub async fn main() -> Result<(), Box> { // Make Credentials ceremony let make_credentials_request = MakeCredentialRequest { + challenge: Vec::from(challenge), origin: "example.org".to_owned(), - hash: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -126,7 +127,9 @@ pub async fn main() -> Result<(), Box> { (&response.authenticator_data).try_into().unwrap(); let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions::default()), diff --git a/libwebauthn/examples/webauthn_json_hid.rs b/libwebauthn/examples/webauthn_json_hid.rs index 4b08ac24..e3a538c8 100644 --- a/libwebauthn/examples/webauthn_json_hid.rs +++ b/libwebauthn/examples/webauthn_json_hid.rs @@ -8,7 +8,8 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionRequest, MakeCredentialRequest, RelyingPartyId, WebAuthnIDL as _, + GetAssertionRequest, JsonFormat, MakeCredentialRequest, RelyingPartyId, + WebAuthnIDL as _, WebAuthnIDLResponse as _, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::transport::hid::list_devices; @@ -132,6 +133,20 @@ pub async fn main() -> Result<(), Box> { .unwrap(); println!("WebAuthn MakeCredential response: {:?}", response); + // Serialize the response back to JSON using the original request as context. + // The request contains the client_data_json bytes that were built during parsing. + match response.to_json(&make_credentials_request, JsonFormat::Prettified) { + Ok(response_json) => { + println!( + "WebAuthn MakeCredential response (JSON):\n{}", + response_json + ); + } + Err(e) => { + eprintln!("Failed to serialize MakeCredential response: {:?}", e); + } + } + let request_json = r#" { "challenge": "Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu", @@ -160,6 +175,18 @@ pub async fn main() -> Result<(), Box> { } .unwrap(); println!("WebAuthn GetAssertion response: {:?}", response); + + // Serialize the response back to JSON using the original request as context. + for assertion in &response.assertions { + match assertion.to_json(&get_assertion, JsonFormat::Prettified) { + Ok(assertion_json) => { + println!("WebAuthn GetAssertion response (JSON):\n{}", assertion_json); + } + Err(e) => { + eprintln!("Failed to serialize GetAssertion response: {:?}", e); + } + } + } } Ok(()) diff --git a/libwebauthn/examples/webauthn_preflight_hid.rs b/libwebauthn/examples/webauthn_preflight_hid.rs index 97f876da..8d439751 100644 --- a/libwebauthn/examples/webauthn_preflight_hid.rs +++ b/libwebauthn/examples/webauthn_preflight_hid.rs @@ -161,8 +161,9 @@ async fn make_credential_call( ) -> Result { let challenge: [u8; 32] = thread_rng().gen(); let make_credentials_request = MakeCredentialRequest { + challenge: Vec::from(challenge), origin: "example.org".to_owned(), - hash: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -199,7 +200,9 @@ async fn get_assertion_call( let challenge: [u8; 32] = thread_rng().gen(); let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: allow_list, user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions::default()), diff --git a/libwebauthn/examples/webauthn_prf_hid.rs b/libwebauthn/examples/webauthn_prf_hid.rs index e2798152..867309a6 100644 --- a/libwebauthn/examples/webauthn_prf_hid.rs +++ b/libwebauthn/examples/webauthn_prf_hid.rs @@ -13,8 +13,8 @@ use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, - MakeCredentialPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue, - PrfInput, ResidentKeyRequirement, UserVerificationRequirement, + MakeCredentialPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, + PRFValue, PrfInput, ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -99,8 +99,9 @@ pub async fn main() -> Result<(), Box> { // Make Credentials ceremony let make_credentials_request = MakeCredentialRequest { + challenge: Vec::from(challenge), origin: "example.org".to_owned(), - hash: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Required), @@ -423,7 +424,9 @@ async fn run_success_test( ) { let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { @@ -465,7 +468,9 @@ async fn run_failed_test( ) { let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { diff --git a/libwebauthn/src/ops/u2f.rs b/libwebauthn/src/ops/u2f.rs index f21dd6ad..9c1f7296 100644 --- a/libwebauthn/src/ops/u2f.rs +++ b/libwebauthn/src/ops/u2f.rs @@ -9,8 +9,8 @@ use x509_parser::nom::AsBytes; use super::webauthn::MakeCredentialRequest; use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; use crate::ops::webauthn::{ - GetAssertionRequest, GetAssertionResponse, - MakeCredentialResponse, UserVerificationRequirement, + GetAssertionRequest, GetAssertionResponse, MakeCredentialResponse, + UserVerificationRequirement, }; use crate::proto::ctap1::{Ctap1RegisterRequest, Ctap1SignRequest}; use crate::proto::ctap1::{Ctap1RegisterResponse, Ctap1SignResponse}; @@ -133,7 +133,7 @@ impl UpgradableResponse for Regis // states a different length range. let attestation_statement = Ctap2AttestationStatement::FidoU2F(FidoU2fAttestationStmt { signature: ByteBuf::from(self.signature.clone()), - certificate: ByteBuf::from(self.attestation.clone()), + certificates: vec![ByteBuf::from(self.attestation.clone())], }); // Let attestationObject be a CBOR map (see "attObj" in Generating an Attestation Object [WebAuthn]) with the @@ -201,7 +201,9 @@ impl UpgradableResponse for SignResponse { // something like that here. In reality, we only need `extensions: None` currently. let orig_request = GetAssertionRequest { relying_party_id: String::new(), // We don't have access to that info here, but we don't need it either - hash: request.app_id_hash.clone(), + challenge: Vec::new(), // U2F path doesn't use client_data for response serialization + origin: String::new(), + cross_origin: None, allow: vec![Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, id: request.key_handle.clone().into(), diff --git a/libwebauthn/src/ops/webauthn/client_data.rs b/libwebauthn/src/ops/webauthn/client_data.rs index 9145a480..18de6702 100644 --- a/libwebauthn/src/ops/webauthn/client_data.rs +++ b/libwebauthn/src/ops/webauthn/client_data.rs @@ -13,7 +13,8 @@ pub struct ClientData { } impl ClientData { - pub fn hash(&self) -> Vec { + /// Returns the canonical JSON representation of the client data. + pub fn to_json_bytes(&self) -> Vec { let op_str = match &self.operation { Operation::MakeCredential => "webauthn.create", Operation::GetAssertion => "webauthn.get", @@ -25,11 +26,13 @@ impl ClientData { } else { "false" }; - let json = - format!("{{\"type\":\"{op_str}\",\"challenge\":\"{challenge_str}\",\"origin\":\"{origin_str}\",\"crossOrigin\":{cross_origin_str}}}"); + format!("{{\"type\":\"{op_str}\",\"challenge\":\"{challenge_str}\",\"origin\":\"{origin_str}\",\"crossOrigin\":{cross_origin_str}}}").into_bytes() + } + pub fn hash(&self) -> Vec { + let json_bytes = self.to_json_bytes(); let mut hasher = Sha256::new(); - hasher.update(json.as_bytes()); + hasher.update(&json_bytes); hasher.finalize().to_vec() } } diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index dc1e10be..92dc906e 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -13,7 +13,12 @@ use crate::{ HmacGetSecretInputJson, LargeBlobInputJson, PrfInputJson, PublicKeyCredentialRequestOptionsJSON, }, - FromInnerModel, JsonError, + response::{ + AuthenticationExtensionsClientOutputsJSON, AuthenticationResponseJSON, + AuthenticatorAssertionResponseJSON, HMACGetSecretOutputJSON, LargeBlobOutputJSON, + PRFOutputJSON, PRFValuesJSON, ResponseSerializationError, WebAuthnIDLResponse, + }, + Base64UrlString, FromInnerModel, JsonError, }, Operation, WebAuthnIDL, }, @@ -39,13 +44,34 @@ pub struct PRFValue { #[derive(Debug, Clone, PartialEq)] pub struct GetAssertionRequest { pub relying_party_id: String, - pub hash: Vec, + pub challenge: Vec, + pub origin: String, + pub cross_origin: Option, pub allow: Vec, pub extensions: Option, pub user_verification: UserVerificationRequirement, pub timeout: Duration, } +impl GetAssertionRequest { + fn client_data(&self) -> ClientData { + ClientData { + operation: Operation::GetAssertion, + challenge: self.challenge.clone(), + origin: self.origin.clone(), + cross_origin: self.cross_origin, + } + } + + pub fn client_data_hash(&self) -> Vec { + self.client_data().hash() + } + + pub fn client_data_json(&self) -> Vec { + self.client_data().to_json_bytes() + } +} + #[derive(thiserror::Error, Debug)] pub enum GetAssertionRequestParsingError { /// The client must throw an "EncodingError" DOMException. @@ -118,16 +144,11 @@ impl FromInnerModel, } +/// Context required for serializing a GetAssertion response to JSON. #[derive(Debug, Clone)] pub struct GetAssertionResponse { pub assertions: Vec, @@ -362,6 +384,102 @@ pub struct Assertion { pub attestation_statement: Option, } +impl WebAuthnIDLResponse for Assertion { + type InnerModel = AuthenticationResponseJSON; + type Context = GetAssertionRequest; + + fn to_inner_model( + &self, + request: &Self::Context, + ) -> Result { + // Get credential ID - either from credential_id field or from authenticator_data + let credential_id_bytes = self + .credential_id + .as_ref() + .map(|cred| cred.id.to_vec()) + .unwrap_or_default(); + + let id = base64_url::encode(&credential_id_bytes); + let raw_id = Base64UrlString::from(credential_id_bytes); + + // Serialize authenticator data + let authenticator_data_bytes = self + .authenticator_data + .to_response_bytes() + .map_err(|e| ResponseSerializationError::AuthenticatorDataError(e.to_string()))?; + + // Get user handle if available + let user_handle = self + .user + .as_ref() + .map(|user| Base64UrlString::from(user.id.as_ref())); + + // Build client extension results + let client_extension_results = self.build_client_extension_results(); + + Ok(AuthenticationResponseJSON { + id, + raw_id, + response: AuthenticatorAssertionResponseJSON { + client_data_json: Base64UrlString::from(request.client_data_json()), + authenticator_data: Base64UrlString::from(authenticator_data_bytes), + signature: Base64UrlString::from(self.signature.clone()), + user_handle, + }, + authenticator_attachment: None, + client_extension_results, + r#type: "public-key".to_string(), + }) + } +} + +impl Assertion { + fn build_client_extension_results(&self) -> AuthenticationExtensionsClientOutputsJSON { + let mut results = AuthenticationExtensionsClientOutputsJSON::default(); + + if let Some(unsigned_ext) = &self.unsigned_extensions_output { + // HMAC-secret extension output + if let Some(hmac_output) = &unsigned_ext.hmac_get_secret { + results.hmac_get_secret = Some(HMACGetSecretOutputJSON { + output1: Base64UrlString::from(hmac_output.output1.as_slice()), + output2: hmac_output + .output2 + .as_ref() + .map(|o| Base64UrlString::from(o.as_slice())), + }); + } + + // Large blob extension output + if let Some(large_blob) = &unsigned_ext.large_blob { + results.large_blob = Some(LargeBlobOutputJSON { + supported: None, + blob: large_blob + .blob + .as_ref() + .map(|b| Base64UrlString::from(b.as_slice())), + written: None, // Write not yet supported + }); + } + + // PRF extension output + if let Some(prf_output) = &unsigned_ext.prf { + results.prf = Some(PRFOutputJSON { + enabled: None, + results: prf_output.results.as_ref().map(|prf_value| PRFValuesJSON { + first: Base64UrlString::from(prf_value.first.as_slice()), + second: prf_value + .second + .as_ref() + .map(|s| Base64UrlString::from(s.as_slice())), + }), + }); + } + } + + results + } +} + impl From<&[Assertion]> for GetAssertionResponse { fn from(assertions: &[Assertion]) -> Self { Self { @@ -410,7 +528,7 @@ impl DowngradableRequest> for GetAssertionRequest { // --> This is already set to 0x08 in trait: From<&Ctap1RegisterRequest> for ApduRequest // Use clientDataHash parameter of CTAP2 request as CTAP1/U2F challenge parameter (32 bytes). - let challenge = &self.hash; + let challenge = self.client_data_hash(); // Let rpIdHash be a byte string of size 32 initialized with SHA-256 hash of rp.id parameter as // CTAP1/U2F application parameter (32 bytes). @@ -422,7 +540,7 @@ impl DowngradableRequest> for GetAssertionRequest { let credential_id = &credential.id; // Let u2fAuthenticateRequest be a byte string with the following structure: [...] - SignRequest::new_upgraded(&rp_id_hash, challenge, credential_id, self.timeout) + SignRequest::new_upgraded(&rp_id_hash, &challenge, credential_id, self.timeout) }) .collect(); trace!(?downgraded_requests); @@ -458,15 +576,11 @@ mod tests { "#; fn request_base() -> GetAssertionRequest { - let client_data_json = ClientData { - operation: Operation::GetAssertion, + GetAssertionRequest { + relying_party_id: "example.org".to_owned(), challenge: base64_url::decode("Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu").unwrap(), origin: "example.org".to_string(), cross_origin: None, - }; - GetAssertionRequest { - relying_party_id: "example.org".to_owned(), - hash: client_data_json.hash(), allow: vec![Ctap2PublicKeyCredentialDescriptor { r#type: Ctap2PublicKeyCredentialType::PublicKey, id: ByteBuf::from(base64_url::decode("bXktY3JlZGVudGlhbC1pZA").unwrap()), @@ -587,4 +701,130 @@ mod tests { panic!("Expected PRF extension with correct values"); } } + + // Tests for response JSON serialization + + fn create_test_assertion() -> Assertion { + use crate::fido::{AuthenticatorData, AuthenticatorDataFlags}; + + let authenticator_data = AuthenticatorData { + rp_id_hash: [0u8; 32], + flags: AuthenticatorDataFlags::USER_PRESENT, + signature_count: 1, + attested_credential: None, + extensions: None, + }; + + Assertion { + credential_id: Some(Ctap2PublicKeyCredentialDescriptor { + r#type: Ctap2PublicKeyCredentialType::PublicKey, + id: ByteBuf::from(vec![0x01, 0x02, 0x03, 0x04]), + transports: None, + }), + authenticator_data, + signature: vec![0xDE, 0xAD, 0xC0, 0xDE], + user: None, + credentials_count: None, + user_selected: None, + large_blob_key: None, + unsigned_extensions_output: None, + enterprise_attestation: None, + attestation_statement: None, + } + } + + fn create_test_request() -> GetAssertionRequest { + GetAssertionRequest { + relying_party_id: "example.org".to_owned(), + challenge: b"DEADCODE_challenge".to_vec(), + origin: "example.org".to_string(), + cross_origin: None, + allow: vec![], + extensions: None, + user_verification: UserVerificationRequirement::Preferred, + timeout: Duration::from_secs(30), + } + } + + #[test] + fn test_assertion_to_json() { + use crate::ops::webauthn::idl::response::JsonFormat; + + let assertion = create_test_assertion(); + let request = create_test_request(); + let json = assertion.to_json(&request, JsonFormat::default()); + assert!(json.is_ok()); + + let json_str = json.unwrap(); + let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap(); + + // Verify required fields + assert!(parsed.get("id").is_some()); + assert!(parsed.get("rawId").is_some()); + assert!(parsed.get("type").is_some()); + assert_eq!(parsed.get("type").unwrap(), "public-key"); + + // Verify response object + let response_obj = parsed.get("response").unwrap(); + assert!(response_obj.get("clientDataJSON").is_some()); + assert!(response_obj.get("authenticatorData").is_some()); + assert!(response_obj.get("signature").is_some()); + } + + #[test] + fn test_assertion_to_inner_model() { + let assertion = create_test_assertion(); + let request = create_test_request(); + let model = assertion.to_inner_model(&request).unwrap(); + + // Verify the credential ID + assert_eq!(model.raw_id.0, vec![0x01, 0x02, 0x03, 0x04]); + assert_eq!(model.r#type, "public-key"); + + // Verify signature + assert_eq!(model.response.signature.0, vec![0xDE, 0xAD, 0xC0, 0xDE]); + } + + #[test] + fn test_assertion_with_user_handle() { + use crate::proto::ctap2::Ctap2PublicKeyCredentialUserEntity; + + let mut assertion = create_test_assertion(); + assertion.user = Some(Ctap2PublicKeyCredentialUserEntity::new( + b"test-user-id", + "testuser", + "Test User", + )); + + let request = create_test_request(); + let model = assertion.to_inner_model(&request).unwrap(); + + // Verify user handle is present + assert!(model.response.user_handle.is_some()); + assert_eq!( + model.response.user_handle.as_ref().unwrap().0, + b"test-user-id".to_vec() + ); + } + + #[test] + fn test_assertion_with_extensions() { + let mut assertion = create_test_assertion(); + assertion.unsigned_extensions_output = Some(GetAssertionResponseUnsignedExtensions { + hmac_get_secret: None, + large_blob: None, + prf: Some(GetAssertionPrfOutput { + results: Some(PRFValue { + first: [0x01u8; 32], + second: None, + }), + }), + }); + + let request = create_test_request(); + let model = assertion.to_inner_model(&request).unwrap(); + + // Verify extension outputs - PRF should be set + assert!(model.client_extension_results.prf.is_some()); + } } diff --git a/libwebauthn/src/ops/webauthn/idl/mod.rs b/libwebauthn/src/ops/webauthn/idl/mod.rs index c392756b..e2d6685a 100644 --- a/libwebauthn/src/ops/webauthn/idl/mod.rs +++ b/libwebauthn/src/ops/webauthn/idl/mod.rs @@ -1,9 +1,17 @@ mod base64url; pub mod create; pub mod get; +pub mod response; pub mod rpid; pub use base64url::Base64UrlString; +pub use response::{ + AuthenticationExtensionsClientOutputsJSON, AuthenticationResponseJSON, + AuthenticatorAssertionResponseJSON, AuthenticatorAttestationResponseJSON, + CredentialPropertiesOutputJSON, HMACGetSecretOutputJSON, JsonFormat, LargeBlobOutputJSON, + PRFOutputJSON, PRFValuesJSON, RegistrationResponseJSON, ResponseSerializationError, + WebAuthnIDLResponse, +}; use rpid::RelyingPartyId; diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 0e6dd251..7edac05b 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -11,15 +11,20 @@ use crate::{ ops::webauthn::{ client_data::ClientData, idl::{ - create::PublicKeyCredentialCreationOptionsJSON, Base64UrlString, FromInnerModel, - JsonError, WebAuthnIDL, + create::PublicKeyCredentialCreationOptionsJSON, + response::{ + AuthenticationExtensionsClientOutputsJSON, AuthenticatorAttestationResponseJSON, + CredentialPropertiesOutputJSON, LargeBlobOutputJSON, PRFOutputJSON, + RegistrationResponseJSON, ResponseSerializationError, WebAuthnIDLResponse, + }, + Base64UrlString, FromInnerModel, JsonError, WebAuthnIDL, }, Operation, RelyingPartyId, }, proto::{ ctap1::{Ctap1RegisteredKey, Ctap1Version}, ctap2::{ - Ctap2AttestationStatement, Ctap2COSEAlgorithmIdentifier, Ctap2CredentialType, + cbor, Ctap2AttestationStatement, Ctap2COSEAlgorithmIdentifier, Ctap2CredentialType, Ctap2GetInfoResponse, Ctap2MakeCredentialsResponseExtensions, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity, Ctap2PublicKeyCredentialUserEntity, @@ -40,6 +45,147 @@ pub struct MakeCredentialResponse { pub unsigned_extensions_output: MakeCredentialsResponseUnsignedExtensions, } +/// Serializable attestation object for CBOR encoding. +#[derive(Debug, Clone, Serialize)] +struct AttestationObject<'a> { + #[serde(rename = "fmt")] + format: &'a str, + #[serde(rename = "authData", with = "serde_bytes")] + auth_data: &'a [u8], + #[serde(rename = "attStmt")] + attestation_statement: &'a Ctap2AttestationStatement, +} + +impl WebAuthnIDLResponse for MakeCredentialResponse { + type InnerModel = RegistrationResponseJSON; + type Context = MakeCredentialRequest; + + fn to_inner_model( + &self, + request: &Self::Context, + ) -> Result { + // Get credential ID from attested credential data + let credential_id_bytes = self + .authenticator_data + .attested_credential + .as_ref() + .map(|cred| cred.credential_id.clone()) + .unwrap_or_default(); + + let id = base64_url::encode(&credential_id_bytes); + let raw_id = Base64UrlString::from(credential_id_bytes); + + // Serialize authenticator data + let authenticator_data_bytes = self + .authenticator_data + .to_response_bytes() + .map_err(|e| ResponseSerializationError::AuthenticatorDataError(e.to_string()))?; + + // Get public key algorithm from attested credential data + let public_key_algorithm = self + .authenticator_data + .attested_credential + .as_ref() + .map(|cred| Self::get_public_key_algorithm(&cred.credential_public_key)) + .unwrap_or(Ctap2COSEAlgorithmIdentifier::ES256 as i64); + + // Serialize public key to COSE key format + let public_key = self + .authenticator_data + .attested_credential + .as_ref() + .map(|cred| { + cbor::to_vec(&cred.credential_public_key) + .map(Base64UrlString::from) + .map_err(|e| ResponseSerializationError::PublicKeyError(e.to_string())) + }) + .transpose()?; + + // Build attestation object (CBOR map with authData, fmt, attStmt) + let attestation_object_bytes = self.build_attestation_object(&authenticator_data_bytes)?; + + // Get transports (we don't have direct access, so return empty for now) + let transports = Vec::new(); + + // Build client extension results + let client_extension_results = self.build_client_extension_results(); + + Ok(RegistrationResponseJSON { + id, + raw_id, + response: AuthenticatorAttestationResponseJSON { + client_data_json: Base64UrlString::from(request.client_data_json()), + authenticator_data: Base64UrlString::from(authenticator_data_bytes), + transports, + public_key, + public_key_algorithm, + attestation_object: Base64UrlString::from(attestation_object_bytes), + }, + authenticator_attachment: None, + client_extension_results, + r#type: "public-key".to_string(), + }) + } +} + +impl MakeCredentialResponse { + /// Get the COSE algorithm identifier from the public key variant + fn get_public_key_algorithm(key: &cosey::PublicKey) -> i64 { + match key { + cosey::PublicKey::P256Key(_) => Ctap2COSEAlgorithmIdentifier::ES256 as i64, + cosey::PublicKey::EcdhEsHkdf256Key(_) => -25, // ECDH-ES + HKDF-256 + cosey::PublicKey::Ed25519Key(_) => Ctap2COSEAlgorithmIdentifier::EDDSA as i64, + cosey::PublicKey::TotpKey(_) => 0, // No standard algorithm for TOTP + } + } + + fn build_attestation_object( + &self, + authenticator_data_bytes: &[u8], + ) -> Result, ResponseSerializationError> { + let attestation_object = AttestationObject { + format: &self.format, + auth_data: authenticator_data_bytes, + attestation_statement: &self.attestation_statement, + }; + + cbor::to_vec(&attestation_object) + .map_err(|e| ResponseSerializationError::AttestationObjectError(e.to_string())) + } + + fn build_client_extension_results(&self) -> AuthenticationExtensionsClientOutputsJSON { + let mut results = AuthenticationExtensionsClientOutputsJSON::default(); + let unsigned_ext = &self.unsigned_extensions_output; + + // Credential properties extension + if let Some(cred_props) = &unsigned_ext.cred_props { + results.cred_props = Some(CredentialPropertiesOutputJSON { rk: cred_props.rk }); + } + + // HMAC-secret extension (hmacCreateSecret) + results.hmac_create_secret = unsigned_ext.hmac_create_secret; + + // Large blob extension + if let Some(large_blob) = &unsigned_ext.large_blob { + results.large_blob = Some(LargeBlobOutputJSON { + supported: large_blob.supported, + blob: None, + written: None, + }); + } + + // PRF extension + if let Some(prf) = &unsigned_ext.prf { + results.prf = Some(PRFOutputJSON { + enabled: prf.enabled, + results: None, + }); + } + + results + } +} + #[derive(Debug, Default, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct MakeCredentialsResponseUnsignedExtensions { @@ -172,8 +318,12 @@ pub enum ResidentKeyRequirement { #[derive(Debug, Clone, PartialEq)] pub struct MakeCredentialRequest { - pub hash: Vec, + /// The challenge from the relying party. + pub challenge: Vec, + /// The origin of the request. pub origin: String, + /// Whether the request is cross-origin (optional per WebAuthn spec). + pub cross_origin: Option, /// rpEntity pub relying_party: Ctap2PublicKeyCredentialRpEntity, /// userEntity @@ -189,6 +339,28 @@ pub struct MakeCredentialRequest { pub timeout: Duration, } +impl MakeCredentialRequest { + /// Builds the ClientData for this request. + fn client_data(&self) -> ClientData { + ClientData { + operation: Operation::MakeCredential, + challenge: self.challenge.clone(), + origin: self.origin.clone(), + cross_origin: self.cross_origin, + } + } + + /// Computes the client data hash (SHA-256 of the client data JSON). + pub fn client_data_hash(&self) -> Vec { + self.client_data().hash() + } + + /// Returns the client data JSON bytes for response serialization. + pub fn client_data_json(&self) -> Vec { + self.client_data().to_json_bytes() + } +} + impl FromInnerModel for MakeCredentialRequest { @@ -222,16 +394,10 @@ impl FromInnerModel Self { Self { - hash: vec![0; 32], + challenge: Vec::new(), + origin: "example.org".to_owned(), + cross_origin: Some(false), relying_party: Ctap2PublicKeyCredentialRpEntity::dummy(), user: Ctap2PublicKeyCredentialUserEntity::dummy(), algorithms: vec![Ctap2CredentialType::default()], exclude: None, extensions: None, - origin: "example.org".to_owned(), resident_key: None, user_verification: UserVerificationRequirement::Discouraged, timeout: Duration::from_secs(10), @@ -428,7 +595,7 @@ impl DowngradableRequest for MakeCredentialRequest { let downgraded = RegisterRequest { version: Ctap1Version::U2fV2, app_id_hash: rp_id_hash, - challenge: self.hash.clone(), + challenge: self.client_data_hash(), registered_keys: self .exclude .as_ref() @@ -499,15 +666,9 @@ mod tests { fn request_base() -> MakeCredentialRequest { MakeCredentialRequest { + challenge: base64_url::decode("Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu").unwrap(), origin: "example.org".to_string(), - hash: ClientData { - operation: Operation::MakeCredential, - challenge: base64_url::decode("Y3JlZGVudGlhbHMtZm9yLWxpbnV4L2xpYndlYmF1dGhu") - .unwrap(), - origin: "example.org".to_string(), - cross_origin: None, - } - .hash(), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(b"userid", "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -631,4 +792,183 @@ mod tests { MakeCredentialRequest::from_json(&rpid, &req_json).unwrap(); assert_eq!(req.timeout, DEFAULT_TIMEOUT); } + + // Tests for response JSON serialization + + fn create_test_response() -> MakeCredentialResponse { + use crate::fido::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags}; + use cosey::Bytes; + use std::collections::BTreeMap; + + // Create a simple attested credential with a P256 key + let credential_id = vec![0x01, 0x02, 0x03, 0x04]; + let aaguid = [0u8; 16]; + + // Create a P256 public key for testing + let public_key = cosey::PublicKey::P256Key(cosey::P256PublicKey { + x: Bytes::from_slice(&[0u8; 32]).unwrap(), + y: Bytes::from_slice(&[0u8; 32]).unwrap(), + }); + + let attested_credential = AttestedCredentialData { + aaguid, + credential_id, + credential_public_key: public_key, + }; + + let authenticator_data = AuthenticatorData { + rp_id_hash: [0u8; 32], + flags: AuthenticatorDataFlags::USER_PRESENT, + signature_count: 0, + attested_credential: Some(attested_credential), + extensions: None, + }; + + MakeCredentialResponse { + format: "none".to_string(), + authenticator_data, + attestation_statement: Ctap2AttestationStatement::None(BTreeMap::new()), + enterprise_attestation: None, + large_blob_key: None, + unsigned_extensions_output: MakeCredentialsResponseUnsignedExtensions::default(), + } + } + + fn create_test_request() -> MakeCredentialRequest { + MakeCredentialRequest { + challenge: b"DEADCODE_challenge".to_vec(), + origin: "example.org".to_string(), + cross_origin: None, + relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), + user: Ctap2PublicKeyCredentialUserEntity::new(b"userid", "mario.rossi", "Mario Rossi"), + resident_key: Some(ResidentKeyRequirement::Discouraged), + user_verification: UserVerificationRequirement::Preferred, + algorithms: vec![Ctap2CredentialType::default()], + exclude: None, + extensions: None, + timeout: Duration::from_secs(30), + } + } + + #[test] + fn test_response_to_json() { + use crate::ops::webauthn::idl::response::JsonFormat; + + let response = create_test_response(); + let request = create_test_request(); + let json = response.to_json(&request, JsonFormat::default()); + assert!(json.is_ok()); + + let json_str = json.unwrap(); + let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap(); + + // Verify required fields + assert!(parsed.get("id").is_some()); + assert!(parsed.get("rawId").is_some()); + assert!(parsed.get("type").is_some()); + assert_eq!(parsed.get("type").unwrap(), "public-key"); + + // Verify response object + let response_obj = parsed.get("response").unwrap(); + assert!(response_obj.get("clientDataJSON").is_some()); + assert!(response_obj.get("authenticatorData").is_some()); + assert!(response_obj.get("attestationObject").is_some()); + assert!(response_obj.get("publicKeyAlgorithm").is_some()); + + // Verify algorithm is ES256 (-7) for P256 key + assert_eq!( + response_obj.get("publicKeyAlgorithm").unwrap(), + Ctap2COSEAlgorithmIdentifier::ES256 as i64 + ); + } + + #[test] + fn test_response_to_inner_model() { + let response = create_test_response(); + let request = create_test_request(); + let model = response.to_inner_model(&request).unwrap(); + + // Verify the credential ID + assert_eq!(model.raw_id.0, vec![0x01, 0x02, 0x03, 0x04]); + assert_eq!(model.r#type, "public-key"); + + // Verify attestation response + assert_eq!( + model.response.public_key_algorithm, + Ctap2COSEAlgorithmIdentifier::ES256 as i64 + ); + assert!(model.response.transports.is_empty()); + } + + #[test] + fn test_response_attestation_object_format() { + let response = create_test_response(); + let request = create_test_request(); + let model = response.to_inner_model(&request).unwrap(); + + // Decode the attestation object + let attestation_bytes = model.response.attestation_object.0; + let attestation: cbor::Value = cbor::from_slice(&attestation_bytes).unwrap(); + + // Verify it's a map with the expected keys + if let cbor::Value::Map(map) = attestation { + let has_fmt = map + .keys() + .any(|k| matches!(k, cbor::Value::Text(s) if s == "fmt")); + let has_auth_data = map + .keys() + .any(|k| matches!(k, cbor::Value::Text(s) if s == "authData")); + let has_att_stmt = map + .keys() + .any(|k| matches!(k, cbor::Value::Text(s) if s == "attStmt")); + + assert!(has_fmt, "attestation object should have 'fmt' key"); + assert!( + has_auth_data, + "attestation object should have 'authData' key" + ); + assert!(has_att_stmt, "attestation object should have 'attStmt' key"); + } else { + panic!("attestation object should be a CBOR map"); + } + } + + #[test] + fn test_response_with_extensions() { + let mut response = create_test_response(); + + // Add some extension outputs + response.unsigned_extensions_output = MakeCredentialsResponseUnsignedExtensions { + cred_props: Some(CredentialPropsExtension { rk: Some(true) }), + hmac_create_secret: Some(true), + large_blob: None, + prf: Some(MakeCredentialPrfOutput { + enabled: Some(true), + }), + }; + + let request = create_test_request(); + let model = response.to_inner_model(&request).unwrap(); + + // Verify extension outputs + assert!(model.client_extension_results.cred_props.is_some()); + assert_eq!( + model + .client_extension_results + .cred_props + .as_ref() + .unwrap() + .rk, + Some(true) + ); + assert_eq!( + model.client_extension_results.hmac_create_secret, + Some(true) + ); + assert!(model.client_extension_results.prf.is_some()); + assert_eq!( + model.client_extension_results.prf.as_ref().unwrap().enabled, + Some(true) + ); + } } diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index 382fd9e9..b9536d3f 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -6,6 +6,7 @@ mod timeout; use super::u2f::{RegisterRequest, SignRequest}; use crate::webauthn::CtapError; +pub use client_data::ClientData; pub use get_assertion::{ Assertion, Ctap2HMACGetSecretOutput, GetAssertionHmacOrPrfInput, GetAssertionLargeBlobExtension, GetAssertionLargeBlobExtensionOutput, GetAssertionPrfOutput, @@ -13,7 +14,12 @@ pub use get_assertion::{ GetAssertionResponseExtensions, GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, HMACGetSecretOutput, PRFValue, PrfInput, }; -pub use idl::{rpid::RelyingPartyId, Base64UrlString, WebAuthnIDL}; +pub use idl::{ + rpid::RelyingPartyId, AuthenticationExtensionsClientOutputsJSON, AuthenticationResponseJSON, + AuthenticatorAssertionResponseJSON, AuthenticatorAttestationResponseJSON, Base64UrlString, + JsonFormat, RegistrationResponseJSON, ResponseSerializationError, WebAuthnIDL, + WebAuthnIDLResponse, +}; pub use make_credential::{ CredentialPropsExtension, CredentialProtectionExtension, CredentialProtectionPolicy, MakeCredentialLargeBlobExtension, MakeCredentialLargeBlobExtensionOutput, diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index 60996af2..39da636f 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -42,7 +42,7 @@ impl Ctap2GetAssertionOptions { } } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct PackedAttestationStmt { #[serde(rename = "alg")] pub algorithm: Ctap2COSEAlgorithmIdentifier, @@ -50,20 +50,21 @@ pub struct PackedAttestationStmt { #[serde(rename = "sig")] pub signature: ByteBuf, - #[serde(rename = "x5c")] + #[serde(rename = "x5c", skip_serializing_if = "Vec::is_empty", default)] pub certificates: Vec, } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct FidoU2fAttestationStmt { #[serde(rename = "sig")] pub signature: ByteBuf, + /// Certificate chain as an array (spec requires array even for single cert). #[serde(rename = "x5c")] - pub certificate: ByteBuf, + pub certificates: Vec, } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct TpmAttestationStmt { #[serde(rename = "ver")] pub version: String, @@ -74,7 +75,7 @@ pub struct TpmAttestationStmt { #[serde(rename = "sig")] pub signature: ByteBuf, - #[serde(rename = "x5c")] + #[serde(rename = "x5c", skip_serializing_if = "Vec::is_empty", default)] pub certificates: Vec, #[serde(rename = "certInfo")] @@ -84,13 +85,13 @@ pub struct TpmAttestationStmt { pub public_area: ByteBuf, } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct AppleAnonymousAttestationStmt { - #[serde(rename = "x5c")] + #[serde(rename = "x5c", skip_serializing_if = "Vec::is_empty", default)] pub certificates: Vec, } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] #[serde(untagged)] pub enum Ctap2AttestationStatement { PackedOrAndroid(PackedAttestationStmt), @@ -171,9 +172,10 @@ impl Ctap2GetAssertionRequest { impl From for Ctap2GetAssertionRequest { fn from(op: GetAssertionRequest) -> Self { + let client_data_hash = ByteBuf::from(op.client_data_hash()); Self { relying_party_id: op.relying_party_id, - client_data_hash: ByteBuf::from(op.hash), + client_data_hash, allow: op.allow, extensions: op.extensions.map(|ext| ext.into()), options: Some(Ctap2GetAssertionOptions { @@ -519,7 +521,11 @@ impl Ctap2GetAssertionResponseExtensions { }); let (hmac_get_secret, prf) = if let Some(decrypted) = decrypted_hmac { - match request.extensions.as_ref().and_then(|ext| ext.hmac_or_prf.as_ref()) { + match request + .extensions + .as_ref() + .and_then(|ext| ext.hmac_or_prf.as_ref()) + { None => (None, None), Some(GetAssertionHmacOrPrfInput::HmacGetSecret(..)) => (Some(decrypted), None), Some(GetAssertionHmacOrPrfInput::Prf(..)) => ( @@ -537,7 +543,11 @@ impl Ctap2GetAssertionResponseExtensions { }; // LargeBlobs was requested - let large_blob = match request.extensions.as_ref().and_then(|ext| ext.large_blob.as_ref()) { + let large_blob = match request + .extensions + .as_ref() + .and_then(|ext| ext.large_blob.as_ref()) + { None => None, Some(GetAssertionLargeBlobExtension::Read) => { Some(GetAssertionLargeBlobExtensionOutput { diff --git a/libwebauthn/src/proto/ctap2/model/make_credential.rs b/libwebauthn/src/proto/ctap2/model/make_credential.rs index 739dc9fe..1bcb005e 100644 --- a/libwebauthn/src/proto/ctap2/model/make_credential.rs +++ b/libwebauthn/src/proto/ctap2/model/make_credential.rs @@ -158,7 +158,7 @@ impl Ctap2MakeCredentialRequest { }; Ok(Ctap2MakeCredentialRequest { - hash: ByteBuf::from(req.hash.clone()), + hash: ByteBuf::from(req.client_data_hash()), relying_party: req.relying_party.clone(), user: req.user.clone(), algorithms: req.algorithms.clone(), diff --git a/libwebauthn/src/tests/basic_ctap2.rs b/libwebauthn/src/tests/basic_ctap2.rs index c383826b..c7d36c2f 100644 --- a/libwebauthn/src/tests/basic_ctap2.rs +++ b/libwebauthn/src/tests/basic_ctap2.rs @@ -38,8 +38,9 @@ async fn test_webauthn_basic_ctap2() { // Make Credentials ceremony let make_credentials_request = MakeCredentialRequest { + challenge: Vec::from(challenge), origin: "example.org".to_owned(), - hash: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -63,7 +64,9 @@ async fn test_webauthn_basic_ctap2() { (&response.authenticator_data).try_into().unwrap(); let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_string(), + cross_origin: None, allow: vec![credential], user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions::default()), diff --git a/libwebauthn/src/webauthn.rs b/libwebauthn/src/webauthn.rs index 134802ae..57a632a4 100644 --- a/libwebauthn/src/webauthn.rs +++ b/libwebauthn/src/webauthn.rs @@ -109,7 +109,7 @@ where if Self::supports_preflight() { if let Some(exclude_list) = &op.exclude { let filtered_exclude_list = - ctap2_preflight(self, exclude_list, &op.hash, &op.relying_party.id).await; + ctap2_preflight(self, exclude_list, &op.client_data_hash(), &op.relying_party.id).await; ctap2_request.exclude = Some(filtered_exclude_list); } } @@ -172,7 +172,7 @@ where if Self::supports_preflight() { let filtered_allow_list = - ctap2_preflight(self, &op.allow, &op.hash, &op.relying_party_id).await; + ctap2_preflight(self, &op.allow, &op.client_data_hash(), &op.relying_party_id).await; if filtered_allow_list.is_empty() && !op.allow.is_empty() { // We filtered out everything in preflight, meaning none of the allowed // credentials are present on this device. So we error out here From d97c80d25bdb974472c40de5e5031db5946ad532 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Fri, 26 Dec 2025 20:55:20 +0000 Subject: [PATCH 19/28] Rebased --- libwebauthn/Cargo.lock | 4068 +++++++++++++++++ libwebauthn/src/proto/ctap2/model.rs | 4 +- libwebauthn/src/proto/ctap2/preflight.rs | 7 +- libwebauthn/src/tests/prf.rs | 15 +- libwebauthn/src/webauthn/pin_uv_auth_token.rs | 4 +- 5 files changed, 4089 insertions(+), 9 deletions(-) create mode 100644 libwebauthn/Cargo.lock diff --git a/libwebauthn/Cargo.lock b/libwebauthn/Cargo.lock new file mode 100644 index 00000000..cd07b690 --- /dev/null +++ b/libwebauthn/Cargo.lock @@ -0,0 +1,4068 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", + "heapless", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "apdu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa1a20ca6e9b354419bd6c2714beb435203b3e942440e09016e6deeffb08ffd" +dependencies = [ + "apdu-core", + "apdu-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "apdu-app" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce391931a2cc4597eaf0d464db9d4d5e1939ccc8dd6eda0f86cda117e914c02d" +dependencies = [ + "iso7816", +] + +[[package]] +name = "apdu-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5ab921a56bbe68325ba6d3711ee2c681239fe4c9c295c6a1c2fe6992e27f86" + +[[package]] +name = "apdu-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd675f7ce10250005ac39b9ee8e618fe51370ce6f39170559726cdd0ff7fe7c" +dependencies = [ + "apdu-core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.17", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", + "synstructure 0.13.2", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-url" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b428e9fb429c6fda7316e9b006f993e6b4c33005e4659339fb5214479dddec" +dependencies = [ + "base64", +] + +[[package]] +name = "base64ct" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" + +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.111", + "which", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.10.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.111", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "bluez-async" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84ae4213cc2a8dc663acecac67bbdad05142be4d8ef372b6903abf878b0c690a" +dependencies = [ + "bitflags 2.10.0", + "bluez-generated", + "dbus", + "dbus-tokio", + "futures", + "itertools 0.14.0", + "log", + "serde", + "serde-xml-rs", + "thiserror 2.0.17", + "tokio", + "uuid", +] + +[[package]] +name = "bluez-generated" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676783265eadd6f11829982792c6f303f3854d014edfba384685dcf237dd062" +dependencies = [ + "dbus", +] + +[[package]] +name = "btleplug" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a11621cb2c8c024e444734292482b1ad86fb50ded066cf46252e46643c8748" +dependencies = [ + "async-trait", + "bitflags 2.10.0", + "bluez-async", + "dashmap 6.1.0", + "dbus", + "futures", + "jni", + "jni-utils", + "log", + "objc2", + "objc2-core-bluetooth", + "objc2-foundation", + "once_cell", + "static_assertions", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "uuid", + "windows 0.61.3", + "windows-future", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cbor-smol" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6dd31f7069836e87169bc5910212571b873cebe389c7c7f2d8b1fb3e55c80d" +dependencies = [ + "delog", + "heapless", + "heapless-bytes", + "serde_core", +] + +[[package]] +name = "cc" +version = "1.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cosey" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75494895fa1a9713ca725ddf2db084ee84fb0c20938fdd7c89293febe732d30a" +dependencies = [ + "heapless-bytes", + "serde", + "serde_repr", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctap-types" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb8b105c5e728afd373e99874f0c1911c170b3a56848456cc16feb4506321606" +dependencies = [ + "bitflags 1.3.2", + "cbor-smol", + "cosey", + "delog", + "heapless", + "heapless-bytes", + "iso7816", + "serde", + "serde-indexed 0.1.1", + "serde_bytes", + "serde_repr", +] + +[[package]] +name = "ctaphid" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa622743e1747e48d25170854b552b3ddc753125a39a6732e57c5c7a5ff7fe11" +dependencies = [ + "ctaphid-types", + "hex", + "log", + "rand_core 0.6.4", + "tap", +] + +[[package]] +name = "ctaphid-app" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe93489fe96c998488d0843dffea35c02ed9add2585e55228e1d45988727ecc" +dependencies = [ + "heapless-bytes", + "trussed-core", +] + +[[package]] +name = "ctaphid-dispatch" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fd4316573df369820c5a9f8285fe522d8871c0b20bcf7d390f73b8e6caee28" +dependencies = [ + "ctaphid-app", + "delog", + "heapless-bytes", + "interchange", + "ref-swap", + "trussed-core", +] + +[[package]] +name = "ctaphid-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4714cdd86d5134532b9decaa6774db0a6851ecd07e96a2f239332ae1f3239350" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "dbus" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b3aa68d7e7abee336255bd7248ea965cc393f3e70411135a6f6a4b651345d4" +dependencies = [ + "futures-channel", + "futures-util", + "libc", + "libdbus-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "dbus-tokio" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007688d459bc677131c063a3a77fb899526e17b7980f390b69644bdbc41fad13" +dependencies = [ + "dbus", + "libc", + "tokio", +] + +[[package]] +name = "delog" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed991f9823b19e8a0380e198dcbb6aa6ac82727b40bfecd2c6cc634f46b7e01c" +dependencies = [ + "log", +] + +[[package]] +name = "der" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +dependencies = [ + "crypto-bigint 0.2.5", + "der_derive", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aed3b3c608dc56cf36c45fe979d04eda51242e6703d8d0bb03426ef7c41db6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +dependencies = [ + "der 0.4.5", + "elliptic-curve 0.10.4", + "hmac 0.11.0", + "signature 1.3.2", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.10", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979", + "serdect", + "signature 2.2.0", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.2.0", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" +dependencies = [ + "crypto-bigint 0.2.5", + "ff 0.10.1", + "generic-array", + "group 0.10.0", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.1", + "generic-array", + "group 0.13.0", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fido-authenticator" +version = "0.1.1" +source = "git+https://github.com/Nitrokey/fido-authenticator.git?tag=v0.1.1-nitrokey.27#5ebb4a48302e4c80a2abe1c2d86201a3df2a1d2d" +dependencies = [ + "apdu-app", + "cbor-smol", + "cosey", + "ctap-types", + "ctaphid-app", + "delog", + "heapless", + "heapless-bytes", + "iso7816", + "littlefs2-core", + "serde", + "serde-indexed 0.1.1", + "serde_bytes", + "sha2 0.10.9", + "trussed-core", + "trussed-fs-info", + "trussed-hkdf", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + +[[package]] +name = "find-winsdk" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8cbf17b871570c1f8612b763bac3e86290602bcf5dc3c5ce657e0e1e9071d9e" +dependencies = [ + "serde", + "serde_derive", + "winreg", +] + +[[package]] +name = "flexiber" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2510a9088d9557aab93401404fc6786fad82f55705dedf4ee5884a3ace9be9b" +dependencies = [ + "delog", + "flexiber_derive", + "heapless", +] + +[[package]] +name = "flexiber_derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9985657bc39bae5cb7f4e686b46c67b1ea37390d82fe4bab56d7cd1933429d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", + "synstructure 0.13.2", +] + +[[package]] +name = "fragile" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.48.0", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "ff 0.10.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "heapless-bytes" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7285eba272c6af3e9f15fb9e1c1b6e7d35aa70580ffe0d47af017e97dfb6f48b" +dependencies = [ + "heapless", + "serde", + "typenum", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hidapi" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "565dd4c730b8f8b2c0fb36df6be12e5470ae10895ddcc4e9dcfbfb495de202b0" +dependencies = [ + "cc", + "cfg-if", + "libc", + "pkg-config", + "windows-sys 0.48.0", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "image" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", +] + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "interchange" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc2a6b02f14a47afb0dbccdf96ae4f527ab32b05f78918d9da92e336bcbc222" +dependencies = [ + "loom", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "iso7816" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c7e91da489667bb054f9cd2f1c60cc2ac4478a899f403d11dbc62189215b0" +dependencies = [ + "heapless", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jni-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259e9f2c3ead61de911f147000660511f07ab00adeed1d84f5ac4d0386e7a6c4" +dependencies = [ + "dashmap 5.5.3", + "futures", + "jni", + "log", + "once_cell", + "static_assertions", + "uuid", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + +[[package]] +name = "libwebauthn" +version = "0.2.2" +dependencies = [ + "aes", + "apdu", + "apdu-core", + "async-trait", + "base64-url", + "bitflags 2.10.0", + "btleplug", + "byteorder", + "cbc", + "cosey", + "ctap-types", + "ctaphid", + "ctaphid-dispatch", + "curve25519-dalek", + "dbus", + "delog", + "fido-authenticator", + "futures", + "heapless", + "hex", + "hidapi", + "hkdf", + "hmac 0.12.1", + "interchange", + "littlefs2", + "maplit", + "mockall", + "nfc1", + "nfc1-sys", + "num-derive", + "num-traits", + "num_enum", + "p256 0.13.2", + "pcsc", + "qrcode", + "rand 0.8.5", + "rustls", + "serde", + "serde-indexed 0.2.0", + "serde_bytes", + "serde_cbor_2", + "serde_derive", + "serde_json", + "serde_repr", + "sha2 0.10.9", + "snow", + "tempfile", + "test-log", + "text_io", + "thiserror 2.0.17", + "time", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tracing", + "tracing-subscriber", + "trussed", + "trussed-staging", + "tungstenite", + "uuid", + "x509-parser", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "littlefs2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a43f3c0c6a7d127e3e1241665dd896d8bf1ca31cf9d826a1dc65239bd59868" +dependencies = [ + "delog", + "generic-array", + "heapless", + "littlefs2-core", + "littlefs2-sys", +] + +[[package]] +name = "littlefs2-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd2d1cad5532f5e11b0fd871b8a981885efd3fdaec0427c0d637322ae09efbf" +dependencies = [ + "bitflags 2.10.0", + "heapless-bytes", + "serde", +] + +[[package]] +name = "littlefs2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f7d54a8325846d818335f6e0a3ce4d4ff1d6a5cea7be989a76913dcb73afdc" +dependencies = [ + "bindgen 0.70.1", + "cc", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "mockall" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nfc1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d6dc2e4110af159c220d2d004661e380b6c40d93c5b04e839e4944f9d5291d" +dependencies = [ + "nfc1-sys", +] + +[[package]] +name = "nfc1-sys" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6652c6cdf52433ff143439595ffb4b945afafbe5f27cec8d2fc5dfb5832796e8" +dependencies = [ + "bindgen 0.65.1", + "cc", + "find-winsdk", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-core-bluetooth" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a644b62ffb826a5277f536cf0f701493de420b13d40e700c452c36567771111" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.10.0", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "p256" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" +dependencies = [ + "ecdsa 0.12.4", + "elliptic-curve 0.10.4", + "sha2 0.9.9", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "serdect", + "sha2 0.10.9", +] + +[[package]] +name = "p256-cortex-m4" +version = "0.1.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647353e42d97cbbc7018cb27c0258a7f5ec1db69a0ac336bd954f468a66af38a" +dependencies = [ + "der 0.4.5", + "ecdsa 0.12.4", + "elliptic-curve 0.10.4", + "p256 0.9.0", + "p256-cortex-m4-sys", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "p256-cortex-m4-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a73da4b90c4bb139ff5cca5526f796451cfeea58f5915bc739df36803977de" +dependencies = [ + "cc", + "cty", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "pcsc" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd833ecf8967e65934c49d3521a175929839bf6d0e497f3bd0d3a2ca08943da" +dependencies = [ + "bitflags 2.10.0", + "pcsc-sys", +] + +[[package]] +name = "pcsc-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ef017e15d2e5592a9e39a346c1dbaea5120bab7ed7106b210ef58ebd97003" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.10", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "postcard" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25c0b0ae06fcffe600ad392aabfa535696c8973f2253d9ac83171924c58a858" +dependencies = [ + "heapless", + "postcard-cobs", + "serde", +] + +[[package]] +name = "postcard-cobs" +version = "0.1.5-pre" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c68cb38ed13fd7bc9dd5db8f165b7c8d9c1a315104083a2b10f11354c2af97f" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.111", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", + "serdect", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pxfm" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "qrcode" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" +dependencies = [ + "image", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "ref-swap" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c30c54dffee5b40af088d5d50aa3455c91a0127164b51f0215efc4cb28fb3c" + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "salty" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b947325a585e90733e0e9ec097228f40b637cc346f9bd68f84d5c6297d0fcfef" +dependencies = [ + "cosey", + "ed25519", + "subtle", + "zeroize", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der 0.7.10", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.10.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-byte-array" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63213ee4ed648dbd87db6fa993d4275b46bfb4ddfd95b3756045007c2b28f742" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-indexed" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "serde-indexed" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "serde-xml-rs" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2215ce3e6a77550b80a1c37251b7d294febaf42e36e21b7b411e0bf54d540d" +dependencies = [ + "log", + "serde", + "thiserror 2.0.17", + "xml", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_cbor_2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aec2709de9078e077090abd848e967abab63c9fb3fdb5d4799ad359d8d482c" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "serde_json" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "snow" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "599b506ccc4aff8cf7844bc42cf783009a434c1e26c964432560fb6d6ad02d82" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "getrandom 0.3.4", + "p256 0.13.2", + "ring", + "rustc_version", + "sha2 0.10.9", + "subtle", +] + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.10", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix 1.1.3", + "windows-sys 0.61.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "test-log" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d53ac171c92a39e4769491c4b4dde7022c60042254b5fc044ae409d34a24d4" +dependencies = [ + "env_logger", + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "text_io" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d8d3ca3b06292094e03841d8995e910712d2a10b5869c8f9725385b29761115" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "trussed" +version = "0.1.0" +source = "git+https://github.com/trussed-dev/trussed.git?rev=024e0eca5fb7dbd2457831f7c7bffe4341e08775#024e0eca5fb7dbd2457831f7c7bffe4341e08775" +dependencies = [ + "aes", + "bitflags 2.10.0", + "cbc", + "cbor-smol", + "cfg-if", + "chacha20", + "chacha20poly1305", + "cosey", + "delog", + "des", + "flexiber", + "generic-array", + "heapless", + "heapless-bytes", + "hex-literal", + "hmac 0.12.1", + "interchange", + "littlefs2", + "littlefs2-core", + "nb", + "p256-cortex-m4", + "postcard", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "salty", + "serde", + "sha-1", + "sha2 0.10.9", + "trussed-core", + "zeroize", +] + +[[package]] +name = "trussed-chunked" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9268d9d812440965ce31684e0115ceafa2636b7a8cc04dc117594567c53ff75e" +dependencies = [ + "serde", + "serde-byte-array", + "trussed-core", +] + +[[package]] +name = "trussed-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddad280ae8a5235e1b06408cca909ce9454cdd89f941b94b024c580732b3ce" +dependencies = [ + "heapless-bytes", + "littlefs2-core", + "postcard", + "rand_core 0.6.4", + "serde", + "serde-indexed 0.1.1", +] + +[[package]] +name = "trussed-fs-info" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44822e0abc5a32b3f370f82644ee9cb08aa693847aac0d48f6dc115389157aea" +dependencies = [ + "serde", + "serde-byte-array", + "trussed-core", +] + +[[package]] +name = "trussed-hkdf" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17884daee9214e24c7bb9cf2429d0f53c569cfa4a8d728106e459e60aed5be69" +dependencies = [ + "serde", + "trussed-core", +] + +[[package]] +name = "trussed-staging" +version = "0.3.2" +source = "git+https://github.com/trussed-dev/trussed-staging.git?rev=7922d67e9637a87e5625aaff9e5111f0d4ec0346#7922d67e9637a87e5625aaff9e5111f0d4ec0346" +dependencies = [ + "chacha20poly1305", + "delog", + "digest 0.10.7", + "hkdf", + "littlefs2-core", + "rand_core 0.6.4", + "salty", + "serde", + "serde-byte-array", + "sha2 0.10.9", + "trussed", + "trussed-chunked", + "trussed-fs-info", + "trussed-hkdf", +] + +[[package]] +name = "tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror 2.0.17", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.111", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" +dependencies = [ + "serde", + "winapi", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.17", + "time", +] + +[[package]] +name = "xml" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "zmij" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a" diff --git a/libwebauthn/src/proto/ctap2/model.rs b/libwebauthn/src/proto/ctap2/model.rs index 7f137e1a..cd84ecbf 100644 --- a/libwebauthn/src/proto/ctap2/model.rs +++ b/libwebauthn/src/proto/ctap2/model.rs @@ -237,9 +237,9 @@ pub enum Ctap2UserVerificationOperation { #[cfg(test)] mod tests { - use crate::ops::webauthn::idl::Base64UrlString; use crate::proto::ctap2::cbor; use crate::proto::ctap2::Ctap2PublicKeyCredentialDescriptor; + use serde_bytes::ByteBuf; use super::{Ctap2COSEAlgorithmIdentifier, Ctap2CredentialType, Ctap2PublicKeyCredentialType}; use hex; @@ -262,7 +262,7 @@ mod tests { /// Verify CBOR serialization conforms to CTAP canonical standard, including ordering (see #95) pub fn credential_descriptor_serialization() { let credential_descriptor = Ctap2PublicKeyCredentialDescriptor { - id: Base64UrlString::from(vec![0x42]), + id: ByteBuf::from(vec![0x42]), r#type: Ctap2PublicKeyCredentialType::PublicKey, transports: None, }; diff --git a/libwebauthn/src/proto/ctap2/preflight.rs b/libwebauthn/src/proto/ctap2/preflight.rs index e6f339a5..a1164896 100644 --- a/libwebauthn/src/proto/ctap2/preflight.rs +++ b/libwebauthn/src/proto/ctap2/preflight.rs @@ -127,7 +127,8 @@ mod tests { let challenge: [u8; 32] = thread_rng().gen(); let make_credentials_request = MakeCredentialRequest { origin: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -151,7 +152,9 @@ mod tests { let challenge: [u8; 32] = thread_rng().gen(); let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_owned(), + cross_origin: None, allow: allow_list, user_verification: UserVerificationRequirement::Discouraged, extensions: None, diff --git a/libwebauthn/src/tests/prf.rs b/libwebauthn/src/tests/prf.rs index 95666b4a..50f9f1f6 100644 --- a/libwebauthn/src/tests/prf.rs +++ b/libwebauthn/src/tests/prf.rs @@ -108,7 +108,8 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { // Make Credentials ceremony let make_credentials_request = MakeCredentialRequest { origin: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + cross_origin: None, relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"), resident_key: Some(ResidentKeyRequirement::Discouraged), @@ -169,7 +170,9 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { (&response.authenticator_data).try_into().unwrap(); let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_owned(), + cross_origin: None, allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, extensions: None, @@ -483,7 +486,9 @@ async fn run_success_test( ) { let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_owned(), + cross_origin: None, allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, extensions: Some(GetAssertionRequestExtensions { @@ -548,7 +553,9 @@ async fn run_failed_test( ) { let get_assertion = GetAssertionRequest { relying_party_id: "example.org".to_owned(), - hash: Vec::from(challenge), + challenge: Vec::from(challenge), + origin: "example.org".to_owned(), + cross_origin: None, allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { diff --git a/libwebauthn/src/webauthn/pin_uv_auth_token.rs b/libwebauthn/src/webauthn/pin_uv_auth_token.rs index 0072bf73..46957965 100644 --- a/libwebauthn/src/webauthn/pin_uv_auth_token.rs +++ b/libwebauthn/src/webauthn/pin_uv_auth_token.rs @@ -481,7 +481,9 @@ mod test { Ctap2GetAssertionRequest::from_webauthn_request( &GetAssertionRequest { relying_party_id: String::from("example.com"), - hash: vec![9; 32], + challenge: vec![9; 32], + origin: String::from("example.com"), + cross_origin: None, allow: vec![], extensions, user_verification: UserVerificationRequirement::Preferred, From 7933f7cf67d66aefe4e983db994f8840aa7f3701 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 15:42:24 -0500 Subject: [PATCH 20/28] Fix: hmac_get_secret typo --- libwebauthn/src/ops/webauthn/get_assertion.rs | 2 +- libwebauthn/src/ops/webauthn/idl/get.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index dc1e10be..c85500de 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -86,7 +86,7 @@ impl FromInnerModel, #[serde(rename = "hmacCreateSecret")] - pub hamc_get_secret: Option, + pub hmac_get_secret: Option, #[serde(rename = "prf")] pub prf: Option, } From acf8b7b2fb1773aa809be301d6faf7158ca3afe0 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 15:44:09 -0500 Subject: [PATCH 21/28] Feedback: From rather than Into --- libwebauthn/src/ops/webauthn/idl/base64url.rs | 6 +++--- libwebauthn/src/ops/webauthn/idl/get.rs | 10 +++++----- libwebauthn/src/ops/webauthn/idl/rpid.rs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/idl/base64url.rs b/libwebauthn/src/ops/webauthn/idl/base64url.rs index 8d5e43e4..ebd805f7 100644 --- a/libwebauthn/src/ops/webauthn/idl/base64url.rs +++ b/libwebauthn/src/ops/webauthn/idl/base64url.rs @@ -54,9 +54,9 @@ impl Serialize for Base64UrlString { } } -impl Into> for Base64UrlString { - fn into(self) -> Vec { - self.0 +impl From for Vec { + fn from(b64: Base64UrlString) -> Vec { + b64.0 } } diff --git a/libwebauthn/src/ops/webauthn/idl/get.rs b/libwebauthn/src/ops/webauthn/idl/get.rs index f19d0ef2..6ab44ad8 100644 --- a/libwebauthn/src/ops/webauthn/idl/get.rs +++ b/libwebauthn/src/ops/webauthn/idl/get.rs @@ -35,12 +35,12 @@ pub struct PublicKeyCredentialDescriptorJSON { pub transports: Option>, } -impl Into for PublicKeyCredentialDescriptorJSON { - fn into(self) -> Ctap2PublicKeyCredentialDescriptor { +impl From for Ctap2PublicKeyCredentialDescriptor { + fn from(value: PublicKeyCredentialDescriptorJSON) -> Self { Ctap2PublicKeyCredentialDescriptor { - r#type: self.r#type, - id: ByteBuf::from(self.id), - transports: self.transports, + r#type: value.r#type, + id: ByteBuf::from(value.id), + transports: value.transports, } } } diff --git a/libwebauthn/src/ops/webauthn/idl/rpid.rs b/libwebauthn/src/ops/webauthn/idl/rpid.rs index a92b12be..b5687142 100644 --- a/libwebauthn/src/ops/webauthn/idl/rpid.rs +++ b/libwebauthn/src/ops/webauthn/idl/rpid.rs @@ -12,9 +12,9 @@ impl Deref for RelyingPartyId { } } -impl Into for RelyingPartyId { - fn into(self) -> String { - self.0 +impl From for String { + fn from(rpid: RelyingPartyId) -> String { + rpid.0 } } From 509a22f9ca26023090319026a86e11a6086dd2e7 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 15:46:47 -0500 Subject: [PATCH 22/28] Feedback: use rename_all=camelCase --- libwebauthn/src/ops/webauthn/idl/create.rs | 11 +++-------- libwebauthn/src/ops/webauthn/make_credential.rs | 14 +++----------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/idl/create.rs b/libwebauthn/src/ops/webauthn/idl/create.rs index c2bf23c4..fb5444dc 100644 --- a/libwebauthn/src/ops/webauthn/idl/create.rs +++ b/libwebauthn/src/ops/webauthn/idl/create.rs @@ -15,15 +15,12 @@ use serde::Deserialize; */ #[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct AuthenticatorSelectionCriteria { - #[serde(rename = "authenticatorAttachment")] pub authenticator_attachment: Option, - #[serde(rename = "residentKey")] pub resident_key: Option, - #[serde(rename = "requireResidentKey")] #[serde(default)] pub require_resident_key: bool, - #[serde(rename = "userVerification")] #[serde(default = "default_user_verification")] pub user_verification: UserVerificationRequirement, } @@ -33,14 +30,15 @@ fn default_user_verification() -> UserVerificationRequirement { } #[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct PublicKeyCredentialUserEntity { pub id: Base64UrlString, pub name: String, - #[serde(rename = "displayName")] pub display_name: String, } #[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct PublicKeyCredentialCreationOptionsJSON { pub rp: Ctap2PublicKeyCredentialRpEntity, pub user: PublicKeyCredentialUserEntity, @@ -48,13 +46,10 @@ pub struct PublicKeyCredentialCreationOptionsJSON { #[serde(rename = "pubKeyCredParams")] pub params: Vec, pub timeout: Option, - #[serde(rename = "excludeCredentials")] pub exclude_credentials: Vec, - #[serde(rename = "authenticatorSelection")] pub authenticator_selection: Option, pub hints: Option>, pub attestation: Option, - #[serde(rename = "attestationFormats")] pub attestation_formats: Option>, pub extensions: Option, } diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 0e6dd251..5aa0aef2 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -273,20 +273,18 @@ pub struct MakeCredentialPrfOutput { } #[derive(Debug, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct CredentialProtectionExtension { - #[serde(rename = "credentialProtectionPolicy")] pub policy: CredentialProtectionPolicy, - #[serde(rename = "enforceCredentialProtectionPolicy")] pub enforce_policy: bool, } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] pub enum CredentialProtectionPolicy { - #[serde(rename = "userVerificationOptional")] UserVerificationOptional = 1, #[serde(rename = "userVerificationOptionalWithCredentialIDList")] UserVerificationOptionalWithCredentialIDList = 2, - #[serde(rename = "userVerificationRequired")] UserVerificationRequired = 3, } @@ -352,20 +350,14 @@ pub struct MakeCredentialLargeBlobExtensionOutput { } #[derive(Debug, Default, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct MakeCredentialsRequestExtensions { - #[serde(rename = "credProps")] pub cred_props: Option, - #[serde(rename = "credProtect")] pub cred_protect: Option, - #[serde(rename = "credBlob")] pub cred_blob: Option, - #[serde(rename = "largeBlob")] pub large_blob: Option, - #[serde(rename = "minPinLength")] pub min_pin_length: Option, - #[serde(rename = "hmacCreateSecret")] pub hmac_create_secret: Option, - #[serde(rename = "prf")] pub prf: Option, } From 93f6b3b21776ec6b6360c34495f72e704fe880f9 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 15:51:32 -0500 Subject: [PATCH 23/28] Feedback: Other minor fixes --- libwebauthn/examples/webauthn_json_hid.rs | 1 - libwebauthn/examples/webauthn_prf_hid.rs | 2 +- libwebauthn/src/ops/webauthn/client_data.rs | 8 +++++--- libwebauthn/src/ops/webauthn/get_assertion.rs | 2 ++ libwebauthn/src/ops/webauthn/make_credential.rs | 7 ++++++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libwebauthn/examples/webauthn_json_hid.rs b/libwebauthn/examples/webauthn_json_hid.rs index 4b08ac24..8005e044 100644 --- a/libwebauthn/examples/webauthn_json_hid.rs +++ b/libwebauthn/examples/webauthn_json_hid.rs @@ -76,7 +76,6 @@ pub async fn main() -> Result<(), Box> { let mut channel = device.channel().await?; channel.wink(TIMEOUT).await?; - // Relying let rpid = RelyingPartyId("example.org".to_owned()); let request_json = r#" { diff --git a/libwebauthn/examples/webauthn_prf_hid.rs b/libwebauthn/examples/webauthn_prf_hid.rs index e2798152..6ae845a5 100644 --- a/libwebauthn/examples/webauthn_prf_hid.rs +++ b/libwebauthn/examples/webauthn_prf_hid.rs @@ -148,7 +148,7 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf: GetAssertionHmacOrPrfInput = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { eval, eval_by_credential, }); diff --git a/libwebauthn/src/ops/webauthn/client_data.rs b/libwebauthn/src/ops/webauthn/client_data.rs index 9145a480..2c614b78 100644 --- a/libwebauthn/src/ops/webauthn/client_data.rs +++ b/libwebauthn/src/ops/webauthn/client_data.rs @@ -4,12 +4,15 @@ use serde::Deserialize; use sha2::{Digest, Sha256}; #[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ClientData { pub operation: Operation, pub challenge: Vec, pub origin: String, - #[serde(rename = "crossOrigin")] pub cross_origin: Option, + /// The origin of the top-level document, if in an iframe. + /// https://www.w3.org/TR/webauthn-3/#dom-collectedclientdata-toporigin + pub top_origin: Option, } impl ClientData { @@ -25,7 +28,7 @@ impl ClientData { } else { "false" }; - let json = + let json = format!("{{\"type\":\"{op_str}\",\"challenge\":\"{challenge_str}\",\"origin\":\"{origin_str}\",\"crossOrigin\":{cross_origin_str}}}"); let mut hasher = Sha256::new(); @@ -33,4 +36,3 @@ impl ClientData { hasher.finalize().to_vec() } } - diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index c85500de..c9c7fbcf 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -123,6 +123,7 @@ impl FromInnerModel for MakeCredentialRequest { #[derive(Debug, Clone, Deserialize, PartialEq)] pub struct MakeCredentialPrfInput { + /// The `eval` field is parsed but not used during credential creation. + /// PRF evaluation only occurs during assertion (getAssertion), not registration. + /// We parse it here to accept valid WebAuthn JSON input without errors. #[serde(rename = "eval")] pub _eval: Option, } @@ -498,6 +502,7 @@ mod tests { .unwrap(), origin: "example.org".to_string(), cross_origin: None, + top_origin: None, } .hash(), relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"), From f39c9ca5ca2eb797efdaa9c094a658f01e59a9c8 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 15:57:27 -0500 Subject: [PATCH 24/28] Feedback: Other minor fixex, simplfiied parsing chain --- libwebauthn/src/ops/webauthn/get_assertion.rs | 16 +++++++--------- libwebauthn/src/ops/webauthn/make_credential.rs | 8 +++----- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index c9c7fbcf..3c8d88b9 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -105,11 +105,7 @@ impl FromInnerModel::try_from) - .transpose() - .ok() - .flatten() - .flatten(), + .and_then(|lb| GetAssertionLargeBlobExtension::try_from(lb).ok()), hmac_or_prf: hmac_or_prf.clone(), }); @@ -202,7 +198,7 @@ impl TryFrom for PrfInput { }, )) }) - .collect::, GetAssertionRequestParsingError>>()?, + .collect::, _>>()?, None => HashMap::new(), }; @@ -255,16 +251,18 @@ pub enum GetAssertionLargeBlobExtension { // Write(Vec), } -impl TryFrom for Option { +impl TryFrom for GetAssertionLargeBlobExtension { type Error = GetAssertionRequestParsingError; fn try_from(value: LargeBlobInputJson) -> Result { match value.read { - Some(true) => Ok(Some(GetAssertionLargeBlobExtension::Read)), + Some(true) => Ok(GetAssertionLargeBlobExtension::Read), Some(false) => Err(GetAssertionRequestParsingError::NotSupported( "largeBlob writes not supported".to_string(), )), - None => Ok(None), + None => Err(GetAssertionRequestParsingError::NotSupported( + "largeBlob read not requested".to_string(), + )), } } } diff --git a/libwebauthn/src/ops/webauthn/make_credential.rs b/libwebauthn/src/ops/webauthn/make_credential.rs index 0fa0a0cc..8bbb7ec9 100644 --- a/libwebauthn/src/ops/webauthn/make_credential.rs +++ b/libwebauthn/src/ops/webauthn/make_credential.rs @@ -161,12 +161,11 @@ impl MakeCredentialsResponseUnsignedExtensions { } #[derive(Debug, Clone, Copy, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] pub enum ResidentKeyRequirement { - #[serde(rename = "required")] Required, - #[serde(rename = "preferred")] Preferred, - #[serde(rename = "discouraged", other)] + #[serde(other)] Discouraged, } @@ -337,10 +336,9 @@ pub struct MakeCredentialLargeBlobExtensionInput { } #[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] pub enum MakeCredentialLargeBlobExtension { - #[serde(rename = "preferred")] Preferred, - #[serde(rename = "required")] Required, #[default] #[serde(other)] From 3da40433f9827c37aa08a4645c9381f4db40a067 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 15:59:39 -0500 Subject: [PATCH 25/28] Feedback: More rename_all --- libwebauthn/src/ops/webauthn/get_assertion.rs | 2 +- libwebauthn/src/ops/webauthn/idl/get.rs | 6 ++---- libwebauthn/src/ops/webauthn/mod.rs | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 3c8d88b9..259cade5 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -198,7 +198,7 @@ impl TryFrom for PrfInput { }, )) }) - .collect::, _>>()?, + .collect::, GetAssertionRequestParsingError>>()?, None => HashMap::new(), }; diff --git a/libwebauthn/src/ops/webauthn/idl/get.rs b/libwebauthn/src/ops/webauthn/idl/get.rs index 6ab44ad8..88345d32 100644 --- a/libwebauthn/src/ops/webauthn/idl/get.rs +++ b/libwebauthn/src/ops/webauthn/idl/get.rs @@ -11,15 +11,14 @@ use crate::{ }; #[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] pub struct PublicKeyCredentialRequestOptionsJSON { pub challenge: Base64UrlString, pub timeout: Option, #[serde(rename = "rpId")] pub relying_party_id: Option, - #[serde(rename = "allowCredentials")] #[serde(default)] pub allow_credentials: Vec, - #[serde(rename = "userVerification")] pub uv_requirement: UserVerificationRequirement, #[serde(default)] pub hints: Vec, @@ -46,14 +45,13 @@ impl From for Ctap2PublicKeyCredentialDescrip } #[derive(Debug, Clone, Default, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct GetAssertionRequestExtensionsJSON { #[serde(rename = "getCredBlob")] pub cred_blob: Option, #[serde(rename = "largeBlobKey")] pub large_blob: Option, - #[serde(rename = "hmacCreateSecret")] pub hmac_get_secret: Option, - #[serde(rename = "prf")] pub prf: Option, } diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index 382fd9e9..9b908f1a 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -30,12 +30,11 @@ pub enum Operation { } #[derive(Debug, Clone, Copy, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] pub enum UserVerificationRequirement { - #[serde(rename = "required")] Required, - #[serde(rename = "discouraged")] Discouraged, - #[serde(rename = "preferred", other)] + #[serde(other)] Preferred, } From 69794ffbfe557aad1234783af7c23561355228ba Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 16:58:52 -0500 Subject: [PATCH 26/28] Feedback: Fix UV field naming for JSON IDL conformance - Rename 'uv_requirement' to 'user_verification' to match WebAuthn IDL - Add Default derive for UserVerificationRequirement (required by serde) - Update references in get_assertion.rs --- libwebauthn/src/ops/webauthn/get_assertion.rs | 2 +- libwebauthn/src/ops/webauthn/idl/get.rs | 3 ++- libwebauthn/src/ops/webauthn/mod.rs | 15 +++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index 259cade5..af1a9902 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -131,7 +131,7 @@ impl FromInnerModel, #[serde(default)] pub allow_credentials: Vec, - pub uv_requirement: UserVerificationRequirement, + #[serde(rename = "userVerification", default)] + pub user_verification: UserVerificationRequirement, #[serde(default)] pub hints: Vec, pub extensions: Option, diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index 9b908f1a..bae8a474 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -7,12 +7,14 @@ mod timeout; use super::u2f::{RegisterRequest, SignRequest}; use crate::webauthn::CtapError; pub use get_assertion::{ - Assertion, Ctap2HMACGetSecretOutput, GetAssertionHmacOrPrfInput, - GetAssertionLargeBlobExtension, GetAssertionLargeBlobExtensionOutput, GetAssertionPrfOutput, - GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, - GetAssertionResponseExtensions, GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, - HMACGetSecretOutput, PRFValue, PrfInput, + Assertion, Ctap2HMACGetSecretOutput, GetAssertionLargeBlobExtension, + GetAssertionLargeBlobExtensionOutput, GetAssertionPrfOutput, GetAssertionRequest, + GetAssertionRequestExtensions, GetAssertionResponse, GetAssertionResponseExtensions, + GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, HMACGetSecretOutput, PRFValue, + PrfInput, }; +// Internal re-export for CTAP layer +pub(crate) use get_assertion::GetAssertionHmacOrPrfInput; pub use idl::{rpid::RelyingPartyId, Base64UrlString, WebAuthnIDL}; pub use make_credential::{ CredentialPropsExtension, CredentialProtectionExtension, CredentialProtectionPolicy, @@ -29,11 +31,12 @@ pub enum Operation { GetAssertion, } -#[derive(Debug, Clone, Copy, Deserialize, PartialEq)] +#[derive(Debug, Clone, Copy, Default, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum UserVerificationRequirement { Required, Discouraged, + #[default] #[serde(other)] Preferred, } From 9c51e1ad10d2e848c13bef72a44d616cc3412435 Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 17:03:29 -0500 Subject: [PATCH 27/28] Feedback: Fix build. --- libwebauthn/src/ops/webauthn/mod.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libwebauthn/src/ops/webauthn/mod.rs b/libwebauthn/src/ops/webauthn/mod.rs index bae8a474..b05b6454 100644 --- a/libwebauthn/src/ops/webauthn/mod.rs +++ b/libwebauthn/src/ops/webauthn/mod.rs @@ -7,14 +7,12 @@ mod timeout; use super::u2f::{RegisterRequest, SignRequest}; use crate::webauthn::CtapError; pub use get_assertion::{ - Assertion, Ctap2HMACGetSecretOutput, GetAssertionLargeBlobExtension, - GetAssertionLargeBlobExtensionOutput, GetAssertionPrfOutput, GetAssertionRequest, - GetAssertionRequestExtensions, GetAssertionResponse, GetAssertionResponseExtensions, - GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, HMACGetSecretOutput, PRFValue, - PrfInput, + Assertion, Ctap2HMACGetSecretOutput, GetAssertionHmacOrPrfInput, + GetAssertionLargeBlobExtension, GetAssertionLargeBlobExtensionOutput, GetAssertionPrfOutput, + GetAssertionRequest, GetAssertionRequestExtensions, GetAssertionResponse, + GetAssertionResponseExtensions, GetAssertionResponseUnsignedExtensions, HMACGetSecretInput, + HMACGetSecretOutput, PRFValue, PrfInput, }; -// Internal re-export for CTAP layer -pub(crate) use get_assertion::GetAssertionHmacOrPrfInput; pub use idl::{rpid::RelyingPartyId, Base64UrlString, WebAuthnIDL}; pub use make_credential::{ CredentialPropsExtension, CredentialProtectionExtension, CredentialProtectionPolicy, From e57fbc04aaff3cfd8e3600432582f84c67bc18de Mon Sep 17 00:00:00 2001 From: Alfie Fresta Date: Sat, 24 Jan 2026 16:59:51 -0500 Subject: [PATCH 28/28] Web IDL support 2/N: drop HMAC from WebAuthn ops --- libwebauthn/examples/prf_test.rs | 14 ++-- .../examples/webauthn_extensions_hid.rs | 19 ++--- libwebauthn/examples/webauthn_prf_hid.rs | 72 +++++++++---------- libwebauthn/src/ops/webauthn/get_assertion.rs | 31 ++++---- .../src/proto/ctap2/model/get_assertion.rs | 41 +++++------ libwebauthn/src/tests/prf.rs | 67 +++++++++-------- libwebauthn/src/webauthn/pin_uv_auth_token.rs | 69 +++++++++--------- 7 files changed, 158 insertions(+), 155 deletions(-) diff --git a/libwebauthn/examples/prf_test.rs b/libwebauthn/examples/prf_test.rs index f4e81cd6..4ac40f93 100644 --- a/libwebauthn/examples/prf_test.rs +++ b/libwebauthn/examples/prf_test.rs @@ -13,8 +13,8 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, PRFValue, - PrfInput, UserVerificationRequirement, + GetAssertionRequest, GetAssertionRequestExtensions, PRFValue, PrfInput, + UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialType}; @@ -126,16 +126,16 @@ pub async fn main() -> Result<(), Box> { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "PRF output: ", ) .await; @@ -147,7 +147,7 @@ async fn run_success_test( channel: &mut HidChannel<'_>, credential: &Ctap2PublicKeyCredentialDescriptor, challenge: &[u8; 32], - hmac_or_prf: GetAssertionHmacOrPrfInput, + prf: PrfInput, printoutput: &str, ) { let get_assertion = GetAssertionRequest { @@ -156,7 +156,7 @@ async fn run_success_test( allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(hmac_or_prf), + prf: Some(prf), ..Default::default() }), timeout: TIMEOUT, diff --git a/libwebauthn/examples/webauthn_extensions_hid.rs b/libwebauthn/examples/webauthn_extensions_hid.rs index 1feef5f8..0c221680 100644 --- a/libwebauthn/examples/webauthn_extensions_hid.rs +++ b/libwebauthn/examples/webauthn_extensions_hid.rs @@ -10,9 +10,9 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - CredentialProtectionExtension, CredentialProtectionPolicy, GetAssertionHmacOrPrfInput, - GetAssertionRequest, GetAssertionRequestExtensions, HMACGetSecretInput, MakeCredentialRequest, - MakeCredentialsRequestExtensions, ResidentKeyRequirement, UserVerificationRequirement, + CredentialProtectionExtension, CredentialProtectionPolicy, GetAssertionRequest, + GetAssertionRequestExtensions, MakeCredentialRequest, MakeCredentialsRequestExtensions, + PRFValue, PrfInput, ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -149,12 +149,13 @@ pub async fn main() -> Result<(), Box> { user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { cred_blob: true, - hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( - HMACGetSecretInput { - salt1: [1; 32], - salt2: None, - }, - )), + prf: Some(PrfInput { + eval: Some(PRFValue { + first: [1; 32], + second: None, + }), + eval_by_credential: std::collections::HashMap::new(), + }), ..Default::default() }), timeout: TIMEOUT, diff --git a/libwebauthn/examples/webauthn_prf_hid.rs b/libwebauthn/examples/webauthn_prf_hid.rs index 6ae845a5..3e50fd87 100644 --- a/libwebauthn/examples/webauthn_prf_hid.rs +++ b/libwebauthn/examples/webauthn_prf_hid.rs @@ -12,9 +12,9 @@ use tokio::sync::broadcast::Receiver; use tracing_subscriber::{self, EnvFilter}; use libwebauthn::ops::webauthn::{ - GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, - MakeCredentialPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue, - PrfInput, ResidentKeyRequirement, UserVerificationRequirement, + GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialPrfInput, + MakeCredentialRequest, MakeCredentialsRequestExtensions, PRFValue, PrfInput, + ResidentKeyRequirement, UserVerificationRequirement, }; use libwebauthn::pin::PinRequestReason; use libwebauthn::proto::ctap2::{ @@ -148,15 +148,15 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "eval_by_credential only", ) .await; @@ -175,15 +175,15 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "eval and eval_by_credential", ) .await; @@ -195,15 +195,15 @@ pub async fn main() -> Result<(), Box> { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "eval only", ) .await; @@ -243,15 +243,15 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "eval and full list of eval_by_credential", ) .await; @@ -284,15 +284,15 @@ pub async fn main() -> Result<(), Box> { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "eval and non-fitting list of eval_by_credential", ) .await; @@ -322,15 +322,15 @@ pub async fn main() -> Result<(), Box> { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( &mut channel, &credential, &challenge, - hmac_or_prf, + prf, "No eval and non-fitting list of eval_by_credential (should have no extension output)", ) .await; @@ -349,15 +349,15 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_failed_test( &mut channel, Some(&credential), &challenge, - hmac_or_prf, + prf, "Wrongly encoded credential_id", WebAuthnError::Platform(PlatformError::SyntaxError), ) @@ -373,15 +373,15 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_failed_test( &mut channel, Some(&credential), &challenge, - hmac_or_prf, + prf, "Empty credential_id", WebAuthnError::Platform(PlatformError::SyntaxError), ) @@ -397,15 +397,15 @@ pub async fn main() -> Result<(), Box> { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_failed_test( &mut channel, None, &challenge, - hmac_or_prf, + prf, "Empty allow_list, set eval_by_credential", WebAuthnError::Platform(PlatformError::NotSupported), ) @@ -418,7 +418,7 @@ async fn run_success_test( channel: &mut HidChannel<'_>, credential: &Ctap2PublicKeyCredentialDescriptor, challenge: &[u8; 32], - hmac_or_prf: GetAssertionHmacOrPrfInput, + prf: PrfInput, printoutput: &str, ) { let get_assertion = GetAssertionRequest { @@ -427,7 +427,7 @@ async fn run_success_test( allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(hmac_or_prf), + prf: Some(prf), ..Default::default() }), timeout: TIMEOUT, @@ -444,7 +444,7 @@ async fn run_success_test( break Err(WebAuthnError::Ctap(ctap_error)); } Err(err) => break Err(err), - }; + } } .unwrap(); for (num, assertion) in response.assertions.iter().enumerate() { @@ -459,7 +459,7 @@ async fn run_failed_test( channel: &mut HidChannel<'_>, credential: Option<&Ctap2PublicKeyCredentialDescriptor>, challenge: &[u8; 32], - hmac_or_prf: GetAssertionHmacOrPrfInput, + prf: PrfInput, printoutput: &str, expected_error: WebAuthnError, ) { @@ -469,7 +469,7 @@ async fn run_failed_test( allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(hmac_or_prf), + prf: Some(prf), ..Default::default() }), timeout: TIMEOUT, @@ -486,7 +486,7 @@ async fn run_failed_test( break Err(WebAuthnError::Ctap(ctap_error)); } Err(err) => break Err(err), - }; + } }; assert_eq!(response, Err(expected_error), "{printoutput}:"); diff --git a/libwebauthn/src/ops/webauthn/get_assertion.rs b/libwebauthn/src/ops/webauthn/get_assertion.rs index af1a9902..e8db340f 100644 --- a/libwebauthn/src/ops/webauthn/get_assertion.rs +++ b/libwebauthn/src/ops/webauthn/get_assertion.rs @@ -81,18 +81,11 @@ impl FromInnerModel Result { - let hmac_or_prf = match inner.extensions.clone() { - Some(ext) => { - if let Some(prf) = ext.prf { - let prf_input = PrfInput::try_from(prf)?; - Some(GetAssertionHmacOrPrfInput::Prf(prf_input)) - } else if let Some(hmac) = ext.hmac_get_secret { - let hmac_input = HMACGetSecretInput::try_from(hmac)?; - Some(GetAssertionHmacOrPrfInput::HmacGetSecret(hmac_input)) - } else { - None - } - } + let prf = match inner.extensions.as_ref() { + Some(ext) => match &ext.prf { + Some(prf_json) => Some(PrfInput::try_from(prf_json.clone())?), + None => None, + }, None => None, }; @@ -106,7 +99,7 @@ impl FromInnerModel, + /// PRF extension input. At the CTAP level, this is converted to HMAC secret. + pub prf: Option, pub large_blob: Option, } @@ -570,11 +567,11 @@ mod tests { let req: GetAssertionRequest = GetAssertionRequest::from_json(&rpid, &req_json).unwrap(); if let Some(GetAssertionRequestExtensions { - hmac_or_prf: - Some(GetAssertionHmacOrPrfInput::Prf(PrfInput { + prf: + Some(PrfInput { eval: Some(ref prf_value), .. - })), + }), .. }) = &req.extensions { diff --git a/libwebauthn/src/proto/ctap2/model/get_assertion.rs b/libwebauthn/src/proto/ctap2/model/get_assertion.rs index 60996af2..078e9ab3 100644 --- a/libwebauthn/src/proto/ctap2/model/get_assertion.rs +++ b/libwebauthn/src/proto/ctap2/model/get_assertion.rs @@ -198,7 +198,7 @@ pub struct Ctap2GetAssertionRequestExtensions { #[serde(skip_serializing_if = "Option::is_none")] pub large_blob_key: Option, #[serde(skip)] - pub hmac_or_prf: Option, + pub(crate) hmac_or_prf: Option, } impl From for Ctap2GetAssertionRequestExtensions { @@ -206,7 +206,7 @@ impl From for Ctap2GetAssertionRequestExtensions Ctap2GetAssertionRequestExtensions { cred_blob: other.cred_blob, hmac_secret: None, // Gets calculated later - hmac_or_prf: other.hmac_or_prf, + hmac_or_prf: other.prf.map(GetAssertionHmacOrPrfInput::Prf), large_blob_key: if other.large_blob == Some(GetAssertionLargeBlobExtension::Read) { Some(true) } else { @@ -518,26 +518,27 @@ impl Ctap2GetAssertionResponseExtensions { } }); - let (hmac_get_secret, prf) = if let Some(decrypted) = decrypted_hmac { - match request.extensions.as_ref().and_then(|ext| ext.hmac_or_prf.as_ref()) { - None => (None, None), - Some(GetAssertionHmacOrPrfInput::HmacGetSecret(..)) => (Some(decrypted), None), - Some(GetAssertionHmacOrPrfInput::Prf(..)) => ( - None, - Some(GetAssertionPrfOutput { - results: Some(PRFValue { - first: decrypted.output1, - second: decrypted.output2, - }), + let prf = decrypted_hmac.and_then(|decrypted| { + // At WebAuthn level, we only support PRF (not raw HMAC). + // The PRF input was converted to HMAC internally. + request + .extensions + .as_ref() + .and_then(|ext| ext.prf.as_ref()) + .map(|_| GetAssertionPrfOutput { + results: Some(PRFValue { + first: decrypted.output1, + second: decrypted.output2, }), - ), - } - } else { - (None, None) - }; + }) + }); // LargeBlobs was requested - let large_blob = match request.extensions.as_ref().and_then(|ext| ext.large_blob.as_ref()) { + let large_blob = match request + .extensions + .as_ref() + .and_then(|ext| ext.large_blob.as_ref()) + { None => None, Some(GetAssertionLargeBlobExtension::Read) => { Some(GetAssertionLargeBlobExtensionOutput { @@ -552,7 +553,7 @@ impl Ctap2GetAssertionResponseExtensions { }; GetAssertionResponseUnsignedExtensions { - hmac_get_secret, + hmac_get_secret: None, large_blob, prf, } diff --git a/libwebauthn/src/tests/prf.rs b/libwebauthn/src/tests/prf.rs index 95666b4a..b6388648 100644 --- a/libwebauthn/src/tests/prf.rs +++ b/libwebauthn/src/tests/prf.rs @@ -2,9 +2,8 @@ use std::collections::HashMap; use std::time::Duration; use crate::ops::webauthn::{ - GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, - MakeCredentialPrfInput, MakeCredentialPrfOutput, MakeCredentialsRequestExtensions, PRFValue, - PrfInput, + GetAssertionRequest, GetAssertionRequestExtensions, MakeCredentialPrfInput, + MakeCredentialPrfOutput, MakeCredentialsRequestExtensions, PRFValue, PrfInput, }; use crate::pin::PinManagement; use crate::proto::ctap2::{Ctap2PinUvAuthProtocol, Ctap2PublicKeyCredentialDescriptor}; @@ -192,15 +191,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( channel, &credential, &challenge, - hmac_or_prf, + prf, true, false, "eval_by_credential only", @@ -221,15 +220,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( channel, &credential, &challenge, - hmac_or_prf, + prf, true, false, "eval and eval_by_credential", @@ -243,15 +242,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { }); let eval_by_credential = HashMap::new(); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( channel, &credential, &challenge, - hmac_or_prf, + prf, true, false, "eval only", @@ -293,15 +292,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: Some([7; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( channel, &credential, &challenge, - hmac_or_prf, + prf, true, true, "eval and full list of eval_by_credential", @@ -336,15 +335,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( channel, &credential, &challenge, - hmac_or_prf, + prf, true, false, "eval and non-fitting list of eval_by_credential", @@ -376,15 +375,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: Some([8; 32]), }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_success_test( channel, &credential, &challenge, - hmac_or_prf, + prf, false, false, "No eval and non-fitting list of eval_by_credential (should have no extension output)", @@ -405,15 +404,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_failed_test( channel, Some(&credential), &challenge, - hmac_or_prf, + prf, "Wrongly encoded credential_id", WebAuthnError::Platform(PlatformError::SyntaxError), ) @@ -429,15 +428,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_failed_test( channel, Some(&credential), &challenge, - hmac_or_prf, + prf, "Empty credential_id", WebAuthnError::Platform(PlatformError::SyntaxError), ) @@ -453,15 +452,15 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) { second: None, }, ); - let hmac_or_prf = GetAssertionHmacOrPrfInput::Prf(PrfInput { + let prf = PrfInput { eval, eval_by_credential, - }); + }; run_failed_test( channel, None, &challenge, - hmac_or_prf, + prf, "Empty allow_list, set eval_by_credential", WebAuthnError::Platform(PlatformError::NotSupported), ) @@ -476,7 +475,7 @@ async fn run_success_test( channel: &mut HidChannel<'_>, credential: &Ctap2PublicKeyCredentialDescriptor, challenge: &[u8; 32], - hmac_or_prf: GetAssertionHmacOrPrfInput, + prf: PrfInput, expect_extensions: bool, expect_prf_second: bool, printoutput: &str, @@ -487,7 +486,7 @@ async fn run_success_test( allow: vec![credential.clone()], user_verification: UserVerificationRequirement::Preferred, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(hmac_or_prf), + prf: Some(prf), ..Default::default() }), timeout: TIMEOUT, @@ -542,7 +541,7 @@ async fn run_failed_test( channel: &mut HidChannel<'_>, credential: Option<&Ctap2PublicKeyCredentialDescriptor>, challenge: &[u8; 32], - hmac_or_prf: GetAssertionHmacOrPrfInput, + prf: PrfInput, printoutput: &str, expected_error: WebAuthnError, ) { @@ -552,7 +551,7 @@ async fn run_failed_test( allow: credential.map(|x| vec![x.clone()]).unwrap_or_default(), user_verification: UserVerificationRequirement::Discouraged, extensions: Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(hmac_or_prf), + prf: Some(prf), ..Default::default() }), timeout: TIMEOUT, diff --git a/libwebauthn/src/webauthn/pin_uv_auth_token.rs b/libwebauthn/src/webauthn/pin_uv_auth_token.rs index 0072bf73..2c73bc75 100644 --- a/libwebauthn/src/webauthn/pin_uv_auth_token.rs +++ b/libwebauthn/src/webauthn/pin_uv_auth_token.rs @@ -433,8 +433,8 @@ mod test { use crate::{ ops::webauthn::{ - GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions, - HMACGetSecretInput, UserVerificationRequirement, + GetAssertionRequest, GetAssertionRequestExtensions, PRFValue, PrfInput, + UserVerificationRequirement, }, pin::{pin_hash, PinUvAuthProtocol, PinUvAuthProtocolOne}, proto::{ @@ -610,12 +610,13 @@ mod test { info_extensions.as_deref(), UserVerificationRequirement::Discouraged, Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( - HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }, - )), + prf: Some(PrfInput { + eval: Some(PRFValue { + first: [0; 32], + second: None, + }), + eval_by_credential: HashMap::new(), + }), ..Default::default() }), Ok(UsedPinUvAuthToken::None), @@ -655,12 +656,13 @@ mod test { Some(&["hmac-secret"]), UserVerificationRequirement::Preferred, Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( - HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }, - )), + prf: Some(PrfInput { + eval: Some(PRFValue { + first: [0; 32], + second: None, + }), + eval_by_credential: HashMap::new(), + }), ..Default::default() }), Ok(UsedPinUvAuthToken::LegacyUV), @@ -726,12 +728,13 @@ mod test { for (info_options, uv_requirement) in testcases { let extensions = Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( - HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }, - )), + prf: Some(PrfInput { + eval: Some(PRFValue { + first: [0; 32], + second: None, + }), + eval_by_credential: HashMap::new(), + }), ..Default::default() }); @@ -795,12 +798,13 @@ mod test { for (info_options, uv_requirement) in testcases { let extensions = Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( - HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }, - )), + prf: Some(PrfInput { + eval: Some(PRFValue { + first: [0; 32], + second: None, + }), + eval_by_credential: HashMap::new(), + }), ..Default::default() }); @@ -911,12 +915,13 @@ mod test { for (info_options, uv_requirement) in testcases { let extensions = Some(GetAssertionRequestExtensions { - hmac_or_prf: Some(GetAssertionHmacOrPrfInput::HmacGetSecret( - HMACGetSecretInput { - salt1: [0; 32], - salt2: None, - }, - )), + prf: Some(PrfInput { + eval: Some(PRFValue { + first: [0; 32], + second: None, + }), + eval_by_credential: HashMap::new(), + }), ..Default::default() });