You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

registration.go 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package webauthn
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "net/http"
  6. "github.com/duo-labs/webauthn/protocol"
  7. "github.com/duo-labs/webauthn/protocol/webauthncose"
  8. )
  9. // BEGIN REGISTRATION
  10. // These objects help us creat the CredentialCreationOptions
  11. // that will be passed to the authenticator via the user client
  12. type RegistrationOption func(*protocol.PublicKeyCredentialCreationOptions)
  13. // Generate a new set of registration data to be sent to the client and authenticator.
  14. func (webauthn *WebAuthn) BeginRegistration(user User, opts ...RegistrationOption) (*protocol.CredentialCreation, *SessionData, error) {
  15. challenge, err := protocol.CreateChallenge()
  16. if err != nil {
  17. return nil, nil, err
  18. }
  19. webAuthnUser := protocol.UserEntity{
  20. ID: user.WebAuthnID(),
  21. DisplayName: user.WebAuthnDisplayName(),
  22. CredentialEntity: protocol.CredentialEntity{
  23. Name: user.WebAuthnName(),
  24. Icon: user.WebAuthnIcon(),
  25. },
  26. }
  27. relyingParty := protocol.RelyingPartyEntity{
  28. ID: webauthn.Config.RPID,
  29. CredentialEntity: protocol.CredentialEntity{
  30. Name: webauthn.Config.RPDisplayName,
  31. Icon: webauthn.Config.RPIcon,
  32. },
  33. }
  34. credentialParams := defaultRegistrationCredentialParameters()
  35. creationOptions := protocol.PublicKeyCredentialCreationOptions{
  36. Challenge: challenge,
  37. RelyingParty: relyingParty,
  38. User: webAuthnUser,
  39. Parameters: credentialParams,
  40. AuthenticatorSelection: webauthn.Config.AuthenticatorSelection,
  41. Timeout: webauthn.Config.Timeout,
  42. Attestation: webauthn.Config.AttestationPreference,
  43. }
  44. for _, setter := range opts {
  45. setter(&creationOptions)
  46. }
  47. response := protocol.CredentialCreation{Response: creationOptions}
  48. newSessionData := SessionData{
  49. Challenge: base64.RawURLEncoding.EncodeToString(challenge),
  50. UserID: user.WebAuthnID(),
  51. UserVerification: creationOptions.AuthenticatorSelection.UserVerification,
  52. }
  53. if err != nil {
  54. return nil, nil, protocol.ErrParsingData.WithDetails("Error packing session data")
  55. }
  56. return &response, &newSessionData, nil
  57. }
  58. // Provide non-default parameters regarding the authenticator to select.
  59. func WithAuthenticatorSelection(authenticatorSelection protocol.AuthenticatorSelection) RegistrationOption {
  60. return func(cco *protocol.PublicKeyCredentialCreationOptions) {
  61. cco.AuthenticatorSelection = authenticatorSelection
  62. }
  63. }
  64. // Provide non-default parameters regarding credentials to exclude from retrieval.
  65. func WithExclusions(excludeList []protocol.CredentialDescriptor) RegistrationOption {
  66. return func(cco *protocol.PublicKeyCredentialCreationOptions) {
  67. cco.CredentialExcludeList = excludeList
  68. }
  69. }
  70. // Provide non-default parameters regarding whether the authenticator should attest to the credential.
  71. func WithConveyancePreference(preference protocol.ConveyancePreference) RegistrationOption {
  72. return func(cco *protocol.PublicKeyCredentialCreationOptions) {
  73. cco.Attestation = preference
  74. }
  75. }
  76. // Provide extension parameter to registration options
  77. func WithExtensions(extension protocol.AuthenticationExtensions) RegistrationOption {
  78. return func(cco *protocol.PublicKeyCredentialCreationOptions) {
  79. cco.Extensions = extension
  80. }
  81. }
  82. // Take the response from the authenticator and client and verify the credential against the user's credentials and
  83. // session data.
  84. func (webauthn *WebAuthn) FinishRegistration(user User, session SessionData, response *http.Request) (*Credential, error) {
  85. parsedResponse, err := protocol.ParseCredentialCreationResponse(response)
  86. if err != nil {
  87. return nil, err
  88. }
  89. return webauthn.CreateCredential(user, session, parsedResponse)
  90. }
  91. // CreateCredential verifies a parsed response against the user's credentials and session data.
  92. func (webauthn *WebAuthn) CreateCredential(user User, session SessionData, parsedResponse *protocol.ParsedCredentialCreationData) (*Credential, error) {
  93. if !bytes.Equal(user.WebAuthnID(), session.UserID) {
  94. return nil, protocol.ErrBadRequest.WithDetails("ID mismatch for User and Session")
  95. }
  96. shouldVerifyUser := session.UserVerification == protocol.VerificationRequired
  97. invalidErr := parsedResponse.Verify(session.Challenge, shouldVerifyUser, webauthn.Config.RPID, webauthn.Config.RPOrigin)
  98. if invalidErr != nil {
  99. return nil, invalidErr
  100. }
  101. return MakeNewCredential(parsedResponse)
  102. }
  103. func defaultRegistrationCredentialParameters() []protocol.CredentialParameter {
  104. return []protocol.CredentialParameter{
  105. protocol.CredentialParameter{
  106. Type: protocol.PublicKeyCredentialType,
  107. Algorithm: webauthncose.AlgES256,
  108. },
  109. protocol.CredentialParameter{
  110. Type: protocol.PublicKeyCredentialType,
  111. Algorithm: webauthncose.AlgES384,
  112. },
  113. protocol.CredentialParameter{
  114. Type: protocol.PublicKeyCredentialType,
  115. Algorithm: webauthncose.AlgES512,
  116. },
  117. protocol.CredentialParameter{
  118. Type: protocol.PublicKeyCredentialType,
  119. Algorithm: webauthncose.AlgRS256,
  120. },
  121. protocol.CredentialParameter{
  122. Type: protocol.PublicKeyCredentialType,
  123. Algorithm: webauthncose.AlgRS384,
  124. },
  125. protocol.CredentialParameter{
  126. Type: protocol.PublicKeyCredentialType,
  127. Algorithm: webauthncose.AlgRS512,
  128. },
  129. protocol.CredentialParameter{
  130. Type: protocol.PublicKeyCredentialType,
  131. Algorithm: webauthncose.AlgPS256,
  132. },
  133. protocol.CredentialParameter{
  134. Type: protocol.PublicKeyCredentialType,
  135. Algorithm: webauthncose.AlgPS384,
  136. },
  137. protocol.CredentialParameter{
  138. Type: protocol.PublicKeyCredentialType,
  139. Algorithm: webauthncose.AlgPS512,
  140. },
  141. protocol.CredentialParameter{
  142. Type: protocol.PublicKeyCredentialType,
  143. Algorithm: webauthncose.AlgEdDSA,
  144. },
  145. }
  146. }