From 92e054df1540005bebaa471175ace4322fddf33a Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Sat, 6 Jul 2024 15:33:06 +0200 Subject: [PATCH 1/9] Implement PublicKeyCredentialHint for WebAuthn L3. --- Src/Fido2.Models/CredentialCreateOptions.cs | 24 ++++++++++++++ .../Objects/PublicKeyCredentialHint.cs | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index bc55d159..652fb741 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -55,6 +55,30 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase [JsonPropertyName("authenticatorSelection")] public AuthenticatorSelection AuthenticatorSelection { get; set; } + private IEnumerable _hints; + + /// + /// This OPTIONAL member contains zero or more elements from to guide the user agent in interacting with the user. Note that the elements have type DOMString despite being taken from that enumeration. + /// For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the authenticatorAttachment SHOULD be set to cross-platform. + /// + [JsonPropertyName("hints")] + public IEnumerable Hints + { + get + { + return _hints; + } + set + { + if (value != null) + { + AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); + AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; + } + _hints = value; + } + } + /// /// 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. /// diff --git a/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs b/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs new file mode 100644 index 00000000..d9f6d4f4 --- /dev/null +++ b/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs @@ -0,0 +1,33 @@ +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace Fido2NetLib.Objects; + +/// +/// WebAuthn Relying Parties may use this enumeration to communicate hints to the user-agent about how a request may be best completed. These hints are not requirements, and do not bind the user-agent, but may guide it in providing the best experience by using contextual information that the Relying Party has about the request. Hints are provided in order of decreasing preference so, if two hints are contradictory, the first one controls. Hints may also overlap: if a more-specific hint is defined a Relying Party may still wish to send less specific ones for user-agents that may not recognise the more specific one. In this case the most specific hint should be sent before the less-specific ones. +/// Hints MAY contradict information contained in credential transports and authenticatorAttachment. When this occurs, the hints take precedence. (Note that transports values are not provided when using discoverable credentials, leaving hints as the only avenue for expressing some aspects of such a request.) +/// +/// +/// https://www.w3.org/TR/webauthn-3/#enum-hints +/// +[JsonConverter(typeof(FidoEnumConverter))] +public enum PublicKeyCredentialHint +{ + /// + /// Indicates that the Relying Party believes that users will satisfy this request with a physical security key. For example, an enterprise Relying Party may set this hint if they have issued security keys to their employees and will only accept those authenticators for registration and authentication. + /// + [EnumMember(Value = "security-key")] + SecurityKey, + + /// + /// Indicates that the Relying Party believes that users will satisfy this request with a platform authenticator attached to the client device. + /// + [EnumMember(Value = "client-device")] + ClientDevice, + + /// + /// Indicates that the Relying Party believes that users will satisfy this request with general-purpose authenticators such as smartphones. For example, a consumer Relying Party may believe that only a small fraction of their customers possesses dedicated security keys. This option also implies that the local platform authenticator should not be promoted in the UI. + /// + [EnumMember(Value = "hybrid")] + Hybrid, +} From bbbe3dcc34dc9eccc580d2154a0f2e5155615939 Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Sun, 7 Jul 2024 14:46:31 +0200 Subject: [PATCH 2/9] Set `Hints` to `null` when empty array is passed. --- Src/Fido2.Models/CredentialCreateOptions.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index 652fb741..cd08b157 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -70,15 +70,16 @@ public IEnumerable Hints } set { - if (value != null) + if (value != null && value.Any()) { AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; + _hints = value; } - _hints = value; + _hints = null; } - } - + } + /// /// 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. /// From e0bbb20c3d1e4397639df523ca22209cf76edfe2 Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Mon, 8 Jul 2024 09:52:34 +0200 Subject: [PATCH 3/9] Format XML comment --- Src/Fido2.Models/CredentialCreateOptions.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index cd08b157..9d62a812 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -58,9 +58,11 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase private IEnumerable _hints; /// - /// This OPTIONAL member contains zero or more elements from to guide the user agent in interacting with the user. Note that the elements have type DOMString despite being taken from that enumeration. - /// For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the authenticatorAttachment SHOULD be set to cross-platform. + /// Guides the user agent in interacting with the user. This OPTIONAL member contains zero or more elements from . /// + /// + /// When is set, will be set to for compatibility with older user agents. + /// [JsonPropertyName("hints")] public IEnumerable Hints { From 8ab7b7fdca4a016cba115487c247e15473266fdb Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Mon, 8 Jul 2024 09:53:22 +0200 Subject: [PATCH 4/9] Ignore when writing null --- Src/Fido2.Models/CredentialCreateOptions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index 9d62a812..773309b0 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -64,6 +64,7 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase /// When is set, will be set to for compatibility with older user agents. /// [JsonPropertyName("hints")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IEnumerable Hints { get From 3796805c52ac3efef66fa5423c75b323f6f341eb Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Mon, 8 Jul 2024 09:55:07 +0200 Subject: [PATCH 5/9] remove link --- Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs b/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs index d9f6d4f4..9634174a 100644 --- a/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs +++ b/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs @@ -7,9 +7,6 @@ namespace Fido2NetLib.Objects; /// WebAuthn Relying Parties may use this enumeration to communicate hints to the user-agent about how a request may be best completed. These hints are not requirements, and do not bind the user-agent, but may guide it in providing the best experience by using contextual information that the Relying Party has about the request. Hints are provided in order of decreasing preference so, if two hints are contradictory, the first one controls. Hints may also overlap: if a more-specific hint is defined a Relying Party may still wish to send less specific ones for user-agents that may not recognise the more specific one. In this case the most specific hint should be sent before the less-specific ones. /// Hints MAY contradict information contained in credential transports and authenticatorAttachment. When this occurs, the hints take precedence. (Note that transports values are not provided when using discoverable credentials, leaving hints as the only avenue for expressing some aspects of such a request.) /// -/// -/// https://www.w3.org/TR/webauthn-3/#enum-hints -/// [JsonConverter(typeof(FidoEnumConverter))] public enum PublicKeyCredentialHint { From 805163c524fbc3fe5fa50f6fe5d40f75d218fc30 Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Mon, 8 Jul 2024 10:06:32 +0200 Subject: [PATCH 6/9] Needs to be list, order matters --- Src/Fido2.Models/CredentialCreateOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index 773309b0..aecc610b 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -55,7 +55,7 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase [JsonPropertyName("authenticatorSelection")] public AuthenticatorSelection AuthenticatorSelection { get; set; } - private IEnumerable _hints; + private List _hints; /// /// Guides the user agent in interacting with the user. This OPTIONAL member contains zero or more elements from . @@ -65,7 +65,7 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase /// [JsonPropertyName("hints")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IEnumerable Hints + public List Hints { get { From a894963647bcfbb2f24821bee81273022951590f Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Sat, 13 Jul 2024 07:59:20 +0200 Subject: [PATCH 7/9] Correct backwards compatibility options for PublicKeyCredentialHint --- Src/Fido2.Models/CredentialCreateOptions.cs | 28 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index aecc610b..5efdca56 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -61,7 +61,12 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase /// Guides the user agent in interacting with the user. This OPTIONAL member contains zero or more elements from . /// /// - /// When is set, will be set to for compatibility with older user agents. + /// When is set, will be set to one of the values in the table below: + /// + /// + /// + /// + /// /// [JsonPropertyName("hints")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -73,10 +78,25 @@ public List Hints } set { - if (value != null && value.Any()) + if (value != null) { - AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); - AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; + var firstHint = value.First(); + switch (firstHint) + { + case PublicKeyCredentialHint.SecurityKey: + case PublicKeyCredentialHint.Hybrid: + { + AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); + AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; + break; + } + case PublicKeyCredentialHint.ClientDevice: + { + AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); + AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.Platform; + break; + } + } _hints = value; } _hints = null; From ec3c3d08aa500519b308edae79f44dbd88349425 Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Sun, 14 Jul 2024 10:13:09 +0200 Subject: [PATCH 8/9] Add support for `hints` during authentication. --- Src/Fido2.Models/AssertionOptions.cs | 6 ++++ Src/Fido2.Models/CredentialCreateOptions.cs | 34 ++++++++++----------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Src/Fido2.Models/AssertionOptions.cs b/Src/Fido2.Models/AssertionOptions.cs index f273ed0f..f7978ff2 100644 --- a/Src/Fido2.Models/AssertionOptions.cs +++ b/Src/Fido2.Models/AssertionOptions.cs @@ -42,6 +42,12 @@ public class AssertionOptions : Fido2ResponseBase [JsonPropertyName("userVerification")] public UserVerificationRequirement? UserVerification { get; set; } + /// + /// This OPTIONAL member contains zero or more elements from to guide the user agent in interacting with the user. Note that the elements have type DOMString despite being taken from that enumeration. + /// + [JsonPropertyName("hints")] + public IReadOnlyList Hints { get; set; } = Array.Empty(); + /// /// This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator. For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension. /// diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index 5efdca56..d1a141b8 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -55,7 +55,7 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase [JsonPropertyName("authenticatorSelection")] public AuthenticatorSelection AuthenticatorSelection { get; set; } - private List _hints; + private IReadOnlyList _hints = Array.Empty(); /// /// Guides the user agent in interacting with the user. This OPTIONAL member contains zero or more elements from . @@ -70,7 +70,7 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase /// [JsonPropertyName("hints")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public List Hints + public IReadOnlyList Hints { get { @@ -78,28 +78,26 @@ public List Hints } set { - if (value != null) + if (value.Any()) { - var firstHint = value.First(); - switch (firstHint) + switch (value[0]) { case PublicKeyCredentialHint.SecurityKey: - case PublicKeyCredentialHint.Hybrid: - { - AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); - AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; - break; + case PublicKeyCredentialHint.Hybrid: + { + AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); + AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; + break; } - case PublicKeyCredentialHint.ClientDevice: - { - AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); - AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.Platform; - break; + case PublicKeyCredentialHint.ClientDevice: + { + AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); + AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.Platform; + break; } } - _hints = value; - } - _hints = null; + } + _hints = value; } } From 74970bc968193572d9b60efa66b2850bb840f8f0 Mon Sep 17 00:00:00 2001 From: Jonas Hendrickx Date: Mon, 15 Jul 2024 12:15:50 +0200 Subject: [PATCH 9/9] Correct --- Src/Fido2.Models/CredentialCreateOptions.cs | 24 +++++++-------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index d1a141b8..f792b5d1 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -80,23 +80,15 @@ public IReadOnlyList Hints { if (value.Any()) { - switch (value[0]) + AuthenticatorSelection ??= new AuthenticatorSelection(); + AuthenticatorSelection.AuthenticatorAttachment = value[0] switch { - case PublicKeyCredentialHint.SecurityKey: - case PublicKeyCredentialHint.Hybrid: - { - AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); - AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform; - break; - } - case PublicKeyCredentialHint.ClientDevice: - { - AuthenticatorSelection.AuthenticatorAttachment ??= new AuthenticatorAttachment(); - AuthenticatorSelection.AuthenticatorAttachment = AuthenticatorAttachment.Platform; - break; - } - } - } + PublicKeyCredentialHint.SecurityKey or PublicKeyCredentialHint.Hybrid => AuthenticatorAttachment + .CrossPlatform, + PublicKeyCredentialHint.ClientDevice => AuthenticatorAttachment.Platform, + _ => AuthenticatorSelection.AuthenticatorAttachment + }; + } _hints = value; } }