@@ -145,7 +145,7 @@ pub trait Customization {
145145 /// this value.
146146 fn max_msg_size ( & self ) -> usize ;
147147
148- /// Sets the number of consecutive failed PINs before blocking interaction.
148+ /// The number of consecutive failed PINs before blocking interaction.
149149 ///
150150 /// # Invariant
151151 ///
@@ -155,6 +155,42 @@ pub trait Customization {
155155 /// The fail retry counter is reset after entering the correct PIN.
156156 fn max_pin_retries ( & self ) -> u8 ;
157157
158+ /// Maximum number of UV retries performed before returning an error.
159+ ///
160+ /// Corresponds to maxUvAttemptsForInternalRetries in CTAP 2.1 onwards.
161+ /// When internal retries are allowed, the authenticator will retry UV
162+ /// before communicating its result through CTAP.
163+ ///
164+ /// # Invariant
165+ ///
166+ /// - Must be in the range [1, `max_uv_retries`].
167+ /// - If `preferred_platform_uv_attempts` is not 1, must be in [1, 5].
168+ #[ cfg( feature = "fingerprint" ) ]
169+ fn max_uv_attempts_for_internal_retries ( & self ) -> u8 ;
170+
171+ /// The number of consecutive failed UV attempts before blocking built-in UV.
172+ ///
173+ /// Corresponds to maxUvRetries in CTAP 2.1 onwards.
174+ ///
175+ /// # Invariant
176+ ///
177+ /// - Must be in the range [1, 25].
178+ #[ cfg( feature = "fingerprint" ) ]
179+ fn max_uv_retries ( & self ) -> u8 ;
180+
181+ /// Preferred number of UV attempts before falling back to PIN.
182+ ///
183+ /// Corresponds to preferredPlatformUvAttempts in CTAP 2.1 onwards.
184+ /// States the preference how often the platform should invoke
185+ /// `getPinUvAuthTokenUsingUvWithPermissions` before falling back to
186+ /// `getPinUvAuthTokenUsingPinWithPermissions` or displaying an error.
187+ ///
188+ /// # Invariant
189+ ///
190+ /// - Must be greater than 0.
191+ #[ cfg( feature = "fingerprint" ) ]
192+ fn preferred_platform_uv_attempts ( & self ) -> usize ;
193+
158194 /// Enables or disables basic attestation for FIDO2.
159195 ///
160196 /// # Invariant
@@ -252,6 +288,12 @@ pub trait Customization {
252288 /// With P=20 and K=150, we have I=2M which is enough for 500 increments per day
253289 /// for 10 years.
254290 fn max_supported_resident_keys ( & self ) -> usize ;
291+
292+ /// Maximum size of a friendly name for a UV template.
293+ ///
294+ /// This value limits storage requirements for fingerprints.
295+ #[ cfg( feature = "fingerprint" ) ]
296+ fn max_template_friendly_name ( & self ) -> usize ;
255297}
256298
257299#[ derive( Clone ) ]
@@ -266,13 +308,21 @@ pub struct CustomizationImpl {
266308 pub enterprise_rp_id_list : & ' static [ & ' static str ] ,
267309 pub max_msg_size : usize ,
268310 pub max_pin_retries : u8 ,
311+ #[ cfg( feature = "fingerprint" ) ]
312+ pub max_uv_attempts_for_internal_retries : u8 ,
313+ #[ cfg( feature = "fingerprint" ) ]
314+ pub max_uv_retries : u8 ,
315+ #[ cfg( feature = "fingerprint" ) ]
316+ pub preferred_platform_uv_attempts : usize ,
269317 pub use_batch_attestation : bool ,
270318 pub use_signature_counter : bool ,
271319 pub max_cred_blob_length : usize ,
272320 pub max_credential_count_in_list : Option < usize > ,
273321 pub max_large_blob_array_size : usize ,
274322 pub max_rp_ids_length : usize ,
275323 pub max_supported_resident_keys : usize ,
324+ #[ cfg( feature = "fingerprint" ) ]
325+ pub max_template_friendly_name : usize ,
276326}
277327
278328pub const DEFAULT_CUSTOMIZATION : CustomizationImpl = CustomizationImpl {
@@ -286,13 +336,21 @@ pub const DEFAULT_CUSTOMIZATION: CustomizationImpl = CustomizationImpl {
286336 enterprise_rp_id_list : & [ ] ,
287337 max_msg_size : 7609 ,
288338 max_pin_retries : 8 ,
339+ #[ cfg( feature = "fingerprint" ) ]
340+ max_uv_attempts_for_internal_retries : 1 ,
341+ #[ cfg( feature = "fingerprint" ) ]
342+ max_uv_retries : 8 ,
343+ #[ cfg( feature = "fingerprint" ) ]
344+ preferred_platform_uv_attempts : 1 ,
289345 use_batch_attestation : false ,
290346 use_signature_counter : true ,
291347 max_cred_blob_length : 32 ,
292348 max_credential_count_in_list : None ,
293349 max_large_blob_array_size : 2048 ,
294350 max_rp_ids_length : 8 ,
295351 max_supported_resident_keys : 150 ,
352+ #[ cfg( feature = "fingerprint" ) ]
353+ max_template_friendly_name : 64 ,
296354} ;
297355
298356impl Customization for CustomizationImpl {
@@ -347,6 +405,21 @@ impl Customization for CustomizationImpl {
347405 self . max_pin_retries
348406 }
349407
408+ #[ cfg( feature = "fingerprint" ) ]
409+ fn max_uv_attempts_for_internal_retries ( & self ) -> u8 {
410+ self . max_uv_attempts_for_internal_retries
411+ }
412+
413+ #[ cfg( feature = "fingerprint" ) ]
414+ fn max_uv_retries ( & self ) -> u8 {
415+ self . max_uv_retries
416+ }
417+
418+ #[ cfg( feature = "fingerprint" ) ]
419+ fn preferred_platform_uv_attempts ( & self ) -> usize {
420+ self . preferred_platform_uv_attempts
421+ }
422+
350423 fn use_batch_attestation ( & self ) -> bool {
351424 self . use_batch_attestation
352425 }
@@ -374,6 +447,11 @@ impl Customization for CustomizationImpl {
374447 fn max_supported_resident_keys ( & self ) -> usize {
375448 self . max_supported_resident_keys
376449 }
450+
451+ #[ cfg( feature = "fingerprint" ) ]
452+ fn max_template_friendly_name ( & self ) -> usize {
453+ self . max_template_friendly_name
454+ }
377455}
378456
379457#[ cfg( feature = "std" ) ]
@@ -446,6 +524,32 @@ pub fn is_valid(customization: &impl Customization) -> bool {
446524 return false ;
447525 }
448526
527+ #[ cfg( feature = "fingerprint" ) ]
528+ {
529+ // Maximum UV retries must be in range [1, 25].
530+ if customization. max_uv_retries ( ) < 1 || customization. max_uv_retries ( ) > 25 {
531+ return false ;
532+ }
533+
534+ // Maximum internal UV attemps must be in range [1, `max_uv_retries`].
535+ // If preferred platform UV attemps is not 1, must additionally be in [1, 5].
536+ if customization. max_uv_attempts_for_internal_retries ( ) < 1
537+ || customization. max_uv_attempts_for_internal_retries ( ) > customization. max_uv_retries ( )
538+ {
539+ return false ;
540+ }
541+ if customization. preferred_platform_uv_attempts ( ) != 1
542+ && customization. max_uv_attempts_for_internal_retries ( ) > 5
543+ {
544+ return false ;
545+ }
546+
547+ // Preferred number of UV attempts must be positive.
548+ if customization. preferred_platform_uv_attempts ( ) == 0 {
549+ return false ;
550+ }
551+ }
552+
449553 true
450554}
451555
@@ -471,13 +575,21 @@ mod test {
471575 enterprise_rp_id_list : & [ ] ,
472576 max_msg_size : 7609 ,
473577 max_pin_retries : 8 ,
578+ #[ cfg( feature = "fingerprint" ) ]
579+ max_uv_attempts_for_internal_retries : 1 ,
580+ #[ cfg( feature = "fingerprint" ) ]
581+ max_uv_retries : 8 ,
582+ #[ cfg( feature = "fingerprint" ) ]
583+ preferred_platform_uv_attempts : 1 ,
474584 use_batch_attestation : true ,
475585 use_signature_counter : true ,
476586 max_cred_blob_length : 32 ,
477587 max_credential_count_in_list : Some ( 3 ) ,
478588 max_large_blob_array_size : 2048 ,
479589 max_rp_ids_length : 8 ,
480590 max_supported_resident_keys : 150 ,
591+ #[ cfg( feature = "fingerprint" ) ]
592+ max_template_friendly_name : 64 ,
481593 } ;
482594 assert_eq ! ( customization. aaguid( ) , & [ 0 ; AAGUID_LENGTH ] ) ;
483595 assert ! ( customization. allows_pin_protocol_v1( ) ) ;
@@ -492,12 +604,20 @@ mod test {
492604 assert ! ( customization. enterprise_rp_id_list( ) . is_empty( ) ) ;
493605 assert_eq ! ( customization. max_msg_size( ) , 7609 ) ;
494606 assert_eq ! ( customization. max_pin_retries( ) , 8 ) ;
607+ #[ cfg( feature = "fingerprint" ) ]
608+ assert_eq ! ( customization. max_uv_attempts_for_internal_retries( ) , 1 ) ;
609+ #[ cfg( feature = "fingerprint" ) ]
610+ assert_eq ! ( customization. max_uv_retries( ) , 8 ) ;
611+ #[ cfg( feature = "fingerprint" ) ]
612+ assert_eq ! ( customization. preferred_platform_uv_attempts( ) , 1 ) ;
495613 assert ! ( customization. use_batch_attestation( ) ) ;
496614 assert ! ( customization. use_signature_counter( ) ) ;
497615 assert_eq ! ( customization. max_cred_blob_length( ) , 32 ) ;
498616 assert_eq ! ( customization. max_credential_count_in_list( ) , Some ( 3 ) ) ;
499617 assert_eq ! ( customization. max_large_blob_array_size( ) , 2048 ) ;
500618 assert_eq ! ( customization. max_rp_ids_length( ) , 8 ) ;
501619 assert_eq ! ( customization. max_supported_resident_keys( ) , 150 ) ;
620+ #[ cfg( feature = "fingerprint" ) ]
621+ assert_eq ! ( customization. max_template_friendly_name( ) , 64 ) ;
502622 }
503623}
0 commit comments