webauthn-rs-proto

Patched webauthn-rs-proto (https://crates.io/crates/webauthn-rs-proto) that adds support for Ed25519.
git clone https://git.philomathiclife.com/repos/webauthn-rs-proto
Log | Files | Refs | README | LICENSE

auth.rs (8788B)


      1 //! Types related to authentication (Assertion)
      2 
      3 use base64urlsafedata::Base64UrlSafeData;
      4 use serde::{Deserialize, Serialize};
      5 
      6 use crate::extensions::{AuthenticationExtensionsClientOutputs, RequestAuthenticationExtensions};
      7 use crate::options::*;
      8 
      9 /// The requested options for the authentication
     10 #[derive(Debug, Serialize, Clone, Deserialize)]
     11 #[serde(rename_all = "camelCase")]
     12 pub struct PublicKeyCredentialRequestOptions {
     13     /// The challenge that should be signed by the authenticator.
     14     pub challenge: Base64UrlSafeData,
     15     /// The timeout for the authenticator in case of no interaction.
     16     #[serde(skip_serializing_if = "Option::is_none")]
     17     pub timeout: Option<u32>,
     18     /// The relying party ID.
     19     pub rp_id: String,
     20     /// The set of credentials that are allowed to sign this challenge.
     21     pub allow_credentials: Vec<AllowCredentials>,
     22     /// The verification policy the browser will request.
     23     pub user_verification: UserVerificationPolicy,
     24     /// extensions.
     25     #[serde(skip_serializing_if = "Option::is_none")]
     26     pub extensions: Option<RequestAuthenticationExtensions>,
     27 }
     28 
     29 /// Request in residentkey workflows that conditional mediation should be used
     30 /// in the UI, or not.
     31 #[derive(Debug, Serialize, Clone, Deserialize)]
     32 #[serde(rename_all = "camelCase")]
     33 pub enum Mediation {
     34     // /// No mediation is provided - This is represented by "None" on the Option
     35     // below. We can't use None here as a variant because it confuses serde-wasm-bindgen :(
     36     // None,
     37     // /// Silent, try to do things without the user being involved. Probably a bad idea.
     38     // Silent,
     39     // /// If we can get creds without the user having to do anything, great, other wise ask the user. Probably a bad idea.
     40     // Optional,
     41     /// Discovered credentials are presented to the user in a dialog.
     42     /// Conditional UI is used. See <https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI>
     43     /// <https://w3c.github.io/webappsec-credential-management/#enumdef-credentialmediationrequirement>
     44     Conditional,
     45     // /// The user needs to do something.
     46     // Required
     47 }
     48 
     49 /// A JSON serializable challenge which is issued to the user's webbrowser
     50 /// for handling. This is meant to be opaque, that is, you should not need
     51 /// to inspect or alter the content of the struct - you should serialise it
     52 /// and transmit it to the client only.
     53 #[derive(Debug, Serialize, Clone, Deserialize)]
     54 #[serde(rename_all = "camelCase")]
     55 pub struct RequestChallengeResponse {
     56     /// The options.
     57     pub public_key: PublicKeyCredentialRequestOptions,
     58     #[serde(default, skip_serializing_if = "Option::is_none")]
     59     /// The mediation requested
     60     pub mediation: Option<Mediation>,
     61 }
     62 
     63 #[cfg(feature = "wasm")]
     64 impl From<RequestChallengeResponse> for web_sys::CredentialRequestOptions {
     65     fn from(rcr: RequestChallengeResponse) -> Self {
     66         use js_sys::{Array, Object, Uint8Array};
     67         use wasm_bindgen::JsValue;
     68 
     69         let jsv = serde_wasm_bindgen::to_value(&rcr).unwrap();
     70         let pkcco = js_sys::Reflect::get(&jsv, &"publicKey".into()).unwrap();
     71 
     72         let chal = Uint8Array::from(rcr.public_key.challenge.0.as_slice());
     73         js_sys::Reflect::set(&pkcco, &"challenge".into(), &chal).unwrap();
     74 
     75         if let Some(extensions) = rcr.public_key.extensions {
     76             let obj: Object = (&extensions).into();
     77             js_sys::Reflect::set(&pkcco, &"extensions".into(), &obj).unwrap();
     78         }
     79 
     80         let allow_creds: Array = rcr
     81             .public_key
     82             .allow_credentials
     83             .iter()
     84             .map(|ac| {
     85                 let obj = Object::new();
     86                 js_sys::Reflect::set(&obj, &"type".into(), &JsValue::from_str(ac.type_.as_str()))
     87                     .unwrap();
     88 
     89                 js_sys::Reflect::set(&obj, &"id".into(), &Uint8Array::from(ac.id.0.as_slice()))
     90                     .unwrap();
     91 
     92                 if let Some(transports) = &ac.transports {
     93                     let tarray: Array = transports
     94                         .iter()
     95                         .map(|trs| serde_wasm_bindgen::to_value(trs).unwrap())
     96                         .collect();
     97 
     98                     js_sys::Reflect::set(&obj, &"transports".into(), &tarray).unwrap();
     99                 }
    100 
    101                 obj
    102             })
    103             .collect();
    104         js_sys::Reflect::set(&pkcco, &"allowCredentials".into(), &allow_creds).unwrap();
    105 
    106         web_sys::CredentialRequestOptions::from(jsv)
    107     }
    108 }
    109 
    110 /// <https://w3c.github.io/webauthn/#authenticatorassertionresponse>
    111 #[derive(Debug, Deserialize, Serialize, Clone)]
    112 pub struct AuthenticatorAssertionResponseRaw {
    113     /// Raw authenticator data.
    114     #[serde(rename = "authenticatorData")]
    115     pub authenticator_data: Base64UrlSafeData,
    116 
    117     /// Signed client data.
    118     #[serde(rename = "clientDataJSON")]
    119     pub client_data_json: Base64UrlSafeData,
    120 
    121     /// Signature
    122     pub signature: Base64UrlSafeData,
    123 
    124     /// Optional userhandle.
    125     #[serde(rename = "userHandle")]
    126     pub user_handle: Option<Base64UrlSafeData>,
    127 }
    128 
    129 /// A client response to an authentication challenge. This contains all required
    130 /// information to asses and assert trust in a credentials legitimacy, followed
    131 /// by authentication to a user.
    132 ///
    133 /// You should not need to handle the inner content of this structure - you should
    134 /// provide this to the correctly handling function of Webauthn only.
    135 #[derive(Debug, Deserialize, Serialize, Clone)]
    136 pub struct PublicKeyCredential {
    137     /// The credential Id, likely base64
    138     pub id: String,
    139     /// The binary of the credential id.
    140     #[serde(rename = "rawId")]
    141     pub raw_id: Base64UrlSafeData,
    142     /// The authenticator response.
    143     pub response: AuthenticatorAssertionResponseRaw,
    144     /// Unsigned Client processed extensions.
    145     #[serde(default)]
    146     pub extensions: AuthenticationExtensionsClientOutputs,
    147     /// The authenticator type.
    148     #[serde(rename = "type")]
    149     pub type_: String,
    150 }
    151 
    152 impl PublicKeyCredential {
    153     /// Retrieve the user uniqueid that *may* have been provided by the authenticator during this
    154     /// authentication.
    155     pub fn get_user_unique_id(&self) -> Option<&[u8]> {
    156         self.response.user_handle.as_ref().map(|b| b.as_ref())
    157     }
    158 
    159     /// Retrieve the credential id that was provided in this authentication
    160     pub fn get_credential_id(&self) -> &[u8] {
    161         self.raw_id.0.as_slice()
    162     }
    163 }
    164 
    165 #[cfg(feature = "wasm")]
    166 impl From<web_sys::PublicKeyCredential> for PublicKeyCredential {
    167     fn from(data: web_sys::PublicKeyCredential) -> PublicKeyCredential {
    168         use js_sys::Uint8Array;
    169 
    170         let data_raw_id =
    171             Uint8Array::new(&js_sys::Reflect::get(&data, &"rawId".into()).unwrap()).to_vec();
    172 
    173         let data_response = js_sys::Reflect::get(&data, &"response".into()).unwrap();
    174 
    175         let data_response_authenticator_data = Uint8Array::new(
    176             &js_sys::Reflect::get(&data_response, &"authenticatorData".into()).unwrap(),
    177         )
    178         .to_vec();
    179 
    180         let data_response_signature =
    181             Uint8Array::new(&js_sys::Reflect::get(&data_response, &"signature".into()).unwrap())
    182                 .to_vec();
    183 
    184         let data_response_user_handle =
    185             &js_sys::Reflect::get(&data_response, &"userHandle".into()).unwrap();
    186         let data_response_user_handle = if data_response_user_handle.is_undefined() {
    187             None
    188         } else {
    189             Some(Uint8Array::new(data_response_user_handle).to_vec())
    190         };
    191 
    192         let data_response_client_data_json = Uint8Array::new(
    193             &js_sys::Reflect::get(&data_response, &"clientDataJSON".into()).unwrap(),
    194         )
    195         .to_vec();
    196 
    197         let data_extensions = data.get_client_extension_results();
    198         web_sys::console::log_1(&data_extensions);
    199 
    200         // Base64 it
    201 
    202         let data_raw_id_b64 = Base64UrlSafeData(data_raw_id);
    203         let data_response_client_data_json_b64 = Base64UrlSafeData(data_response_client_data_json);
    204         let data_response_authenticator_data_b64 =
    205             Base64UrlSafeData(data_response_authenticator_data);
    206         let data_response_signature_b64 = Base64UrlSafeData(data_response_signature);
    207 
    208         let data_response_user_handle_b64 = data_response_user_handle.map(Base64UrlSafeData);
    209 
    210         PublicKeyCredential {
    211             id: format!("{}", data_raw_id_b64),
    212             raw_id: data_raw_id_b64,
    213             response: AuthenticatorAssertionResponseRaw {
    214                 authenticator_data: data_response_authenticator_data_b64,
    215                 client_data_json: data_response_client_data_json_b64,
    216                 signature: data_response_signature_b64,
    217                 user_handle: data_response_user_handle_b64,
    218             },
    219             extensions: data_extensions.into(),
    220             type_: "public-key".to_string(),
    221         }
    222     }
    223 }