From 1b8248dc0e255ab9b8e1226ed18547d4af4187e3 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Fri, 9 Feb 2024 05:34:36 +1100 Subject: [PATCH] feat: support hints and attestation formats This adds support to the hints and attestation format options, both of which are new elements from Level 3 which are effectively optional. This allows users who wish to leverage this option to do so with no negative effects for those who do not. --- protocol/options.go | 90 +++++++++++++++++++++++++++++++++------- webauthn/login.go | 16 +++++++ webauthn/registration.go | 26 +++++++++++- 3 files changed, 116 insertions(+), 16 deletions(-) diff --git a/protocol/options.go b/protocol/options.go index 80a9e55..f48577c 100644 --- a/protocol/options.go +++ b/protocol/options.go @@ -17,27 +17,24 @@ type CredentialAssertion struct { // In order to create a Credential via create(), the caller specifies a few parameters in a // PublicKeyCredentialCreationOptions object. // -// TODO: There is one field missing from this for WebAuthn Level 3. A string slice named 'attestationFormats'. -// // Specification: §5.4. Options for Credential Creation (https://www.w3.org/TR/webauthn/#dictionary-makecredentialoptions) type PublicKeyCredentialCreationOptions struct { - RelyingParty RelyingPartyEntity `json:"rp"` - User UserEntity `json:"user"` - Challenge URLEncodedBase64 `json:"challenge"` - Parameters []CredentialParameter `json:"pubKeyCredParams,omitempty"` - Timeout int `json:"timeout,omitempty"` - CredentialExcludeList []CredentialDescriptor `json:"excludeCredentials,omitempty"` - AuthenticatorSelection AuthenticatorSelection `json:"authenticatorSelection,omitempty"` - Attestation ConveyancePreference `json:"attestation,omitempty"` - Extensions AuthenticationExtensions `json:"extensions,omitempty"` + RelyingParty RelyingPartyEntity `json:"rp"` + User UserEntity `json:"user"` + Challenge URLEncodedBase64 `json:"challenge"` + Parameters []CredentialParameter `json:"pubKeyCredParams,omitempty"` + Timeout int `json:"timeout,omitempty"` + CredentialExcludeList []CredentialDescriptor `json:"excludeCredentials,omitempty"` + AuthenticatorSelection AuthenticatorSelection `json:"authenticatorSelection,omitempty"` + Hints []PublicKeyCredentialHint `json:"hints,omitempty"` + Attestation ConveyancePreference `json:"attestation,omitempty"` + AttestationFormats []AttestationFormat `json:"attestationFormats,omitempty"` + Extensions AuthenticationExtensions `json:"extensions,omitempty"` } // The PublicKeyCredentialRequestOptions dictionary supplies get() with the data it needs to generate an assertion. // Its challenge member MUST be present, while its other members are OPTIONAL. // -// TODO: There are two fields missing from this for WebAuthn Level 3. A string type named 'attestation', and a string -// slice named 'attestationFormats'. -// // Specification: §5.5. Options for Assertion Generation (https://www.w3.org/TR/webauthn/#dictionary-assertion-options) type PublicKeyCredentialRequestOptions struct { Challenge URLEncodedBase64 `json:"challenge"` @@ -45,6 +42,8 @@ type PublicKeyCredentialRequestOptions struct { RelyingPartyID string `json:"rpId,omitempty"` AllowedCredentials []CredentialDescriptor `json:"allowCredentials,omitempty"` UserVerification UserVerificationRequirement `json:"userVerification,omitempty"` + Attestation ConveyancePreference `json:"attestation,omitempty"` + AttestationFormats []AttestationFormat `json:"attestationFormats,omitempty"` Extensions AuthenticationExtensions `json:"extensions,omitempty"` } @@ -126,6 +125,69 @@ type AuthenticatorSelection struct { UserVerification UserVerificationRequirement `json:"userVerification,omitempty"` } +// PublicKeyCredentialHint is a type representing the enum PublicKeyCredentialHints from +// https://www.w3.org/TR/webauthn-3/#enum-hints. +type PublicKeyCredentialHint string + +const ( + // PublicKeyCredentialHintSecurityKey is a PublicKeyCredentialHint that 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. + // + // For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the + // authenticatorAttachment SHOULD be set to cross-platform. + PublicKeyCredentialHintSecurityKey PublicKeyCredentialHint = "security-key" + + // PublicKeyCredentialHintClientDevice is a PublicKeyCredentialHint that indicates that the Relying Party believes + // that users will satisfy this request with a platform authenticator attached to the client device. + // + // For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the + // authenticatorAttachment SHOULD be set to platform. + PublicKeyCredentialHintClientDevice PublicKeyCredentialHint = "client-device" + + // PublicKeyCredentialHintHybrid is a PublicKeyCredentialHint that 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. + // + // For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the + // authenticatorAttachment SHOULD be set to cross-platform. + PublicKeyCredentialHintHybrid PublicKeyCredentialHint = "hybrid" +) + +type AttestationFormat string + +const ( + // AttestationFormatPacked is the "packed" attestation statement format is a WebAuthn-optimized format for + // attestation. It uses a very compact but still extensible encoding method. This format is implementable by + //authenticators with limited resources (e.g., secure elements). + AttestationFormatPacked AttestationFormat = "packed" + + // AttestationFormatTPM is the TPM attestation statement format returns an attestation statement in the same format + // as the packed attestation statement format, although the rawData and signature fields are computed differently. + AttestationFormatTPM AttestationFormat = "tpm" + + // AttestationFormatAndroidKey is the attestation statement format for platform authenticators on versions "N", and + // later, which may provide this proprietary "hardware attestation" statement. + AttestationFormatAndroidKey AttestationFormat = "android-key" + + // AttestationFormatAndroidSafetyNet is the attestation statement format that Android-based platform authenticators + // MAY produce an attestation statement based on the Android SafetyNet API. + AttestationFormatAndroidSafetyNet AttestationFormat = "android-safetynet" + + // AttestationFormatFIDOU2F is the attestation statement format that is used with FIDO U2F authenticators. + AttestationFormatFIDOU2F AttestationFormat = "fido-u2f" + + // AttestationFormatApple is the attestation statement format that is used with Apple devices' platform + // authenticators. + AttestationFormatApple AttestationFormat = "apple" + + // AttestationFormatNone is the attestation statement format that is used to replace any authenticator-provided + // attestation statement when a WebAuthn Relying Party indicates it does not wish to receive attestation information. + AttestationFormatNone AttestationFormat = "none" +) + // ConveyancePreference is the type representing the AttestationConveyancePreference IDL. // // WebAuthn Relying Parties may use AttestationConveyancePreference to specify their preference regarding attestation diff --git a/webauthn/login.go b/webauthn/login.go index 73e69af..ca981d5 100644 --- a/webauthn/login.go +++ b/webauthn/login.go @@ -115,6 +115,22 @@ func WithUserVerification(userVerification protocol.UserVerificationRequirement) } } +// WithLoginConveyancePreference adjusts the non-default parameters regarding whether the authenticator should attest to the +// credential. +func WithLoginConveyancePreference(preference protocol.ConveyancePreference) LoginOption { + return func(cco *protocol.PublicKeyCredentialRequestOptions) { + cco.Attestation = preference + } +} + +// WithLoginAttestationFormats adjusts the preferred attestation formats for this credential request in most to least +// preferable. Advisory only. +func WithLoginAttestationFormats(formats ...protocol.AttestationFormat) LoginOption { + return func(cco *protocol.PublicKeyCredentialRequestOptions) { + cco.AttestationFormats = formats + } +} + // WithAssertionExtensions adjusts the requested extensions. func WithAssertionExtensions(extensions protocol.AuthenticationExtensions) LoginOption { return func(cco *protocol.PublicKeyCredentialRequestOptions) { diff --git a/webauthn/registration.go b/webauthn/registration.go index 9715246..cb9d234 100644 --- a/webauthn/registration.go +++ b/webauthn/registration.go @@ -101,6 +101,12 @@ func WithAuthenticatorSelection(authenticatorSelection protocol.AuthenticatorSel } } +func WithHints(hints ...protocol.PublicKeyCredentialHint) RegistrationOption { + return func(cco *protocol.PublicKeyCredentialCreationOptions) { + cco.Hints = hints + } +} + // WithExclusions adjusts the non-default parameters regarding credentials to exclude from registration. func WithExclusions(excludeList []protocol.CredentialDescriptor) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) { @@ -108,14 +114,30 @@ func WithExclusions(excludeList []protocol.CredentialDescriptor) RegistrationOpt } } -// WithConveyancePreference adjusts the non-default parameters regarding whether the authenticator should attest to the -// credential. +// WithConveyancePreference is a direct alias for WithRegistrationConveyancePreference. +// +// Deprecated: Use WithRegistrationConveyancePreference in favor of WithConveyancePreference as this function will be +// likely be removed in a future release. func WithConveyancePreference(preference protocol.ConveyancePreference) RegistrationOption { + return WithRegistrationConveyancePreference(preference) +} + +// WithRegistrationConveyancePreference adjusts the non-default parameters regarding whether the authenticator should attest to the +// credential. +func WithRegistrationConveyancePreference(preference protocol.ConveyancePreference) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) { cco.Attestation = preference } } +// WithRegistrationAttestationFormats adjusts the preferred attestation formats for this credential creation in most to +// least preferable. Advisory only. +func WithRegistrationAttestationFormats(formats ...protocol.AttestationFormat) RegistrationOption { + return func(cco *protocol.PublicKeyCredentialCreationOptions) { + cco.AttestationFormats = formats + } +} + // WithExtensions adjusts the extension parameter in the registration options. func WithExtensions(extension protocol.AuthenticationExtensions) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) {