gitea/vendor/github.com/duo-labs/webauthn/webauthn/registration.go

171 lines
5.6 KiB
Go

package webauthn
import (
"bytes"
"encoding/base64"
"net/http"
"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/protocol/webauthncose"
)
// BEGIN REGISTRATION
// These objects help us creat the CredentialCreationOptions
// that will be passed to the authenticator via the user client
type RegistrationOption func(*protocol.PublicKeyCredentialCreationOptions)
// Generate a new set of registration data to be sent to the client and authenticator.
func (webauthn *WebAuthn) BeginRegistration(user User, opts ...RegistrationOption) (*protocol.CredentialCreation, *SessionData, error) {
challenge, err := protocol.CreateChallenge()
if err != nil {
return nil, nil, err
}
webAuthnUser := protocol.UserEntity{
ID: user.WebAuthnID(),
DisplayName: user.WebAuthnDisplayName(),
CredentialEntity: protocol.CredentialEntity{
Name: user.WebAuthnName(),
Icon: user.WebAuthnIcon(),
},
}
relyingParty := protocol.RelyingPartyEntity{
ID: webauthn.Config.RPID,
CredentialEntity: protocol.CredentialEntity{
Name: webauthn.Config.RPDisplayName,
Icon: webauthn.Config.RPIcon,
},
}
credentialParams := defaultRegistrationCredentialParameters()
creationOptions := protocol.PublicKeyCredentialCreationOptions{
Challenge: challenge,
RelyingParty: relyingParty,
User: webAuthnUser,
Parameters: credentialParams,
AuthenticatorSelection: webauthn.Config.AuthenticatorSelection,
Timeout: webauthn.Config.Timeout,
Attestation: webauthn.Config.AttestationPreference,
}
for _, setter := range opts {
setter(&creationOptions)
}
response := protocol.CredentialCreation{Response: creationOptions}
newSessionData := SessionData{
Challenge: base64.RawURLEncoding.EncodeToString(challenge),
UserID: user.WebAuthnID(),
UserVerification: creationOptions.AuthenticatorSelection.UserVerification,
}
if err != nil {
return nil, nil, protocol.ErrParsingData.WithDetails("Error packing session data")
}
return &response, &newSessionData, nil
}
// Provide non-default parameters regarding the authenticator to select.
func WithAuthenticatorSelection(authenticatorSelection protocol.AuthenticatorSelection) RegistrationOption {
return func(cco *protocol.PublicKeyCredentialCreationOptions) {
cco.AuthenticatorSelection = authenticatorSelection
}
}
// Provide non-default parameters regarding credentials to exclude from retrieval.
func WithExclusions(excludeList []protocol.CredentialDescriptor) RegistrationOption {
return func(cco *protocol.PublicKeyCredentialCreationOptions) {
cco.CredentialExcludeList = excludeList
}
}
// Provide non-default parameters regarding whether the authenticator should attest to the credential.
func WithConveyancePreference(preference protocol.ConveyancePreference) RegistrationOption {
return func(cco *protocol.PublicKeyCredentialCreationOptions) {
cco.Attestation = preference
}
}
// Provide extension parameter to registration options
func WithExtensions(extension protocol.AuthenticationExtensions) RegistrationOption {
return func(cco *protocol.PublicKeyCredentialCreationOptions) {
cco.Extensions = extension
}
}
// 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) {
parsedResponse, err := protocol.ParseCredentialCreationResponse(response)
if err != nil {
return nil, err
}
return webauthn.CreateCredential(user, session, parsedResponse)
}
// CreateCredential verifies a parsed response against the user's credentials and session data.
func (webauthn *WebAuthn) CreateCredential(user User, session SessionData, parsedResponse *protocol.ParsedCredentialCreationData) (*Credential, error) {
if !bytes.Equal(user.WebAuthnID(), session.UserID) {
return nil, protocol.ErrBadRequest.WithDetails("ID mismatch for User and Session")
}
shouldVerifyUser := session.UserVerification == protocol.VerificationRequired
invalidErr := parsedResponse.Verify(session.Challenge, shouldVerifyUser, webauthn.Config.RPID, webauthn.Config.RPOrigin)
if invalidErr != nil {
return nil, invalidErr
}
return MakeNewCredential(parsedResponse)
}
func defaultRegistrationCredentialParameters() []protocol.CredentialParameter {
return []protocol.CredentialParameter{
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgES256,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgES384,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgES512,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgRS256,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgRS384,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgRS512,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgPS256,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgPS384,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgPS512,
},
protocol.CredentialParameter{
Type: protocol.PublicKeyCredentialType,
Algorithm: webauthncose.AlgEdDSA,
},
}
}