-
-
Notifications
You must be signed in to change notification settings - Fork 182
/
Copy pathFido2NetLib.cs
148 lines (131 loc) · 7.17 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
using System.Collections.Generic;
using System.Security.Cryptography;
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 RandomNumberGenerator _crypto;
private readonly IMetadataService _metadataService;
public Fido2(
Fido2Configuration config,
IMetadataService metadataService = null)
{
_config = config;
_crypto = RandomNumberGenerator.Create();
_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];
_crypto.GetBytes(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>
/// <returns></returns>
public async Task<CredentialMakeResult> MakeNewCredentialAsync(
AuthenticatorAttestationRawResponse attestationResponse,
CredentialCreateOptions origChallenge,
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
byte[] requestTokenBindingId = null)
{
var parsedResponse = AuthenticatorAttestationResponse.Parse(attestationResponse);
var success = await parsedResponse.VerifyAsync(origChallenge, _config, isCredentialIdUniqueToUser, _metadataService, requestTokenBindingId);
// 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];
_crypto.GetBytes(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)
{
var parsedResponse = AuthenticatorAssertionResponse.Parse(assertionResponse);
var result = await parsedResponse.VerifyAsync(originalOptions,
_config.Origin,
storedPublicKey,
storedSignatureCounter,
isUserHandleOwnerOfCredentialIdCallback,
requestTokenBindingId);
return result;
}
/// <summary>
/// Result of parsing and verifying attestation. Used to transport Public Key back to RP
/// </summary>
public class CredentialMakeResult : Fido2ResponseBase
{
public AttestationVerificationSuccess Result { get; internal set; }
// 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);
/// <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);
}