-
-
Notifications
You must be signed in to change notification settings - Fork 182
/
Copy pathFido2NetLib.cs
157 lines (141 loc) · 7.79 KB
/
Fido2NetLib.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Fido2NetLib.Objects;
namespace Fido2NetLib
{
/// <summary>
/// Public API for parsing and veriyfing FIDO2 attestation & assertion responses.
/// </summary>
public partial class Fido2 : IFido2
{
private readonly Fido2Configuration _config;
private readonly IMetadataService? _metadataService;
public Fido2(
Fido2Configuration config,
IMetadataService? metadataService = null)
{
_config = config;
_metadataService = metadataService;
}
/// <summary>
/// Returns CredentialCreateOptions including a challenge to be sent to the browser/authr to create new credentials
/// </summary>
/// <returns></returns>
/// <param name="excludeCredentials">Recommended. This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter.</param>
public CredentialCreateOptions RequestNewCredential(
Fido2User user,
List<PublicKeyCredentialDescriptor> excludeCredentials,
AuthenticationExtensionsClientInputs? extensions = null)
{
return RequestNewCredential(user, excludeCredentials, AuthenticatorSelection.Default, AttestationConveyancePreference.None, extensions);
}
/// <summary>
/// Returns CredentialCreateOptions including a challenge to be sent to the browser/authr to create new credentials
/// </summary>
/// <returns></returns>
/// <param name="attestationPreference">This member is intended for use by Relying Parties that wish to express their preference for attestation conveyance. The default is none.</param>
/// <param name="excludeCredentials">Recommended. This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter.</param>
public CredentialCreateOptions RequestNewCredential(
Fido2User user,
List<PublicKeyCredentialDescriptor> excludeCredentials,
AuthenticatorSelection authenticatorSelection,
AttestationConveyancePreference attestationPreference,
AuthenticationExtensionsClientInputs? extensions = null)
{
var challenge = new byte[_config.ChallengeSize];
RandomNumberGenerator.Fill(challenge);
var options = CredentialCreateOptions.Create(_config, challenge, user, authenticatorSelection, attestationPreference, excludeCredentials, extensions);
return options;
}
/// <summary>
/// Verifies the response from the browser/authr after creating new credentials
/// </summary>
/// <param name="attestationResponse"></param>
/// <param name="origChallenge"></param>
/// <param name="isCredentialIdUniqueToUser"></param>
/// <param name="requestTokenBindingId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<CredentialMakeResult> MakeNewCredentialAsync(
AuthenticatorAttestationRawResponse attestationResponse,
CredentialCreateOptions origChallenge,
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
byte[]? requestTokenBindingId = null,
CancellationToken cancellationToken = default)
{
var parsedResponse = AuthenticatorAttestationResponse.Parse(attestationResponse);
var success = await parsedResponse.VerifyAsync(origChallenge, _config, isCredentialIdUniqueToUser, _metadataService, requestTokenBindingId, cancellationToken);
// todo: Set Errormessage etc.
return new CredentialMakeResult(
status : "ok",
errorMessage : string.Empty,
result : success
);
}
/// <summary>
/// Returns AssertionOptions including a challenge to the browser/authr to assert existing credentials and authenticate a user.
/// </summary>
/// <returns></returns>
public AssertionOptions GetAssertionOptions(
IEnumerable<PublicKeyCredentialDescriptor> allowedCredentials,
UserVerificationRequirement? userVerification,
AuthenticationExtensionsClientInputs? extensions = null)
{
var challenge = new byte[_config.ChallengeSize];
RandomNumberGenerator.Fill(challenge);
var options = AssertionOptions.Create(_config, challenge, allowedCredentials, userVerification, extensions);
return options;
}
/// <summary>
/// Verifies the assertion response from the browser/authr to assert existing credentials and authenticate a user.
/// </summary>
/// <returns></returns>
public async Task<AssertionVerificationResult> MakeAssertionAsync(
AuthenticatorAssertionRawResponse assertionResponse,
AssertionOptions originalOptions,
byte[] storedPublicKey,
uint storedSignatureCounter,
IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredentialIdCallback,
byte[]? requestTokenBindingId = null,
CancellationToken cancellationToken = default)
{
var parsedResponse = AuthenticatorAssertionResponse.Parse(assertionResponse);
var result = await parsedResponse.VerifyAsync(originalOptions,
_config.FullyQualifiedOrigins,
storedPublicKey,
storedSignatureCounter,
isUserHandleOwnerOfCredentialIdCallback,
requestTokenBindingId,
cancellationToken);
return result;
}
/// <summary>
/// Result of parsing and verifying attestation. Used to transport Public Key back to RP
/// </summary>
public sealed class CredentialMakeResult : Fido2ResponseBase
{
public CredentialMakeResult(string status, string errorMessage, AttestationVerificationSuccess? result)
{
Status = status;
ErrorMessage = errorMessage;
Result = result;
}
public AttestationVerificationSuccess? Result { get; }
// todo: add debuginfo?
}
}
/// <summary>
/// Callback function used to validate that the CredentialID is unique to this User
/// </summary>
/// <param name="credentialIdUserParams"></param>
/// <returns></returns>
public delegate Task<bool> IsCredentialIdUniqueToUserAsyncDelegate(IsCredentialIdUniqueToUserParams credentialIdUserParams, CancellationToken cancellationToken);
/// <summary>
/// Callback function used to validate that the Userhandle is indeed owned of the CrendetialId
/// </summary>
/// <param name="credentialIdUserHandleParams"></param>
/// <returns></returns>
public delegate Task<bool> IsUserHandleOwnerOfCredentialIdAsync(IsUserHandleOwnerOfCredentialIdParams credentialIdUserHandleParams, CancellationToken cancellationToken);
}