From ab35c93ac5e35988be13e73e1be7a5a2099342d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Mon, 18 Nov 2024 17:50:37 +0100 Subject: [PATCH 1/2] Allow customised pubKeyCredParams --- Demo/TestController.cs | 10 +++-- Src/Fido2.Models/CredentialCreateOptions.cs | 40 +++++++++++-------- Src/Fido2/Fido2.cs | 2 +- Src/Fido2/RequestNewCredentialParams.cs | 5 +++ Tests/Fido2.Tests/Fido2Tests.cs | 2 - .../TestFiles/attestationOptionsPacked.json | 4 ++ .../TestFiles/attestationTPMSHA1Options.json | 6 ++- 7 files changed, 44 insertions(+), 25 deletions(-) diff --git a/Demo/TestController.cs b/Demo/TestController.cs index ca916982..7c408498 100644 --- a/Demo/TestController.cs +++ b/Demo/TestController.cs @@ -74,10 +74,12 @@ public OkObjectResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialPa ExcludeCredentials = existingKeys, AuthenticatorSelection = opts.AuthenticatorSelection, AttestationPreference = opts.Attestation, - Extensions = exts - }); - - // 4. Temporarily store options, session/in-memory cache/redis/db + Extensions = exts, + // Conformance tools requires RS1, but it's deprecated + PubKeyCredParams = [..PubKeyCredParam.Defaults, PubKeyCredParam.RS1] + }); + + // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson()); // 5. return options to client diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index abc62c08..4c380759 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -35,7 +35,7 @@ public sealed class CredentialCreateOptions /// This member contains information about the desired properties of the credential to be created. The sequence is ordered from most preferred to least preferred. The platform makes a best-effort to create the most preferred credential that it can. /// [JsonPropertyName("pubKeyCredParams")] - public List PubKeyCredParams { get; set; } + public IReadOnlyList PubKeyCredParams { get; set; } /// /// This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, and MAY be overridden by the platform. @@ -122,7 +122,9 @@ public static CredentialCreateOptions Create( AuthenticatorSelection authenticatorSelection, AttestationConveyancePreference attestationConveyancePreference, IReadOnlyList excludeCredentials, - AuthenticationExtensionsClientInputs extensions) + AuthenticationExtensionsClientInputs extensions, + IReadOnlyList pubKeyCredParams) + { return new CredentialCreateOptions { @@ -130,21 +132,7 @@ public static CredentialCreateOptions Create( Rp = new PublicKeyCredentialRpEntity(config.ServerDomain, config.ServerName, config.ServerIcon), Timeout = config.Timeout, User = user, - PubKeyCredParams = - [ - // Add additional as appropriate - PubKeyCredParam.Ed25519, - PubKeyCredParam.ES256, - PubKeyCredParam.RS256, - PubKeyCredParam.PS256, - PubKeyCredParam.ES384, - PubKeyCredParam.RS384, - PubKeyCredParam.PS384, - PubKeyCredParam.ES512, - PubKeyCredParam.RS512, - PubKeyCredParam.PS512, - PubKeyCredParam.RS1 - ], + PubKeyCredParams = pubKeyCredParams, AuthenticatorSelection = authenticatorSelection, Attestation = attestationConveyancePreference, ExcludeCredentials = excludeCredentials, @@ -196,6 +184,24 @@ public sealed class PubKeyCredParam( public static readonly PubKeyCredParam PS512 = new(COSE.Algorithm.PS512); public static readonly PubKeyCredParam Ed25519 = new(COSE.Algorithm.EdDSA); public static readonly PubKeyCredParam RS1 = new(COSE.Algorithm.RS1); + + /// + /// The default algorithms supported by the library + /// + public static IReadOnlyList Defaults => + [ + // Add additional as appropriate + Ed25519, + ES256, + RS256, + PS256, + ES384, + RS384, + PS384, + ES512, + RS512, + PS512 + ]; } /// diff --git a/Src/Fido2/Fido2.cs b/Src/Fido2/Fido2.cs index a35fa853..04a75f89 100644 --- a/Src/Fido2/Fido2.cs +++ b/Src/Fido2/Fido2.cs @@ -31,7 +31,7 @@ public Fido2( public CredentialCreateOptions RequestNewCredential(RequestNewCredentialParams requestNewCredentialParams) { var challenge = RandomNumberGenerator.GetBytes(_config.ChallengeSize); - return CredentialCreateOptions.Create(_config, challenge, requestNewCredentialParams.User, requestNewCredentialParams.AuthenticatorSelection, requestNewCredentialParams.AttestationPreference, requestNewCredentialParams.ExcludeCredentials, requestNewCredentialParams.Extensions); + return CredentialCreateOptions.Create(_config, challenge, requestNewCredentialParams.User, requestNewCredentialParams.AuthenticatorSelection, requestNewCredentialParams.AttestationPreference, requestNewCredentialParams.ExcludeCredentials, requestNewCredentialParams.Extensions, requestNewCredentialParams.PubKeyCredParams); } diff --git a/Src/Fido2/RequestNewCredentialParams.cs b/Src/Fido2/RequestNewCredentialParams.cs index 13877c75..03836671 100644 --- a/Src/Fido2/RequestNewCredentialParams.cs +++ b/Src/Fido2/RequestNewCredentialParams.cs @@ -34,4 +34,9 @@ public sealed class RequestNewCredentialParams /// The Relying Party MAY use this OPTIONAL member to provide client extension inputs requesting additional processing by the client and authenticator. For example, the Relying Party may request that the client returns additional information about the credential that was created. /// public AuthenticationExtensionsClientInputs? Extensions { get; init; } + + /// + /// For advanced use cases. This member lists the key types and signature algorithms the Relying Party supports, ordered from most preferred to least preferred. The client and authenticator make a best-effort to create a credential of the most preferred type possible. If none of the listed types can be created, the create() operation fails. + /// + public IReadOnlyList PubKeyCredParams { get; init; } = PubKeyCredParam.Defaults; } diff --git a/Tests/Fido2.Tests/Fido2Tests.cs b/Tests/Fido2.Tests/Fido2Tests.cs index 9c70358b..c2b51bf2 100644 --- a/Tests/Fido2.Tests/Fido2Tests.cs +++ b/Tests/Fido2.Tests/Fido2Tests.cs @@ -611,7 +611,6 @@ public async Task TestPackedAttestationAsync() var jsonPost = JsonSerializer.Deserialize(await File.ReadAllTextAsync("./attestationResultsPacked.json")); var options = JsonSerializer.Deserialize(await File.ReadAllTextAsync("./attestationOptionsPacked.json")); var o = AuthenticatorAttestationResponse.Parse(jsonPost); - options.PubKeyCredParams.Add(new PubKeyCredParam(COSE.Algorithm.RS1, PublicKeyCredentialType.PublicKey)); await o.VerifyAsync(options, _config, (x, cancellationToken) => Task.FromResult(true), _metadataService, null, CancellationToken.None); var authData = o.AttestationObject.AuthData; var acdBytes = authData.AttestedCredentialData.ToByteArray(); @@ -644,7 +643,6 @@ public async Task TestTPMSHA1AttestationAsync() var jsonPost = JsonSerializer.Deserialize(await File.ReadAllTextAsync("./attestationTPMSHA1Response.json")); var options = JsonSerializer.Deserialize(await File.ReadAllTextAsync("./attestationTPMSHA1Options.json")); var o = AuthenticatorAttestationResponse.Parse(jsonPost); - options.PubKeyCredParams.Add(new PubKeyCredParam(COSE.Algorithm.RS1, PublicKeyCredentialType.PublicKey)); await o.VerifyAsync(options, _config, (x, cancellationToken) => Task.FromResult(true), _metadataService, null, CancellationToken.None); } diff --git a/Tests/Fido2.Tests/TestFiles/attestationOptionsPacked.json b/Tests/Fido2.Tests/TestFiles/attestationOptionsPacked.json index 0954584d..21301e4a 100644 --- a/Tests/Fido2.Tests/TestFiles/attestationOptionsPacked.json +++ b/Tests/Fido2.Tests/TestFiles/attestationOptionsPacked.json @@ -15,6 +15,10 @@ { "type": "public-key", "alg": -7 + }, + { + "type": "public-key", + "alg": -65535 } ], "timeout": 0 diff --git a/Tests/Fido2.Tests/TestFiles/attestationTPMSHA1Options.json b/Tests/Fido2.Tests/TestFiles/attestationTPMSHA1Options.json index 0915b21c..3afe62f5 100644 --- a/Tests/Fido2.Tests/TestFiles/attestationTPMSHA1Options.json +++ b/Tests/Fido2.Tests/TestFiles/attestationTPMSHA1Options.json @@ -19,7 +19,11 @@ { "type": "public-key", "alg": -257 - } + }, + { + "type": "public-key", + "alg": -65535 + } ], "timeout": 60000, "attestation": "direct", From 6dddf89d67645bccc098bd201b31f8c1a2edd1f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Mon, 18 Nov 2024 20:06:22 +0100 Subject: [PATCH 2/2] format --- Demo/TestController.cs | 2 +- Src/Fido2.Models/CredentialCreateOptions.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Demo/TestController.cs b/Demo/TestController.cs index 7c408498..22758728 100644 --- a/Demo/TestController.cs +++ b/Demo/TestController.cs @@ -76,7 +76,7 @@ public OkObjectResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialPa AttestationPreference = opts.Attestation, Extensions = exts, // Conformance tools requires RS1, but it's deprecated - PubKeyCredParams = [..PubKeyCredParam.Defaults, PubKeyCredParam.RS1] + PubKeyCredParams = [.. PubKeyCredParam.Defaults, PubKeyCredParam.RS1] }); // 4. Temporarily store options, session/in-memory cache/redis/db diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index 4c380759..91cb362d 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -123,8 +123,8 @@ public static CredentialCreateOptions Create( AttestationConveyancePreference attestationConveyancePreference, IReadOnlyList excludeCredentials, AuthenticationExtensionsClientInputs extensions, - IReadOnlyList pubKeyCredParams) - + IReadOnlyList pubKeyCredParams) + { return new CredentialCreateOptions { @@ -183,8 +183,8 @@ public sealed class PubKeyCredParam( public static readonly PubKeyCredParam PS384 = new(COSE.Algorithm.PS384); public static readonly PubKeyCredParam PS512 = new(COSE.Algorithm.PS512); public static readonly PubKeyCredParam Ed25519 = new(COSE.Algorithm.EdDSA); - public static readonly PubKeyCredParam RS1 = new(COSE.Algorithm.RS1); - + public static readonly PubKeyCredParam RS1 = new(COSE.Algorithm.RS1); + /// /// The default algorithms supported by the library ///