From d973582f1ae9432913b96511a858ca46618fd1e2 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Fri, 18 Feb 2022 16:43:13 +1100 Subject: [PATCH] feat: add resident key protocol option Adds the residentKey protocol option which is part of Webauthn Level 2. --- protocol/authenticator.go | 21 ++++++++++++++++++--- protocol/options.go | 5 +++++ webauthn/authenticator_test.go | 4 ++-- webauthn/registration.go | 13 +++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/protocol/authenticator.go b/protocol/authenticator.go index c054718..b196035 100644 --- a/protocol/authenticator.go +++ b/protocol/authenticator.go @@ -50,7 +50,7 @@ type AttestedCredentialData struct { CredentialPublicKey []byte `json:"public_key"` } -// AuthenticatorAttachment https://www.w3.org/TR/webauthn/#platform-attachment +// AuthenticatorAttachment https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-authenticatorattachment type AuthenticatorAttachment string const ( @@ -65,6 +65,21 @@ const ( CrossPlatform AuthenticatorAttachment = "cross-platform" ) +// ResidentKeyRequirement https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-residentkey +type ResidentKeyRequirement string + +const ( + // ResidentKeyRequirementDiscouraged indicates to the client we do not want a discoverable credential. This is the default. + ResidentKeyRequirementDiscouraged ResidentKeyRequirement = "discouraged" + + // ResidentKeyRequirementPreferred indicates to the client we would prefer a discoverable credential. + ResidentKeyRequirementPreferred ResidentKeyRequirement = "preferred" + + // ResidentKeyRequirementRequired indicates to the client we require a discoverable credential and that it should + // fail if the credential does not support this feature. + ResidentKeyRequirementRequired ResidentKeyRequirement = "required" +) + // Authenticators may implement various transports for communicating with clients. This enumeration defines // hints as to how clients might communicate with a particular authenticator in order to obtain an assertion // for a specific credential. Note that these hints represent the WebAuthn Relying Party's best belief as to @@ -237,8 +252,8 @@ func ResidentKeyRequired() *bool { return &required } -// ResidentKeyUnrequired - Do not require that the private key be resident to the client device. -func ResidentKeyUnrequired() *bool { +// ResidentKeyNotRequired - Do not require that the private key be resident to the client device. +func ResidentKeyNotRequired() *bool { required := false return &required } diff --git a/protocol/options.go b/protocol/options.go index 3b23762..ca70779 100644 --- a/protocol/options.go +++ b/protocol/options.go @@ -91,6 +91,11 @@ type AuthenticatorSelection struct { // credentials. If the parameter is set to true, the authenticator MUST create a client-side-resident // public key credential source when creating a public key credential. RequireResidentKey *bool `json:"requireResidentKey,omitempty"` + + // ResidentKey this member describes the Relying Party's requirements regarding resident + // credentials per Webauthn Level 2. + ResidentKey ResidentKeyRequirement `json:"residentKey,omitempty"` + // UserVerification This member describes the Relying Party's requirements regarding user verification for // the create() operation. Eligible authenticators are filtered to only those capable of satisfying this // requirement. diff --git a/webauthn/authenticator_test.go b/webauthn/authenticator_test.go index 643531c..1b2b7a2 100644 --- a/webauthn/authenticator_test.go +++ b/webauthn/authenticator_test.go @@ -127,12 +127,12 @@ func TestSelectAuthenticator(t *testing.T) { {"Generate Correct Authenticator Selection", args{ att: "platform", - rrk: p.ResidentKeyUnrequired(), + rrk: p.ResidentKeyNotRequired(), uv: "preferred", }, p.AuthenticatorSelection{ AuthenticatorAttachment: p.Platform, - RequireResidentKey: p.ResidentKeyUnrequired(), + RequireResidentKey: p.ResidentKeyNotRequired(), UserVerification: p.VerificationPreferred, }, }, diff --git a/webauthn/registration.go b/webauthn/registration.go index 4988d7e..74e2121 100644 --- a/webauthn/registration.go +++ b/webauthn/registration.go @@ -113,6 +113,19 @@ func WithAppIdExcludeExtension(appid string) RegistrationOption { } } +// WithResidentKeyRequirement sets both the resident key and require resident key protocol options. When +func WithResidentKeyRequirement(requirement protocol.ResidentKeyRequirement) RegistrationOption { + return func(cco *protocol.PublicKeyCredentialCreationOptions) { + cco.AuthenticatorSelection.ResidentKey = requirement + switch requirement { + case protocol.ResidentKeyRequirementRequired: + cco.AuthenticatorSelection.RequireResidentKey = protocol.ResidentKeyRequired() + default: + cco.AuthenticatorSelection.RequireResidentKey = protocol.ResidentKeyNotRequired() + } + } +} + // Take the response from the authenticator and client and verify the credential against the user's credentials and // session data. func (webauthn *WebAuthn) FinishRegistration(user User, session SessionData, response *http.Request) (*Credential, error) {