diff --git a/BlazorWasmDemo/Server/Controllers/UserController.cs b/BlazorWasmDemo/Server/Controllers/UserController.cs index 7ad042ab..1ec1719e 100644 --- a/BlazorWasmDemo/Server/Controllers/UserController.cs +++ b/BlazorWasmDemo/Server/Controllers/UserController.cs @@ -150,7 +150,12 @@ public async Task CreateCredentialAsync([FromRoute] string username, [Fr // 2. Create callback so that lib can verify credential id is unique to this user // 3. Verify and make the credentials - var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, CredentialIdUniqueToUserAsync, cancellationToken: cancellationToken); + var credential = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = attestationResponse, + OriginalOptions = options, + IsCredentialIdUniqueToUserCallback = CredentialIdUniqueToUserAsync + }, cancellationToken: cancellationToken); // 4. Store the credentials in db _demoStorage.AddCredentialToUser(options.User, new StoredCredential @@ -266,14 +271,15 @@ public async Task MakeAssertionAsync([FromBody] AuthenticatorAssertionRa var creds = _demoStorage.GetCredentialById(clientResponse.Id) ?? throw new Exception("Unknown credentials"); // 3. Make the assertion - var res = await _fido2.MakeAssertionAsync( - clientResponse, - options, - creds.PublicKey, - creds.DevicePublicKeys, - creds.SignCount, - UserHandleOwnerOfCredentialIdAsync, - cancellationToken: cancellationToken); + var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = clientResponse, + OriginalOptions = options, + StoredPublicKey = creds.PublicKey, + StoredSignatureCounter = creds.SignCount, + IsUserHandleOwnerOfCredentialIdCallback = UserHandleOwnerOfCredentialIdAsync, + StoredDevicePublicKeys = creds.DevicePublicKeys + }, cancellationToken: cancellationToken); // 4. Store the updated counter _demoStorage.UpdateCounter(res.CredentialId, res.SignCount); diff --git a/Demo/Controller.cs b/Demo/Controller.cs index 733f11e7..b0a0273b 100644 --- a/Demo/Controller.cs +++ b/Demo/Controller.cs @@ -106,7 +106,12 @@ public async Task MakeCredential([FromBody] AuthenticatorAttestation }; // 2. Verify and make the credentials - var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken); + var credential = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = attestationResponse, + OriginalOptions = options, + IsCredentialIdUniqueToUserCallback = callback + }, cancellationToken: cancellationToken); // 3. Store the credentials in db DemoStorage.AddCredentialToUser(options.User, new StoredCredential @@ -204,7 +209,15 @@ public async Task MakeAssertion([FromBody] AuthenticatorAssertionRaw }; // 5. Make the assertion - var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, creds.DevicePublicKeys, storedCounter, callback, cancellationToken: cancellationToken); + var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = clientResponse, + OriginalOptions = options, + StoredPublicKey = creds.PublicKey, + StoredSignatureCounter = storedCounter, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = creds.DevicePublicKeys + }, cancellationToken: cancellationToken); // 6. Store the updated counter DemoStorage.UpdateCounter(res.CredentialId, res.SignCount); diff --git a/Demo/TestController.cs b/Demo/TestController.cs index 5967a8af..2ccf4fdc 100644 --- a/Demo/TestController.cs +++ b/Demo/TestController.cs @@ -95,7 +95,12 @@ public async Task MakeCredentialResultTestAsync([FromBody] Authe }; // 2. Verify and make the credentials - var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken); + var credential = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = attestationResponse, + OriginalOptions = options, + IsCredentialIdUniqueToUserCallback = callback + }, cancellationToken: cancellationToken); // 3. Store the credentials in db _demoStorage.AddCredentialToUser(options.User, new StoredCredential @@ -177,7 +182,15 @@ public async Task MakeAssertionTestAsync([FromBody] AuthenticatorAss }; // 5. Make the assertion - var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, creds.DevicePublicKeys, storedCounter, callback, cancellationToken: cancellationToken); + var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = clientResponse, + OriginalOptions = options, + StoredPublicKey = creds.PublicKey, + StoredSignatureCounter = storedCounter, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = creds.DevicePublicKeys + }, cancellationToken: cancellationToken); // 6. Store the updated counter _demoStorage.UpdateCounter(res.CredentialId, res.SignCount); diff --git a/Src/Fido2/Fido2.cs b/Src/Fido2/Fido2.cs index 8ebf338b..afd32d96 100644 --- a/Src/Fido2/Fido2.cs +++ b/Src/Fido2/Fido2.cs @@ -62,21 +62,14 @@ public CredentialCreateOptions RequestNewCredential( /// /// Verifies the response from the browser/authenticator after creating new credentials. /// - /// The attestation response from the authenticator. - /// The original options that was sent to the client. - /// The delegate used to validate that the CredentialID is unique to this user. - /// DO NOT USE - Deprecated, but kept in code due to conformance testing tool + /// Wraps the input parameters for making a new credential /// The used to propagate notifications that the operation should be canceled. /// - public async Task MakeNewCredentialAsync( - AuthenticatorAttestationRawResponse attestationResponse, - CredentialCreateOptions originalOptions, - IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser, - byte[]? requestTokenBindingId = null, + public async Task MakeNewCredentialAsync(MakeNewCredentialParams makeNewCredentialParams, CancellationToken cancellationToken = default) { - var parsedResponse = AuthenticatorAttestationResponse.Parse(attestationResponse); - var credential = await parsedResponse.VerifyAsync(originalOptions, _config, isCredentialIdUniqueToUser, _metadataService, requestTokenBindingId, cancellationToken); + var parsedResponse = AuthenticatorAttestationResponse.Parse(makeNewCredentialParams.AttestationResponse); + var credential = await parsedResponse.VerifyAsync(makeNewCredentialParams.OriginalOptions, _config, makeNewCredentialParams.IsCredentialIdUniqueToUserCallback, _metadataService, makeNewCredentialParams.RequestTokenBindingId, cancellationToken); return credential; } @@ -101,35 +94,22 @@ public AssertionOptions GetAssertionOptions( /// /// Verifies the assertion response from the browser/authenticator to assert existing credentials and authenticate a user. /// - /// The assertion response from the authenticator. - /// The original options that was sent to the client. - /// The stored credential public key. - /// The stored device public keys. - /// The stored value of the signature counter. - /// The delegate used to validate that the user handle is indeed owned of the CredentialId. - /// DO NOT USE - Deprecated, but kept in code due to conformance testing tool + /// Wraps the input arguments for asserting a passkey /// The used to propagate notifications that the operation should be canceled. /// - public async Task MakeAssertionAsync( - AuthenticatorAssertionRawResponse assertionResponse, - AssertionOptions originalOptions, - byte[] storedPublicKey, - IReadOnlyList storedDevicePublicKeys, - uint storedSignatureCounter, - IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredentialIdCallback, - byte[]? requestTokenBindingId = null, + public async Task MakeAssertionAsync(MakeAssertionParams makeAssertionParams, CancellationToken cancellationToken = default) { - var parsedResponse = AuthenticatorAssertionResponse.Parse(assertionResponse); + var parsedResponse = AuthenticatorAssertionResponse.Parse(makeAssertionParams.AssertionResponse); - var result = await parsedResponse.VerifyAsync(originalOptions, + var result = await parsedResponse.VerifyAsync(makeAssertionParams.OriginalOptions, _config, - storedPublicKey, - storedDevicePublicKeys, - storedSignatureCounter, - isUserHandleOwnerOfCredentialIdCallback, + makeAssertionParams.StoredPublicKey, + makeAssertionParams.StoredDevicePublicKeys, + makeAssertionParams.StoredSignatureCounter, + makeAssertionParams.IsUserHandleOwnerOfCredentialIdCallback, _metadataService, - requestTokenBindingId, + makeAssertionParams.RequestTokenBindingId, cancellationToken); return result; diff --git a/Src/Fido2/IFido2.cs b/Src/Fido2/IFido2.cs index 8b58de02..e22035c4 100644 --- a/Src/Fido2/IFido2.cs +++ b/Src/Fido2/IFido2.cs @@ -13,21 +13,10 @@ AssertionOptions GetAssertionOptions( UserVerificationRequirement? userVerification, AuthenticationExtensionsClientInputs? extensions = null); - Task MakeAssertionAsync( - AuthenticatorAssertionRawResponse assertionResponse, - AssertionOptions originalOptions, - byte[] storedPublicKey, - IReadOnlyList storedDevicePublicKeys, - uint storedSignatureCounter, - IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredentialIdCallback, - byte[]? requestTokenBindingId = null, + Task MakeAssertionAsync(MakeAssertionParams makeAssertionParams, CancellationToken cancellationToken = default); - Task MakeNewCredentialAsync( - AuthenticatorAttestationRawResponse attestationResponse, - CredentialCreateOptions originalOptions, - IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser, - byte[]? requestTokenBindingId = null, + Task MakeNewCredentialAsync(MakeNewCredentialParams makeNewCredentialParams, CancellationToken cancellationToken = default); CredentialCreateOptions RequestNewCredential( diff --git a/Src/Fido2/MakeAssertionParams.cs b/Src/Fido2/MakeAssertionParams.cs new file mode 100644 index 00000000..206def41 --- /dev/null +++ b/Src/Fido2/MakeAssertionParams.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace Fido2NetLib; + +/// +/// Wraps the input for the MakeAssertion function +/// +public class MakeAssertionParams +{ + /// + /// The assertion response from the authenticator. + /// + public required AuthenticatorAssertionRawResponse AssertionResponse { get; init; } + + /// + /// The original options that was sent to the client. + /// + public required AssertionOptions OriginalOptions { get; init; } + + /// + /// The stored credential public key. + /// + public required byte[] StoredPublicKey { get; init; } + + /// + /// The stored value of the signature counter. + /// + public required uint StoredSignatureCounter { get; init; } + + /// + /// The delegate used to validate that the user handle is indeed owned of the CredentialId. + /// + public required IsUserHandleOwnerOfCredentialIdAsync IsUserHandleOwnerOfCredentialIdCallback { get; init; } + + /// + /// The stored device public keys. + /// + public IReadOnlyList StoredDevicePublicKeys { get; init; } = Array.Empty(); + + + /// + /// DO NOT USE - Deprecated, but kept in code due to conformance testing tool. + /// + public byte[]? RequestTokenBindingId { get; init; } +} diff --git a/Src/Fido2/MakeNewCredentialParams.cs b/Src/Fido2/MakeNewCredentialParams.cs new file mode 100644 index 00000000..852b8969 --- /dev/null +++ b/Src/Fido2/MakeNewCredentialParams.cs @@ -0,0 +1,27 @@ +namespace Fido2NetLib; + +/// +/// Wraps the input for the MakeNewCredential function +/// +public class MakeNewCredentialParams +{ + /// + /// The attestation response from the authenticator. + /// + public required AuthenticatorAttestationRawResponse AttestationResponse { get; init; } + + /// + /// The original options that was sent to the client. + /// + public required CredentialCreateOptions OriginalOptions { get; init; } + + /// + /// The delegate used to validate that the CredentialID is unique to this user. + /// + public required IsCredentialIdUniqueToUserAsyncDelegate IsCredentialIdUniqueToUserCallback { get; init; } + + /// + /// DO NOT USE - Deprecated, but kept in code due to conformance testing tool + /// + public byte[]? RequestTokenBindingId { get; init; } +} diff --git a/Test/Attestation/Apple.cs b/Test/Attestation/Apple.cs index a09862dd..6bcc7267 100644 --- a/Test/Attestation/Apple.cs +++ b/Test/Attestation/Apple.cs @@ -269,7 +269,12 @@ public async Task TestApplePublicKeyMismatch() Origins = new HashSet { "https://www.passwordless.dev" }, }); - var credentialMakeResult = await lib.MakeNewCredentialAsync(attestationResponse, originalOptions, callback); + var credentialMakeResult = await lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = attestationResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + }); } private string[] StackAllocSha256(ReadOnlySpan authData, ReadOnlySpan clientDataJson) diff --git a/Test/AuthenticatorResponse.cs b/Test/AuthenticatorResponse.cs index 93b6a064..6528ab2c 100644 --- a/Test/AuthenticatorResponse.cs +++ b/Test/AuthenticatorResponse.cs @@ -123,7 +123,12 @@ public async Task TestAuthenticatorOriginsAsync(string origin, string expectedOr Origins = new HashSet { expectedOrigin }, }); - var result = await lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback); + var result = await lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + }); } [Theory] @@ -224,7 +229,12 @@ public async Task TestAuthenticatorOriginsFail(string origin, string expectedOri Origins = new HashSet { expectedOrigin }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.StartsWith("Fully qualified origin", ex.Message); } @@ -433,7 +443,12 @@ public async Task TestAuthenticatorAttestationResponseInvalidType() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Same(Fido2ErrorMessages.AttestationResponseTypeNotWebAuthnGet, ex.Message); } @@ -503,7 +518,12 @@ public async Task TestAuthenticatorAttestationResponseInvalidRawId(byte[] value) Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Same(Fido2ErrorMessages.AttestationResponseIdMissing, ex.Message); } @@ -571,7 +591,12 @@ public async Task TestAuthenticatorAttestationResponseInvalidRawType() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal("AttestationResponse type must be 'public-key'", ex.Message); } @@ -646,7 +671,12 @@ public async Task TestAuthenticatorAttestationResponseRpidMismatch() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal(Fido2ErrorCode.InvalidRpidHash, ex.Code); Assert.Equal(Fido2ErrorMessages.InvalidRpidHash, ex.Message); } @@ -723,7 +753,12 @@ public async Task TestAuthenticatorAttestationResponseNotUserPresentAsync() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal(Fido2ErrorCode.UserPresentFlagNotSet, ex.Code); Assert.Equal(Fido2ErrorMessages.UserPresentFlagNotSet, ex.Message); @@ -801,7 +836,12 @@ public async Task TestAuthenticatorAttestationResponseBackupEligiblePolicyRequir BackupEligibleCredentialPolicy = Fido2Configuration.CredentialBackupPolicy.Required, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal(Fido2ErrorMessages.BackupEligibilityRequirementNotMet, ex.Message); } @@ -877,7 +917,12 @@ public async Task TestAuthenticatorAttestationResponseBackupEligiblePolicyDisall BackupEligibleCredentialPolicy = Fido2Configuration.CredentialBackupPolicy.Disallowed, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal(Fido2ErrorMessages.BackupEligibilityRequirementNotMet, ex.Message); } @@ -952,7 +997,12 @@ public async Task TestAuthenticatorAttestationResponseNoAttestedCredentialData() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal("Attestation flag not set on attestation data", ex.Message); } @@ -1028,7 +1078,12 @@ public async Task TestAuthenticatorAttestationResponseUnknownAttestationType() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal("Unknown attestation type. Was 'testing'", ex.Message); Assert.Equal(Fido2ErrorCode.UnknownAttestationType, ex.Code); } @@ -1104,7 +1159,12 @@ public async Task TestAuthenticatorAttestationResponseNotUniqueCredId() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal("CredentialId is not unique to this user", ex.Message); } @@ -1179,7 +1239,12 @@ public async Task TestAuthenticatorAttestationResponseUVRequired() Origins = new HashSet { rp }, }); - var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(rawResponse, originalOptions, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = rawResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + })); Assert.Equal("User Verified flag not set in authenticator data and user verification was required", ex.Message); } @@ -1313,7 +1378,15 @@ public async Task TestAuthenticatorAssertionTypeNotPublicKey() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.AssertionResponseNotPublicKey, ex.Message); } @@ -1381,7 +1454,15 @@ public async Task TestAuthenticatorAssertionIdMissing() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.AssertionResponseIdMissing, ex.Message); } @@ -1450,7 +1531,15 @@ public async Task TestAuthenticatorAssertionRawIdMissing() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.AssertionResponseRawIdMissing, ex.Message); } @@ -1519,7 +1608,15 @@ public async Task TestAuthenticatorAssertionUserHandleEmpty() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.UserHandleIsEmpty, ex.Message); } @@ -1588,7 +1685,15 @@ public async Task TestAuthenticatorAssertionUserHandleNotOwnerOfPublicKey() return Task.FromResult(false); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.UserHandleNotOwnerOfPublicKey, ex.Message); } @@ -1657,7 +1762,15 @@ public async Task TestAuthenticatorAssertionTypeNotWebAuthnGet() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.AssertionResponseTypeNotWebAuthnGet, ex.Message); } @@ -1728,7 +1841,15 @@ public async Task TestAuthenticatorAssertionAppId() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.InvalidRpidHash, ex.Message); } @@ -1798,7 +1919,15 @@ public async Task TestAuthenticatorAssertionInvalidRpIdHash() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.InvalidRpidHash, ex.Message); } @@ -1868,7 +1997,15 @@ public async Task TestAuthenticatorAssertionUPRequirementNotMet() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.UserPresentFlagNotSet, ex.Message); } @@ -1938,7 +2075,15 @@ public async Task TestAuthenticatorAssertionUVPolicyNotMet() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.UserVerificationRequirementNotMet, ex.Message); } @@ -2007,7 +2152,15 @@ public async Task TestAuthenticatorAssertionBEPolicyRequired() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.BackupEligibilityRequirementNotMet, ex.Message); } @@ -2076,7 +2229,15 @@ public async Task TestAuthenticatorAssertionBEPolicyDisallow() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.BackupEligibilityRequirementNotMet, ex.Message); } @@ -2145,7 +2306,15 @@ public async Task TestAuthenticatorAssertionBSPolicyRequired() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.BackupStateRequirementNotMet, ex.Message); } @@ -2214,7 +2383,15 @@ public async Task TestAuthenticatorAssertionBSPolicyDisallow() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.BackupStateRequirementNotMet, ex.Message); } @@ -2283,7 +2460,15 @@ public async Task TestAuthenticatorAssertionStoredPublicKeyMissing() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, null, null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = null, + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.MissingStoredPublicKey, ex.Message); } @@ -2353,7 +2538,15 @@ public async Task TestAuthenticatorAssertionInvalidSignature() }; fido2_net_lib.Test.Fido2Tests.MakeEdDSA(out _, out var publicKey, out var privateKey); - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, fido2_net_lib.Test.Fido2Tests.MakeCredentialPublicKey(COSE.KeyType.OKP, COSE.Algorithm.EdDSA, COSE.EllipticCurve.Ed25519, publicKey).GetBytes(), null, 0, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = fido2_net_lib.Test.Fido2Tests.MakeCredentialPublicKey(COSE.KeyType.OKP, COSE.Algorithm.EdDSA, COSE.EllipticCurve.Ed25519, publicKey).GetBytes(), + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.InvalidSignature, ex.Message); } @@ -2428,7 +2621,15 @@ public async Task TestAuthenticatorAssertionSignCountSignature() return Task.FromResult(true); }; - var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(assertionResponse, options, cpk.GetBytes(), null, 2, callback)); + var ex = await Assert.ThrowsAsync(() => lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = assertionResponse, + OriginalOptions = options, + StoredPublicKey = cpk.GetBytes(), + StoredSignatureCounter = 2, + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredDevicePublicKeys = null + })); Assert.Equal(Fido2ErrorMessages.SignCountIsLessThanSignatureCounter, ex.Message); } } diff --git a/Test/ExistingU2fRegistrationDataTests.cs b/Test/ExistingU2fRegistrationDataTests.cs index 55f2f80e..f740bbbb 100644 --- a/Test/ExistingU2fRegistrationDataTests.cs +++ b/Test/ExistingU2fRegistrationDataTests.cs @@ -55,7 +55,16 @@ public async Task TestFido2AssertionWithExistingU2fRegistrationWithAppId() Origins = new HashSet { "https://localhost:44336" } //data was generated with this origin }); - var credential = await fido2.MakeAssertionAsync(authResponse, options, publicKey.Encode(), null, 0, null); + var credential = await fido2.MakeAssertionAsync(new MakeAssertionParams + { + + AssertionResponse = authResponse, + OriginalOptions = options, + StoredPublicKey = publicKey.Encode(), + StoredSignatureCounter = 0, + IsUserHandleOwnerOfCredentialIdCallback = null, + StoredDevicePublicKeys = null + }); Assert.NotEmpty(credential.CredentialId); } diff --git a/Test/Fido2Tests.cs b/Test/Fido2Tests.cs index db69354c..cfe2ed45 100644 --- a/Test/Fido2Tests.cs +++ b/Test/Fido2Tests.cs @@ -237,7 +237,12 @@ public async Task MakeAttestationResponseAsync() Origins = new HashSet { rp }, }); - var credentialMakeResult = await lib.MakeNewCredentialAsync(attestationResponse, originalOptions, callback); + var credentialMakeResult = await lib.MakeNewCredentialAsync(new MakeNewCredentialParams + { + AttestationResponse = attestationResponse, + OriginalOptions = originalOptions, + IsCredentialIdUniqueToUserCallback = callback + }); return credentialMakeResult; } @@ -988,7 +993,14 @@ internal static async Task MakeAssertionResponseAsync( { return Task.FromResult(true); }; - return await lib.MakeAssertionAsync(response, options, cpk.GetBytes(), null, signCount, callback); + return await lib.MakeAssertionAsync(new MakeAssertionParams + { + AssertionResponse = response, + OriginalOptions = options, + StoredPublicKey = cpk.GetBytes(), + IsUserHandleOwnerOfCredentialIdCallback = callback, + StoredSignatureCounter = signCount + }); } internal static void MakeEdDSA(out byte[] privateKeySeed, out byte[] publicKey, out byte[] expandedPrivateKey)