usesuper::commands::CommandError; usecrate::transport::errors::HIDError; use base64::Engine; use serde::de::{self, Deserializer, Error as SerdeError, MapAccess, Visitor}; use serde::{Deserialize, Serialize, Serializer}; use serde_json as json; use sha2::{Digest, Sha256}; use std::fmt;
/// https://w3c.github.io/webauthn/#dom-collectedclientdata-tokenbinding // tokenBinding, of type TokenBinding // // This OPTIONAL member contains information about the state of the Token // Binding protocol [TokenBinding] used when communicating with the Relying // Party. Its absence indicates that the client doesn’t support token // binding. // // status, of type TokenBindingStatus // // This member is one of the following: // // supported // // Indicates the client supports token binding, but it was not // negotiated when communicating with the Relying Party. // // present // // Indicates token binding was used when communicating with the // Relying Party. In this case, the id member MUST be present. // // id, of type DOMString // // This member MUST be present if status is present, and MUST be a // base64url encoding of the Token Binding ID that was used when // communicating with the Relying Party. #[derive(Debug, Clone, PartialEq, Eq)] pubenum TokenBinding {
Present(String),
Supported,
}
impl Serialize for TokenBinding { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ match *self {
TokenBinding::Supported => {
serialize_map!(
serializer,
&"status" => &"supported",
)
}
TokenBinding::Present(ref v) => {
serialize_map!(
serializer,
&"status" => "present", // Verify here, that `v` is valid base64 encoded? // base64::decode_config(&v, base64::URL_SAFE_NO_PAD); // For now: Let the token do that.
&"id" => &v,
)
}
}
}
}
impl<'de> Deserialize<'de> for TokenBinding { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where
D: Deserializer<'de>,
{ struct TokenBindingVisitor;
impl<'de> Visitor<'de> for TokenBindingVisitor { type Value = TokenBinding;
/// https://w3c.github.io/webauthn/#dom-collectedclientdata-type // type, of type DOMString // // This member contains the string "webauthn.create" when creating new // credentials, and "webauthn.get" when getting an assertion from an // existing credential. The purpose of this member is to prevent certain // types of signature confusion attacks (where an attacker substitutes one // legitimate signature for another). #[derive(Debug, Copy, Clone, PartialEq, Eq)] pubenum WebauthnType {
Create,
Get,
}
impl Serialize for WebauthnType { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ match *self {
WebauthnType::Create => serializer.serialize_str("webauthn.create"),
WebauthnType::Get => serializer.serialize_str("webauthn.get"),
}
}
}
impl<'de> Deserialize<'de> for WebauthnType { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where
D: Deserializer<'de>,
{ struct WebauthnTypeVisitor;
impl<'de> Visitor<'de> for WebauthnTypeVisitor { type Value = WebauthnType;
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] pubstruct CollectedClientData { #[serde(rename = "type")] pub webauthn_type: WebauthnType, pub challenge: Challenge, pub origin: Origin, // It is optional, according to https://www.w3.org/TR/webauthn/#collectedclientdata-hash-of-the-serialized-client-data // But we are serializing it, so we *have to* set crossOrigin (if not given, we have to set it to false) // Thus, on our side, it is not optional. For deserializing, we provide a default (bool's default == False) #[serde(rename = "crossOrigin", default)] pub cross_origin: bool, #[serde(rename = "tokenBinding", skip_serializing_if = "Option::is_none")] pub token_binding: Option<TokenBinding>,
}
impl CollectedClientData { pubfn hash(&self) -> Result<ClientDataHash, HIDError> { // WebIDL's dictionary definition specifies that the order of the struct // is exactly as the WebIDL specification declares it, with an algorithm // for partial dictionaries, so that's how interop works for these // things. // See: https://heycam.github.io/webidl/#dfn-dictionary let json = json::to_vec(&self).map_err(CommandError::Json)?; let digest = Sha256::digest(json);
Ok(ClientDataHash(digest.into()))
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.