Skip to content

Commit 67eec54

Browse files
authored
[Draft] Add credProtect extension to Fido2.Models (#448)
1 parent c2f384d commit 67eec54

File tree

5 files changed

+89
-8
lines changed

5 files changed

+89
-8
lines changed

Src/Fido2.Models/Converters/FidoEnumConverter.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,26 @@ public sealed class FidoEnumConverter<[DynamicallyAccessedMembers(DynamicallyAcc
1010
{
1111
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1212
{
13-
string text = reader.GetString();
14-
15-
if (EnumNameMapper<T>.TryGetValue(reader.GetString(), out T value))
16-
{
17-
return value;
18-
}
19-
else
13+
switch (reader.TokenType)
2014
{
21-
throw new JsonException($"Invalid enum value = {text}");
15+
case JsonTokenType.String:
16+
string text = reader.GetString();
17+
if (EnumNameMapper<T>.TryGetValue(text, out T value))
18+
return value;
19+
else
20+
throw new JsonException($"Invalid enum value = \"{text}\"");
21+
22+
case JsonTokenType.Number:
23+
if (!reader.TryGetInt32(out var number))
24+
throw new JsonException($"Invalid enum value = {reader.GetString()}");
25+
var casted = (T)(object)number; // ints can always be casted to enum, even when the value is not defined
26+
if (Enum.IsDefined(casted))
27+
return casted;
28+
else
29+
throw new JsonException($"Invalid enum value = {number}");
30+
31+
default:
32+
throw new JsonException($"Invalid enum value ({reader.TokenType})");
2233
}
2334
}
2435

Src/Fido2.Models/Objects/AuthenticationExtensionsClientInputs.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,27 @@ public sealed class AuthenticationExtensionsClientInputs
6161
[JsonPropertyName("prf")]
6262
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
6363
public AuthenticationExtensionsPRFInputs? PRF { get; set; }
64+
65+
/// <summary>
66+
/// This registration extension allows relying parties to specify a credential protection policy when creating a credential.
67+
/// Additionally, authenticators MAY choose to establish a default credential protection policy greater than <c>UserVerificationOptional</c> (the lowest level)
68+
/// and unilaterally enforce such policy. Authenticators not supporting some form of user verification MUST NOT support this extension.
69+
/// Authenticators supporting some form of user verification MUST process this extension and persist the credProtect value with the credential,
70+
/// even if the authenticator is not protected by some form of user verification at the time.
71+
/// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-credProtect-extension
72+
/// </summary>
73+
[JsonPropertyName("credentialProtectionPolicy")]
74+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
75+
public CredentialProtectionPolicy? CredentialProtectionPolicy { get; set; }
76+
77+
/// <summary>
78+
/// This controls whether it is better to fail to create a credential rather than ignore the protection policy.
79+
/// When true, and <c>CredentialProtectionPolicy</c>'s value is
80+
/// either <c>UserVerificationOptionalWithCredentialIdList</c> or <c>UserVerificationRequired</c>, the platform
81+
/// SHOULD NOT create the credential in a way that does not implement the requested protection policy.
82+
/// </summary>
83+
[JsonPropertyName("enforceCredentialProtectionPolicy")]
84+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
85+
public bool? EnforceCredentialProtectionPolicy { get; set; }
6486
}
6587

Src/Fido2.Models/Objects/AuthenticationExtensionsClientOutputs.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,13 @@ public class AuthenticationExtensionsClientOutputs
5858
[JsonPropertyName("prf")]
5959
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
6060
public AuthenticationExtensionsPRFOutputs? PRF { get; set; }
61+
62+
63+
/// <summary>
64+
/// The <c>CredentialProtectionPolicy</c> stored alongside the created credential
65+
/// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-credProtect-extension
66+
/// </summary>
67+
[JsonPropertyName("credProtect")]
68+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
69+
public CredentialProtectionPolicy? CredProtect { get; set; }
6170
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Runtime.Serialization;
2+
using System.Text.Json.Serialization;
3+
4+
namespace Fido2NetLib.Objects;
5+
6+
/// <summary>
7+
/// CredentialProtectionPolicy
8+
/// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-credProtect-extension
9+
/// </summary>
10+
[JsonConverter(typeof(FidoEnumConverter<CredentialProtectionPolicy>))]
11+
public enum CredentialProtectionPolicy
12+
{
13+
/// <summary>
14+
/// This reflects "FIDO_2_0" semantics. In this configuration, performing some form of user verification is OPTIONAL with or without credentialID list.
15+
/// This is the default state of the credential if the extension is not specified
16+
/// </summary>
17+
[EnumMember(Value = "userVerificationOptional")]
18+
UserVerificationOptional = 0x01,
19+
20+
/// <summary>
21+
/// In this configuration, credential is discovered only when its credentialID is provided by the platform or when some form of user verification is performed.
22+
/// </summary>
23+
[EnumMember(Value = "userVerificationOptionalWithCredentialIDList")]
24+
UserVerificationOptionalWithCredentialIdList = 0x02,
25+
26+
/// <summary>
27+
/// TThis reflects that discovery and usage of the credential MUST be preceded by some form of user verification.
28+
/// </summary>
29+
[EnumMember(Value = "userVerificationRequired")]
30+
UserVerificationRequired = 0x03
31+
}

Test/Converters/FidoEnumConverterTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ public void CorrectlyFallsBackToMemberName()
2929
Assert.Equal(ABC.A, JsonSerializer.Deserialize<ABC>("\"a\""));
3030
}
3131

32+
[Fact]
33+
public void CorrectlyDeserializesNumericEnumValue()
34+
{
35+
Assert.Equal(CredentialProtectionPolicy.UserVerificationRequired, JsonSerializer.Deserialize<CredentialProtectionPolicy>($"{CredentialProtectionPolicy.UserVerificationRequired:d}"));
36+
Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<CredentialProtectionPolicy>($"99"));
37+
Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<CredentialProtectionPolicy>($"99.7"));
38+
}
39+
3240
[Fact]
3341
public void DeserializationIsCaseInsensitive()
3442
{

0 commit comments

Comments
 (0)