@@ -88,7 +88,7 @@ public async Task TestAuthenticatorOrigins(string origin, string expectedOrigin)
88
88
{
89
89
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
90
90
RequireResidentKey = true ,
91
- UserVerification = UserVerificationRequirement . Required ,
91
+ UserVerification = UserVerificationRequirement . Discouraged ,
92
92
} ,
93
93
Challenge = challenge ,
94
94
ErrorMessage = "" ,
@@ -192,7 +192,7 @@ public void TestAuthenticatorOriginsFail(string origin, string expectedOrigin)
192
192
{
193
193
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
194
194
RequireResidentKey = true ,
195
- UserVerification = UserVerificationRequirement . Required ,
195
+ UserVerification = UserVerificationRequirement . Discouraged ,
196
196
} ,
197
197
Challenge = challenge ,
198
198
ErrorMessage = "" ,
@@ -388,7 +388,7 @@ public void TestAuthenticatorAttestationResponseInvalidType()
388
388
{
389
389
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
390
390
RequireResidentKey = true ,
391
- UserVerification = UserVerificationRequirement . Required ,
391
+ UserVerification = UserVerificationRequirement . Discouraged ,
392
392
} ,
393
393
Challenge = challenge ,
394
394
ErrorMessage = "" ,
@@ -459,7 +459,7 @@ public void TestAuthenticatorAttestationResponseInvalidRawId(byte[] value)
459
459
{
460
460
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
461
461
RequireResidentKey = true ,
462
- UserVerification = UserVerificationRequirement . Required ,
462
+ UserVerification = UserVerificationRequirement . Discouraged ,
463
463
} ,
464
464
Challenge = challenge ,
465
465
ErrorMessage = "" ,
@@ -528,7 +528,7 @@ public void TestAuthenticatorAttestationResponseInvalidRawType()
528
528
{
529
529
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
530
530
RequireResidentKey = true ,
531
- UserVerification = UserVerificationRequirement . Required ,
531
+ UserVerification = UserVerificationRequirement . Discouraged ,
532
532
} ,
533
533
Challenge = challenge ,
534
534
ErrorMessage = "" ,
@@ -605,7 +605,7 @@ public void TestAuthenticatorAttestationResponseRpidMismatch()
605
605
{
606
606
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
607
607
RequireResidentKey = true ,
608
- UserVerification = UserVerificationRequirement . Required ,
608
+ UserVerification = UserVerificationRequirement . Discouraged ,
609
609
} ,
610
610
Challenge = challenge ,
611
611
ErrorMessage = "" ,
@@ -683,7 +683,7 @@ public void TestAuthenticatorAttestationResponseNotUserPresent()
683
683
{
684
684
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
685
685
RequireResidentKey = true ,
686
- UserVerification = UserVerificationRequirement . Required ,
686
+ UserVerification = UserVerificationRequirement . Discouraged ,
687
687
} ,
688
688
Challenge = challenge ,
689
689
ErrorMessage = "" ,
@@ -760,7 +760,7 @@ public void TestAuthenticatorAttestationResponseNoAttestedCredentialData()
760
760
{
761
761
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
762
762
RequireResidentKey = true ,
763
- UserVerification = UserVerificationRequirement . Required ,
763
+ UserVerification = UserVerificationRequirement . Discouraged ,
764
764
} ,
765
765
Challenge = challenge ,
766
766
ErrorMessage = "" ,
@@ -838,7 +838,7 @@ public void TestAuthenticatorAttestationResponseUnknownAttestationType()
838
838
{
839
839
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
840
840
RequireResidentKey = true ,
841
- UserVerification = UserVerificationRequirement . Required ,
841
+ UserVerification = UserVerificationRequirement . Discouraged ,
842
842
} ,
843
843
Challenge = challenge ,
844
844
ErrorMessage = "" ,
@@ -915,7 +915,7 @@ public void TestAuthenticatorAttestationResponseNotUniqueCredId()
915
915
{
916
916
AuthenticatorAttachment = AuthenticatorAttachment . CrossPlatform ,
917
917
RequireResidentKey = true ,
918
- UserVerification = UserVerificationRequirement . Required ,
918
+ UserVerification = UserVerificationRequirement . Discouraged ,
919
919
} ,
920
920
Challenge = challenge ,
921
921
ErrorMessage = "" ,
@@ -950,6 +950,83 @@ public void TestAuthenticatorAttestationResponseNotUniqueCredId()
950
950
Assert . Equal ( "CredentialId is not unique to this user" , ex . Result . Message ) ;
951
951
}
952
952
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
+
953
1030
[ Fact ]
954
1031
public void TestAuthenticatorAssertionRawResponse ( )
955
1032
{
0 commit comments