@@ -12,9 +12,9 @@ use crate::{
1212 ctap1:: { Ctap1RegisteredKey , Ctap1Version } ,
1313 ctap2:: {
1414 Ctap2AttestationStatement , Ctap2COSEAlgorithmIdentifier , Ctap2CredentialType ,
15- Ctap2GetAssertionResponseExtensions , Ctap2MakeCredentialsResponseExtensions ,
16- Ctap2PublicKeyCredentialDescriptor , Ctap2PublicKeyCredentialRpEntity ,
17- Ctap2PublicKeyCredentialUserEntity ,
15+ Ctap2GetAssertionResponseExtensions , Ctap2GetInfoResponse ,
16+ Ctap2MakeCredentialsResponseExtensions , Ctap2PublicKeyCredentialDescriptor ,
17+ Ctap2PublicKeyCredentialRpEntity , Ctap2PublicKeyCredentialUserEntity ,
1818 } ,
1919 } ,
2020 webauthn:: CtapError ,
@@ -54,7 +54,7 @@ pub struct MakeCredentialResponse {
5454 pub attestation_statement : Ctap2AttestationStatement ,
5555 pub enterprise_attestation : Option < bool > ,
5656 pub large_blob_key : Option < Vec < u8 > > ,
57- pub unsigned_extensions_output : Option < MakeCredentialsResponseUnsignedExtensions > ,
57+ pub unsigned_extensions_output : MakeCredentialsResponseUnsignedExtensions ,
5858}
5959
6060#[ derive( Debug , Default , Clone , Serialize ) ]
@@ -73,6 +73,95 @@ pub struct MakeCredentialsResponseUnsignedExtensions {
7373 pub prf : Option < MakeCredentialPrfOutput > ,
7474}
7575
76+ impl MakeCredentialsResponseUnsignedExtensions {
77+ pub fn has_some ( & self ) -> bool {
78+ self . cred_props . is_some ( )
79+ || self . hmac_create_secret . is_some ( )
80+ || self . large_blob . is_some ( )
81+ || self . prf . is_some ( )
82+ }
83+
84+ pub fn from_signed_extensions (
85+ signed_extensions : & Option < Ctap2MakeCredentialsResponseExtensions > ,
86+ request : & MakeCredentialRequest ,
87+ info : Option < & Ctap2GetInfoResponse > ,
88+ ) -> MakeCredentialsResponseUnsignedExtensions {
89+ let mut hmac_create_secret = None ;
90+ let mut prf = None ;
91+ if let Some ( signed_extensions) = signed_extensions {
92+ ( hmac_create_secret, prf) = if let Some ( incoming_ext) = & request. extensions {
93+ match & incoming_ext. hmac_or_prf {
94+ MakeCredentialHmacOrPrfInput :: None => ( None , None ) ,
95+ MakeCredentialHmacOrPrfInput :: HmacGetSecret => {
96+ ( signed_extensions. hmac_secret , None )
97+ }
98+ MakeCredentialHmacOrPrfInput :: Prf => (
99+ None ,
100+ Some ( MakeCredentialPrfOutput {
101+ enabled : signed_extensions. hmac_secret ,
102+ } ) ,
103+ ) ,
104+ }
105+ } else {
106+ ( None , None )
107+ } ;
108+ }
109+
110+ // credProps extension
111+ // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension
112+ let cred_props = match & request
113+ . extensions
114+ . as_ref ( )
115+ . and_then ( |x| x. cred_props . as_ref ( ) )
116+ {
117+ None | Some ( false ) => None , // Not requested, so we don't give an answer
118+ Some ( true ) => {
119+ // https://w3c.github.io/webauthn/#dom-credentialpropertiesoutput-rk
120+ // Some authenticators create discoverable credentials even when not
121+ // requested by the client platform. Because of this, client platforms may be
122+ // forced to omit the rk property because they lack the assurance to be able
123+ // to set it to false.
124+ if info. map ( |x| x. supports_fido_2_1 ( ) ) == Some ( true ) {
125+ // https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#op-makecred-step-rk
126+ // if the "rk" option is false: the authenticator MUST create a non-discoverable credential.
127+ // Note: This step is a change from CTAP2.0 where if the "rk" option is false the authenticator could optionally create a discoverable credential.
128+ Some ( CredentialPropsExtension {
129+ rk : Some ( request. require_resident_key ) ,
130+ } )
131+ } else {
132+ Some ( CredentialPropsExtension {
133+ // For CTAP 2.0, we can't say if "rk" is true or not.
134+ rk : None ,
135+ } )
136+ }
137+ }
138+ } ;
139+
140+ // largeBlob extension
141+ // https://www.w3.org/TR/webauthn-3/#sctn-large-blob-extension
142+ let large_blob = match & request. extensions . as_ref ( ) . map ( |x| & x. large_blob ) {
143+ None | Some ( MakeCredentialLargeBlobExtension :: None ) => None , // Not requested, so we don't give an answer
144+ Some ( MakeCredentialLargeBlobExtension :: Preferred )
145+ | Some ( MakeCredentialLargeBlobExtension :: Required ) => {
146+ if info. map ( |x| x. option_enabled ( "largeBlobs" ) ) == Some ( true ) {
147+ Some ( MakeCredentialLargeBlobExtensionOutput {
148+ supported : Some ( true ) ,
149+ } )
150+ } else {
151+ None
152+ }
153+ }
154+ } ;
155+
156+ MakeCredentialsResponseUnsignedExtensions {
157+ cred_props,
158+ hmac_create_secret,
159+ large_blob,
160+ prf,
161+ }
162+ }
163+ }
164+
76165#[ derive( Debug , Clone ) ]
77166pub struct MakeCredentialRequest {
78167 pub hash : Vec < u8 > ,
@@ -131,10 +220,12 @@ pub struct CredentialProtectionExtension {
131220}
132221
133222#[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
134- #[ serde( rename_all = "camelCase" ) ]
135223pub enum CredentialProtectionPolicy {
224+ #[ serde( rename = "userVerificationOptional" ) ]
136225 UserVerificationOptional = 1 ,
137- UserVerificationOptionalWithCredentialIdList = 2 ,
226+ #[ serde( rename = "userVerificationOptionalWithCredentialIDList" ) ]
227+ UserVerificationOptionalWithCredentialIDList = 2 ,
228+ #[ serde( rename = "userVerificationRequired" ) ]
138229 UserVerificationRequired = 3 ,
139230}
140231
@@ -144,7 +235,7 @@ impl From<CredentialProtectionPolicy> for Ctap2CredentialProtectionPolicy {
144235 CredentialProtectionPolicy :: UserVerificationOptional => {
145236 Ctap2CredentialProtectionPolicy :: Optional
146237 }
147- CredentialProtectionPolicy :: UserVerificationOptionalWithCredentialIdList => {
238+ CredentialProtectionPolicy :: UserVerificationOptionalWithCredentialIDList => {
148239 Ctap2CredentialProtectionPolicy :: OptionalWithCredentialIdList
149240 }
150241 CredentialProtectionPolicy :: UserVerificationRequired => {
@@ -161,7 +252,7 @@ impl From<Ctap2CredentialProtectionPolicy> for CredentialProtectionPolicy {
161252 CredentialProtectionPolicy :: UserVerificationOptional
162253 }
163254 Ctap2CredentialProtectionPolicy :: OptionalWithCredentialIdList => {
164- CredentialProtectionPolicy :: UserVerificationOptionalWithCredentialIdList
255+ CredentialProtectionPolicy :: UserVerificationOptionalWithCredentialIDList
165256 }
166257 Ctap2CredentialProtectionPolicy :: Required => {
167258 CredentialProtectionPolicy :: UserVerificationRequired
0 commit comments