From 61e26940d53b2800243175f28a1b9bbe6e1d5af7 Mon Sep 17 00:00:00 2001 From: Marlon Regenhardt Date: Mon, 30 Dec 2024 01:06:30 +0100 Subject: [PATCH] Change Id to be received as string instead of decoded RawId is decoded to the raw byte value, while Id is the same value in base64url-encoded form. --- .../Server/Controllers/UserController.cs | 2 +- Demo/Controller.cs | 2 +- Demo/TestController.cs | 2 +- .../AuthenticatorAssertionRawResponse.cs | 3 +- Src/Fido2/AuthenticatorAssertionResponse.cs | 6 ++-- Tests/Fido2.Tests/AuthenticatorResponse.cs | 36 +++++++++---------- .../ExistingU2fRegistrationDataTests.cs | 5 +-- Tests/Fido2.Tests/Fido2Tests.cs | 2 +- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/BlazorWasmDemo/Server/Controllers/UserController.cs b/BlazorWasmDemo/Server/Controllers/UserController.cs index 5b648d00..cce465ce 100644 --- a/BlazorWasmDemo/Server/Controllers/UserController.cs +++ b/BlazorWasmDemo/Server/Controllers/UserController.cs @@ -265,7 +265,7 @@ public async Task MakeAssertionAsync([FromBody] AuthenticatorAssertionRa _pendingAssertions.Remove(key); // 2. Get registered credential from database - var creds = _demoStorage.GetCredentialById(clientResponse.Id) ?? throw new Exception("Unknown credentials"); + var creds = _demoStorage.GetCredentialById(clientResponse.RawId) ?? throw new Exception("Unknown credentials"); // 3. Make the assertion var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams diff --git a/Demo/Controller.cs b/Demo/Controller.cs index 367a30c1..1b745036 100644 --- a/Demo/Controller.cs +++ b/Demo/Controller.cs @@ -194,7 +194,7 @@ public async Task MakeAssertion([FromBody] AuthenticatorAssertionRaw var options = AssertionOptions.FromJson(jsonOptions); // 2. Get registered credential from database - var creds = DemoStorage.GetCredentialById(clientResponse.Id) ?? throw new Exception("Unknown credentials"); + var creds = DemoStorage.GetCredentialById(clientResponse.RawId) ?? throw new Exception("Unknown credentials"); // 3. Get credential counter from database var storedCounter = creds.SignCount; diff --git a/Demo/TestController.cs b/Demo/TestController.cs index 22758728..c12a1414 100644 --- a/Demo/TestController.cs +++ b/Demo/TestController.cs @@ -181,7 +181,7 @@ public async Task MakeAssertionTestAsync([FromBody] AuthenticatorAss var options = AssertionOptions.FromJson(jsonOptions); // 2. Get registered credential from database - var creds = _demoStorage.GetCredentialById(clientResponse.Id); + var creds = _demoStorage.GetCredentialById(clientResponse.RawId); // 3. Get credential counter from database var storedCounter = creds.SignCount; diff --git a/Src/Fido2.Models/AuthenticatorAssertionRawResponse.cs b/Src/Fido2.Models/AuthenticatorAssertionRawResponse.cs index c78b14bc..efc8d50a 100644 --- a/Src/Fido2.Models/AuthenticatorAssertionRawResponse.cs +++ b/Src/Fido2.Models/AuthenticatorAssertionRawResponse.cs @@ -12,9 +12,8 @@ namespace Fido2NetLib; /// public class AuthenticatorAssertionRawResponse { - [JsonConverter(typeof(Base64UrlConverter))] [JsonPropertyName("id"), Required] - public byte[] Id { get; init; } + public string Id { get; init; } // might be wrong to base64url encode this... [JsonConverter(typeof(Base64UrlConverter))] diff --git a/Src/Fido2/AuthenticatorAssertionResponse.cs b/Src/Fido2/AuthenticatorAssertionResponse.cs index bf94b4a5..f578338c 100644 --- a/Src/Fido2/AuthenticatorAssertionResponse.cs +++ b/Src/Fido2/AuthenticatorAssertionResponse.cs @@ -77,7 +77,7 @@ public async Task VerifyAsync( if (options.AllowCredentials != null && options.AllowCredentials.Any()) { // might need to transform x.Id and raw.id as described in https://www.w3.org/TR/webauthn/#publickeycredential - if (!options.AllowCredentials.Any(x => x.Id.SequenceEqual(Raw.Id))) + if (!options.AllowCredentials.Any(x => x.Id.SequenceEqual(Raw.RawId))) throw new Fido2VerificationException(Fido2ErrorCode.InvalidAssertionResponse, Fido2ErrorMessages.CredentialIdNotInAllowedCredentials); } @@ -87,7 +87,7 @@ public async Task VerifyAsync( if (UserHandle.Length is 0) throw new Fido2VerificationException(Fido2ErrorMessages.UserHandleIsEmpty); - if (await isUserHandleOwnerOfCredId(new IsUserHandleOwnerOfCredentialIdParams(Raw.Id, UserHandle), cancellationToken) is false) + if (await isUserHandleOwnerOfCredId(new IsUserHandleOwnerOfCredentialIdParams(Raw.RawId, UserHandle), cancellationToken) is false) { throw new Fido2VerificationException(Fido2ErrorCode.InvalidAssertionResponse, Fido2ErrorMessages.UserHandleNotOwnerOfPublicKey); } @@ -177,7 +177,7 @@ public async Task VerifyAsync( return new VerifyAssertionResult { - CredentialId = Raw.Id, + CredentialId = Raw.RawId, SignCount = authData.SignCount, IsBackedUp = authData.IsBackedUp diff --git a/Tests/Fido2.Tests/AuthenticatorResponse.cs b/Tests/Fido2.Tests/AuthenticatorResponse.cs index 8ce33b76..b8a2437c 100644 --- a/Tests/Fido2.Tests/AuthenticatorResponse.cs +++ b/Tests/Fido2.Tests/AuthenticatorResponse.cs @@ -1275,7 +1275,7 @@ public void TestAuthenticatorAssertionRawResponse() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -1301,7 +1301,7 @@ public void TestAuthenticatorAssertionRawResponse() } }; Assert.Equal(PublicKeyCredentialType.PublicKey, assertionResponse.Type); - Assert.Equal([0xf1, 0xd0], assertionResponse.Id); + Assert.Equal("8dA", assertionResponse.Id); Assert.Equal([0xf1, 0xd0], assertionResponse.RawId); Assert.Equal([0xf1, 0xd0], assertionResponse.Response.AuthenticatorData); Assert.Equal([0xf1, 0xd0], assertionResponse.Response.Signature); @@ -1352,7 +1352,7 @@ public async Task TestAuthenticatorAssertionTypeNotPublicKey() { Response = assertion, Type = PublicKeyCredentialType.Invalid, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -1504,7 +1504,7 @@ public async Task TestAuthenticatorAssertionRawIdMissing() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { AppID = false, @@ -1579,7 +1579,7 @@ public async Task TestAuthenticatorAssertionUserHandleEmpty() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -1655,7 +1655,7 @@ public async Task TestAuthenticatorAssertionUserHandleNotOwnerOfPublicKey() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -1731,7 +1731,7 @@ public async Task TestAuthenticatorAssertionTypeNotWebAuthnGet() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -1809,7 +1809,7 @@ public async Task TestAuthenticatorAssertionAppId() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -1886,7 +1886,7 @@ public async Task TestAuthenticatorAssertionInvalidRpIdHash() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -1964,7 +1964,7 @@ public async Task TestAuthenticatorAssertionUPRequirementNotMet() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -2041,7 +2041,7 @@ public async Task TestAuthenticatorAssertionUVPolicyNotMet() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -2116,7 +2116,7 @@ public async Task TestAuthenticatorAssertionBEPolicyRequired() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -2192,7 +2192,7 @@ public async Task TestAuthenticatorAssertionBEPolicyDisallow() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -2268,7 +2268,7 @@ public async Task TestAuthenticatorAssertionBSPolicyRequired() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -2344,7 +2344,7 @@ public async Task TestAuthenticatorAssertionBSPolicyDisallow() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs { @@ -2421,7 +2421,7 @@ public async Task TestAuthenticatorAssertionStoredPublicKeyMissing() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -2497,7 +2497,7 @@ public async Task TestAuthenticatorAssertionInvalidSignature() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { @@ -2580,7 +2580,7 @@ public async Task TestAuthenticatorAssertionSignCountSignature() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], ClientExtensionResults = new AuthenticationExtensionsClientOutputs() { diff --git a/Tests/Fido2.Tests/ExistingU2fRegistrationDataTests.cs b/Tests/Fido2.Tests/ExistingU2fRegistrationDataTests.cs index 6097498e..f03a60fb 100644 --- a/Tests/Fido2.Tests/ExistingU2fRegistrationDataTests.cs +++ b/Tests/Fido2.Tests/ExistingU2fRegistrationDataTests.cs @@ -14,7 +14,8 @@ public async Task TestFido2AssertionWithExistingU2fRegistrationWithAppId() { // u2f registration with appId var appId = "https://localhost:44336"; - var keyHandleData = Base64Url.DecodeFromChars("2uzGTqu9XGoDQpRBhkv3qDYWzEEZrDjOHT94fHe3J9VXl6KpaY6jL1C4gCAVSBCWZejOn-EYSyXfiG7RDQqgKw"); + var keyHandleB64Data = "2uzGTqu9XGoDQpRBhkv3qDYWzEEZrDjOHT94fHe3J9VXl6KpaY6jL1C4gCAVSBCWZejOn-EYSyXfiG7RDQqgKw"; + var keyHandleData = Base64Url.DecodeFromChars(keyHandleB64Data); var publicKeyData = Base64Url.DecodeFromChars("BEKJkJiDzo8wlrYbAHmyz5a5vShbkStO58ZO7F-hy4fvBp6TowCZoV2dNGcxIN1yT18799bb_WuP0Yq_DSv5a-U"); //key as cbor @@ -36,7 +37,7 @@ public async Task TestFido2AssertionWithExistingU2fRegistrationWithAppId() var authResponse = new AuthenticatorAssertionRawResponse { - Id = keyHandleData, + Id = keyHandleB64Data, RawId = keyHandleData, Type = PublicKeyCredentialType.PublicKey, ClientExtensionResults = new AuthenticationExtensionsClientOutputs diff --git a/Tests/Fido2.Tests/Fido2Tests.cs b/Tests/Fido2.Tests/Fido2Tests.cs index c2b51bf2..cd0d5c9e 100644 --- a/Tests/Fido2.Tests/Fido2Tests.cs +++ b/Tests/Fido2.Tests/Fido2Tests.cs @@ -987,7 +987,7 @@ internal static async Task MakeAssertionResponseAsync( { Response = assertion, Type = PublicKeyCredentialType.PublicKey, - Id = [0xf1, 0xd0], + Id = "8dA", RawId = [0xf1, 0xd0], }; IsUserHandleOwnerOfCredentialIdAsync callback = (args, cancellationToken) =>