@@ -88,7 +88,7 @@ public async Task TestAuthenticatorOrigins(string origin, string expectedOrigin)
8888 {
8989 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
9090 RequireResidentKey = true ,
91- UserVerification = UserVerificationRequirement . Required ,
91+ UserVerification = UserVerificationRequirement . Discouraged ,
9292 } ,
9393 Challenge = challenge ,
9494 ErrorMessage = "" ,
@@ -192,7 +192,7 @@ public void TestAuthenticatorOriginsFail(string origin, string expectedOrigin)
192192 {
193193 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
194194 RequireResidentKey = true ,
195- UserVerification = UserVerificationRequirement . Required ,
195+ UserVerification = UserVerificationRequirement . Discouraged ,
196196 } ,
197197 Challenge = challenge ,
198198 ErrorMessage = "" ,
@@ -388,7 +388,7 @@ public void TestAuthenticatorAttestationResponseInvalidType()
388388 {
389389 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
390390 RequireResidentKey = true ,
391- UserVerification = UserVerificationRequirement . Required ,
391+ UserVerification = UserVerificationRequirement . Discouraged ,
392392 } ,
393393 Challenge = challenge ,
394394 ErrorMessage = "" ,
@@ -459,7 +459,7 @@ public void TestAuthenticatorAttestationResponseInvalidRawId(byte[] value)
459459 {
460460 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
461461 RequireResidentKey = true ,
462- UserVerification = UserVerificationRequirement . Required ,
462+ UserVerification = UserVerificationRequirement . Discouraged ,
463463 } ,
464464 Challenge = challenge ,
465465 ErrorMessage = "" ,
@@ -528,7 +528,7 @@ public void TestAuthenticatorAttestationResponseInvalidRawType()
528528 {
529529 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
530530 RequireResidentKey = true ,
531- UserVerification = UserVerificationRequirement . Required ,
531+ UserVerification = UserVerificationRequirement . Discouraged ,
532532 } ,
533533 Challenge = challenge ,
534534 ErrorMessage = "" ,
@@ -605,7 +605,7 @@ public void TestAuthenticatorAttestationResponseRpidMismatch()
605605 {
606606 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
607607 RequireResidentKey = true ,
608- UserVerification = UserVerificationRequirement . Required ,
608+ UserVerification = UserVerificationRequirement . Discouraged ,
609609 } ,
610610 Challenge = challenge ,
611611 ErrorMessage = "" ,
@@ -683,7 +683,7 @@ public void TestAuthenticatorAttestationResponseNotUserPresent()
683683 {
684684 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
685685 RequireResidentKey = true ,
686- UserVerification = UserVerificationRequirement . Required ,
686+ UserVerification = UserVerificationRequirement . Discouraged ,
687687 } ,
688688 Challenge = challenge ,
689689 ErrorMessage = "" ,
@@ -760,7 +760,7 @@ public void TestAuthenticatorAttestationResponseNoAttestedCredentialData()
760760 {
761761 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
762762 RequireResidentKey = true ,
763- UserVerification = UserVerificationRequirement . Required ,
763+ UserVerification = UserVerificationRequirement . Discouraged ,
764764 } ,
765765 Challenge = challenge ,
766766 ErrorMessage = "" ,
@@ -838,7 +838,7 @@ public void TestAuthenticatorAttestationResponseUnknownAttestationType()
838838 {
839839 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
840840 RequireResidentKey = true ,
841- UserVerification = UserVerificationRequirement . Required ,
841+ UserVerification = UserVerificationRequirement . Discouraged ,
842842 } ,
843843 Challenge = challenge ,
844844 ErrorMessage = "" ,
@@ -915,7 +915,7 @@ public void TestAuthenticatorAttestationResponseNotUniqueCredId()
915915 {
916916 AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
917917 RequireResidentKey = true ,
918- UserVerification = UserVerificationRequirement . Required ,
918+ UserVerification = UserVerificationRequirement . Discouraged ,
919919 } ,
920920 Challenge = challenge ,
921921 ErrorMessage = "" ,
@@ -950,6 +950,83 @@ public void TestAuthenticatorAttestationResponseNotUniqueCredId()
950950 Assert . Equal ( "CredentialId is not unique to this user" , ex . Result . Message ) ;
951951 }
952952
953+ [ Fact ]
954+ public void TestAuthenticatorAttestationResponseUVRequired ( )
955+ {
956+ var challenge = RandomGenerator . Default . GenerateBytes ( 128 ) ;
957+ var rp = "https://www.passwordless.dev" ;
958+ var acd = new AttestedCredentialData ( ( "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-40-FE-6A-32-63-BE-37-D1-01-B1-2E-57-CA-96-6C-00-22-93-E4-19-C8-CD-01-06-23-0B-C6-92-E8-CC-77-12-21-F1-DB-11-5D-41-0F-82-6B-DB-98-AC-64-2E-B1-AE-B5-A8-03-D1-DB-C1-47-EF-37-1C-FD-B1-CE-B0-48-CB-2C-A5-01-02-03-26-20-01-21-58-20-A6-D1-09-38-5A-C7-8E-5B-F0-3D-1C-2E-08-74-BE-6D-BB-A4-0B-4F-2A-5F-2F-11-82-45-65-65-53-4F-67-28-22-58-20-43-E1-08-2A-F3-13-5B-40-60-93-79-AC-47-42-58-AA-B3-97-B8-86-1D-E4-41-B4-4E-83-08-5D-1C-6B-E0-D0" ) . Split ( '-' ) . Select ( c => Convert . ToByte ( c , 16 ) ) . ToArray ( ) ) ;
959+ var authData = new AuthenticatorData (
960+ SHA256 . HashData ( Encoding . UTF8 . GetBytes ( rp ) ) ,
961+ AuthenticatorFlags . AT | AuthenticatorFlags . UP ,
962+ 0 ,
963+ acd
964+ ) . ToByteArray ( ) ;
965+ var clientDataJson = JsonSerializer . SerializeToUtf8Bytes ( new
966+ {
967+ type = "webauthn.create" ,
968+ challenge = challenge ,
969+ origin = rp ,
970+ } ) ;
971+
972+ var rawResponse = new AuthenticatorAttestationRawResponse
973+ {
974+ Type = PublicKeyCredentialType . PublicKey ,
975+ Id = new byte [ ] { 0xf1 , 0xd0 } ,
976+ RawId = new byte [ ] { 0xf1 , 0xd0 } ,
977+ Response = new AuthenticatorAttestationRawResponse . ResponseData ( )
978+ {
979+ AttestationObject = new CborMap {
980+ { "fmt" , "none" } ,
981+ { "attStmt" , new CborMap ( ) } ,
982+ { "authData" , authData }
983+ } . Encode ( ) ,
984+ ClientDataJson = clientDataJson
985+ } ,
986+ } ;
987+
988+ var origChallenge = new CredentialCreateOptions
989+ {
990+ Attestation = AttestationConveyancePreference . Direct ,
991+ AuthenticatorSelection = new AuthenticatorSelection
992+ {
993+ AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
994+ RequireResidentKey = true ,
995+ UserVerification = UserVerificationRequirement . Required ,
996+ } ,
997+ Challenge = challenge ,
998+ ErrorMessage = "" ,
999+ PubKeyCredParams = new List < PubKeyCredParam > ( )
1000+ {
1001+ new PubKeyCredParam ( COSE . Algorithm . ES256 )
1002+ } ,
1003+ Rp = new PublicKeyCredentialRpEntity ( rp , rp , "" ) ,
1004+ Status = "ok" ,
1005+ User = new Fido2User
1006+ {
1007+ Name = "testuser" ,
1008+ Id = Encoding . UTF8 . GetBytes ( "testuser" ) ,
1009+ DisplayName = "Test User" ,
1010+ } ,
1011+ Timeout = 60000 ,
1012+ } ;
1013+
1014+ IsCredentialIdUniqueToUserAsyncDelegate callback = ( args ) =>
1015+ {
1016+ return Task . FromResult ( true ) ;
1017+ } ;
1018+
1019+ var lib = new Fido2 ( new Fido2Configuration ( )
1020+ {
1021+ ServerDomain = rp ,
1022+ ServerName = rp ,
1023+ Origins = new HashSet < string > { rp } ,
1024+ } ) ;
1025+
1026+ var ex = Assert . ThrowsAsync < Fido2VerificationException > ( ( ) => lib . MakeNewCredentialAsync ( rawResponse , origChallenge , callback ) ) ;
1027+ Assert . Equal ( "User Verified flag not set in authenticator data and user verification was required" , ex . Result . Message ) ;
1028+ }
1029+
9531030 [ Fact ]
9541031 public void TestAuthenticatorAssertionRawResponse ( )
9551032 {
0 commit comments