From 437070dfa457d76e39ef708051e26fa40e1732dc Mon Sep 17 00:00:00 2001 From: renovate <renovate-bot@autistici.org> Date: Tue, 18 Apr 2023 10:36:39 +0000 Subject: [PATCH] Update github.com/duo-labs/webauthn digest to ebaf9b7 --- go.mod | 2 +- go.sum | 2 + .../webauthn/protocol/attestation_tpm.go | 35 +++++++----- .../duo-labs/webauthn/protocol/credential.go | 2 +- .../webauthn/protocol/webauthncose/ed25519.go | 2 +- .../protocol/webauthncose/ed25519_go112.go | 2 +- .../protocol/webauthncose/webauthncose.go | 40 +++++++++++++- .../duo-labs/webauthn/webauthn/login.go | 53 +++++++++++++++---- vendor/modules.txt | 2 +- 9 files changed, 111 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index f5438c2c..416fdd63 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/bradfitz/gomemcache v0.0.0-20230124162541-5f7a7d875746 github.com/cenkalti/backoff/v4 v4.1.3 github.com/coreos/go-systemd/v22 v22.5.0 - github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 + github.com/duo-labs/webauthn v0.0.0-20221205164246-ebaf9b74c6ec github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect github.com/go-ldap/ldap/v3 v3.4.4 github.com/go-sql-driver/mysql v1.7.0 diff --git a/go.sum b/go.sum index 50ea4681..83420bed 100644 --- a/go.sum +++ b/go.sum @@ -244,6 +244,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 h1:jaQHuGKk9NVcfu9VbA7ygslr/7utxdYs47i4osBhZP8= github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499/go.mod h1:UMk1JMDgQDcdI2vQz+WJOIUTSjIq07qSepAVgc93rUc= +github.com/duo-labs/webauthn v0.0.0-20221205164246-ebaf9b74c6ec h1:darQ1FPPrwlzwmuN3fRMVCrsaCpuDqkKHADYzcMa73M= +github.com/duo-labs/webauthn v0.0.0-20221205164246-ebaf9b74c6ec/go.mod h1:V3q8IgNpNqFio+56G0vy/QZIi7iho65UFrDwdF5OtZA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= diff --git a/vendor/github.com/duo-labs/webauthn/protocol/attestation_tpm.go b/vendor/github.com/duo-labs/webauthn/protocol/attestation_tpm.go index 7cf578b3..5ee3ec5e 100644 --- a/vendor/github.com/duo-labs/webauthn/protocol/attestation_tpm.go +++ b/vendor/github.com/duo-labs/webauthn/protocol/attestation_tpm.go @@ -79,19 +79,20 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in } key, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey) - switch key.(type) { + if err != nil { + return tpmAttestationKey, nil, err + } + switch key := key.(type) { case webauthncose.EC2PublicKeyData: - e := key.(webauthncose.EC2PublicKeyData) - if pubArea.ECCParameters.CurveID != googletpm.EllipticCurve(e.Curve) || - 0 != pubArea.ECCParameters.Point.X.Cmp(new(big.Int).SetBytes(e.XCoord)) || - 0 != pubArea.ECCParameters.Point.Y.Cmp(new(big.Int).SetBytes(e.YCoord)) { + if pubArea.ECCParameters.CurveID != key.TPMCurveID() || + pubArea.ECCParameters.Point.X.Cmp(new(big.Int).SetBytes(key.XCoord)) != 0 || + pubArea.ECCParameters.Point.Y.Cmp(new(big.Int).SetBytes(key.YCoord)) != 0 { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Mismatch between ECCParameters in pubArea and credentialPublicKey") } case webauthncose.RSAPublicKeyData: - r := key.(webauthncose.RSAPublicKeyData) - mod := new(big.Int).SetBytes(r.Modulus) - exp := uint32(r.Exponent[0]) + uint32(r.Exponent[1])<<8 + uint32(r.Exponent[2])<<16 - if 0 != pubArea.RSAParameters.Modulus.Cmp(mod) || + mod := new(big.Int).SetBytes(key.Modulus) + exp := uint32(key.Exponent[0]) + uint32(key.Exponent[1])<<8 + uint32(key.Exponent[2])<<16 + if pubArea.RSAParameters.Modulus.Cmp(mod) != 0 || pubArea.RSAParameters.Exponent != exp { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Mismatch between RSAParameters in pubArea and credentialPublicKey") } @@ -104,6 +105,9 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in // Validate that certInfo is valid: certInfo, err := googletpm.DecodeAttestationData(certInfoBytes) + if err != nil { + return tpmAttestationKey, nil, err + } // 1/4 Verify that magic is set to TPM_GENERATED_VALUE. if certInfo.Magic != 0xff544347 { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Magic is not set to TPM_GENERATED_VALUE") @@ -116,7 +120,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in f := webauthncose.HasherFromCOSEAlg(coseAlg) h := f() h.Write(attToBeSigned) - if 0 != bytes.Compare(certInfo.ExtraData, h.Sum(nil)) { + if !bytes.Equal(certInfo.ExtraData, h.Sum(nil)) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("ExtraData is not set to hash of attToBeSigned") } // 4/4 Verify that attested contains a TPMS_CERTIFY_INFO structure as specified in @@ -126,7 +130,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in f, err = certInfo.AttestedCertifyInfo.Name.Digest.Alg.HashConstructor() h = f() h.Write(pubAreaBytes) - if 0 != bytes.Compare(h.Sum(nil), certInfo.AttestedCertifyInfo.Name.Digest.Value) { + if !bytes.Equal(h.Sum(nil), certInfo.AttestedCertifyInfo.Name.Digest.Value) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Hash value mismatch attested and pubArea") } @@ -170,6 +174,9 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in for _, ext := range aikCert.Extensions { if ext.Id.Equal([]int{2, 5, 29, 17}) { manufacturer, model, version, err = parseSANExtension(ext.Value) + if err != nil { + return tpmAttestationKey, nil, err + } } } @@ -177,7 +184,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Invalid SAN data in AIK certificate") } - if false == isValidTPMManufacturer(manufacturer) { + if !isValidTPMManufacturer(manufacturer) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Invalid TPM manufacturer") } @@ -193,7 +200,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in ekuValid = true } } - if false == ekuValid { + if !ekuValid { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate missing EKU") } @@ -212,7 +219,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in } } } - if constraints.IsCA != false { + if constraints.IsCA { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints missing or CA is true") } // 6/6 An Authority Information Access (AIA) extension with entry id-ad-ocsp and a CRL Distribution Point diff --git a/vendor/github.com/duo-labs/webauthn/protocol/credential.go b/vendor/github.com/duo-labs/webauthn/protocol/credential.go index a43369cb..f1426bfc 100644 --- a/vendor/github.com/duo-labs/webauthn/protocol/credential.go +++ b/vendor/github.com/duo-labs/webauthn/protocol/credential.go @@ -85,7 +85,7 @@ func ParseCredentialCreationResponseBody(body io.Reader) (*ParsedCredentialCreat } var pcc ParsedCredentialCreationData - pcc.ID, pcc.RawID, pcc.Type = ccr.ID, ccr.RawID, ccr.Type + pcc.ID, pcc.RawID, pcc.Type, pcc.ClientExtensionResults = ccr.ID, ccr.RawID, ccr.Type, ccr.ClientExtensionResults pcc.Raw = ccr parsedAttestationResponse, err := ccr.AttestationResponse.Parse() diff --git a/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519.go b/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519.go index 73ebc870..b3dc1f83 100644 --- a/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519.go +++ b/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519.go @@ -1,4 +1,4 @@ -// +build go1.13 +//go:build go1.13 package webauthncose diff --git a/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519_go112.go b/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519_go112.go index f1ae39d7..7dc8c538 100644 --- a/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519_go112.go +++ b/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/ed25519_go112.go @@ -1,4 +1,4 @@ -// +build !go1.13 +//go:build !go1.13 package webauthncose diff --git a/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/webauthncose.go b/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/webauthncose.go index 325f903c..8d568d50 100644 --- a/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/webauthncose.go +++ b/vendor/github.com/duo-labs/webauthn/protocol/webauthncose/webauthncose.go @@ -14,6 +14,7 @@ import ( "golang.org/x/crypto/ed25519" + "github.com/duo-labs/webauthn/protocol/googletpm" "github.com/duo-labs/webauthn/protocol/webauthncbor" ) @@ -198,7 +199,8 @@ func ParseFIDOPublicKey(keyBytes []byte) (EC2PublicKeyData, error) { // COSEAlgorithmIdentifier From §5.10.5. A number identifying a cryptographic algorithm. The algorithm // identifiers SHOULD be values registered in the IANA COSE Algorithms registry // [https://www.w3.org/TR/webauthn/#biblio-iana-cose-algs-reg], for instance, -7 for "ES256" -// and -257 for "RS256". +// +// and -257 for "RS256". type COSEAlgorithmIdentifier int const ( @@ -238,6 +240,42 @@ const ( RSAKey COSEKeyType = 3 ) +// The COSE Elliptic Curves +// https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves +type COSEEllipticCurve int + +const ( + // EC2 NIST P-256 also known as secp256r1 + P256 COSEEllipticCurve = 1 + // EC2 NIST P-384 also known as secp384r1 + P384 COSEEllipticCurve = 2 + // EC2 NIST P-521 also known as secp521r1 + P521 COSEEllipticCurve = 3 + // OKP X25519 for use w/ ECDH only + X25519 COSEEllipticCurve = 4 + // OKP X448 for use w/ ECDH only + X448 COSEEllipticCurve = 5 + // OKP Ed25519 for use w/ EdDSA only + Ed25519 COSEEllipticCurve = 6 + // OKP Ed448 for use w/ EdDSA only + Ed448 COSEEllipticCurve = 7 + // EC2 SECG secp256k1 curve + secp256k1 COSEEllipticCurve = 8 +) + +func (k *EC2PublicKeyData) TPMCurveID() googletpm.EllipticCurve { + switch COSEEllipticCurve(k.Curve) { + case P256: + return googletpm.CurveNISTP256 // TPM_ECC_NIST_P256 + case P384: + return googletpm.CurveNISTP384 // TPM_ECC_NIST_P384 + case P521: + return googletpm.CurveNISTP521 // TPM_ECC_NIST_P521 + default: + return googletpm.EllipticCurve(0) // TPM_ECC_NONE + } +} + func VerifySignature(key interface{}, data []byte, sig []byte) (bool, error) { switch key.(type) { diff --git a/vendor/github.com/duo-labs/webauthn/webauthn/login.go b/vendor/github.com/duo-labs/webauthn/webauthn/login.go index 4ce3a88d..fdb923f3 100644 --- a/vendor/github.com/duo-labs/webauthn/webauthn/login.go +++ b/vendor/github.com/duo-labs/webauthn/webauthn/login.go @@ -15,6 +15,9 @@ import ( // LoginOption is used to provide parameters that modify the default Credential Assertion Payload that is sent to the user. type LoginOption func(*protocol.PublicKeyCredentialRequestOptions) +// DiscoverableUserHandler returns a *User given the provided userHandle. +type DiscoverableUserHandler func(rawID, userHandle []byte) (user User, err error) + // Creates the CredentialAssertion data payload that should be sent to the user agent for beginning the // login/assertion process. The format of this data can be seen in §5.5 of the WebAuthn specification // (https://www.w3.org/TR/webauthn/#assertion-options). These default values can be amended by providing @@ -22,14 +25,9 @@ type LoginOption func(*protocol.PublicKeyCredentialRequestOptions) // RP in a secure manner and then provided to the FinishLogin function. This data helps us verify the // ownership of the credential being retreived. func (webauthn *WebAuthn) BeginLogin(user User, opts ...LoginOption) (*protocol.CredentialAssertion, *SessionData, error) { - challenge, err := protocol.CreateChallenge() - if err != nil { - return nil, nil, err - } - credentials := user.WebAuthnCredentials() - if len(credentials) == 0 { // If the user does not have any credentials, we cannot do login + if len(credentials) == 0 { // If the user does not have any credentials, we cannot perform an assertion. return nil, nil, protocol.ErrBadRequest.WithDetails("Found no credentials for user") } @@ -42,6 +40,20 @@ func (webauthn *WebAuthn) BeginLogin(user User, opts ...LoginOption) (*protocol. allowedCredentials[i] = credentialDescriptor } + return webauthn.beginLogin(user.WebAuthnID(), allowedCredentials, opts...) +} + +// BeginDiscoverableLogin begins a client-side discoverable login, previously known as Resident Key logins. +func (webauthn *WebAuthn) BeginDiscoverableLogin(opts ...LoginOption) (*protocol.CredentialAssertion, *SessionData, error) { + return webauthn.beginLogin(nil, nil, opts...) +} + +func (webauthn *WebAuthn) beginLogin(userID []byte, allowedCredentials []protocol.CredentialDescriptor, opts ...LoginOption) (*protocol.CredentialAssertion, *SessionData, error) { + challenge, err := protocol.CreateChallenge() + if err != nil { + return nil, nil, err + } + requestOptions := protocol.PublicKeyCredentialRequestOptions{ Challenge: challenge, Timeout: webauthn.Config.Timeout, @@ -56,13 +68,13 @@ func (webauthn *WebAuthn) BeginLogin(user User, opts ...LoginOption) (*protocol. newSessionData := SessionData{ Challenge: base64.RawURLEncoding.EncodeToString(challenge), - UserID: user.WebAuthnID(), + UserID: userID, AllowedCredentialIDs: requestOptions.GetAllowedCredentialIDs(), UserVerification: requestOptions.UserVerification, Extensions: requestOptions.Extensions, } - response := protocol.CredentialAssertion{requestOptions} + response := protocol.CredentialAssertion{Response: requestOptions} return &response, &newSessionData, nil } @@ -105,6 +117,29 @@ func (webauthn *WebAuthn) ValidateLogin(user User, session SessionData, parsedRe return nil, protocol.ErrBadRequest.WithDetails("ID mismatch for User and Session") } + return webauthn.validateLogin(user, session, parsedResponse) +} + +// ValidateDiscoverableLogin is an overloaded version of ValidateLogin that allows for discoverable credentials. +func (webauthn *WebAuthn) ValidateDiscoverableLogin(handler DiscoverableUserHandler, session SessionData, parsedResponse *protocol.ParsedCredentialAssertionData) (*Credential, error) { + if session.UserID != nil { + return nil, protocol.ErrBadRequest.WithDetails("Session was not initiated as a client-side discoverable login") + } + + if parsedResponse.Response.UserHandle == nil { + return nil, protocol.ErrBadRequest.WithDetails("Client-side Discoverable Assertion was attempted with a blank User Handle") + } + + user, err := handler(parsedResponse.RawID, parsedResponse.Response.UserHandle) + if err != nil { + return nil, protocol.ErrBadRequest.WithDetails("Failed to lookup Client-side Discoverable Credential") + } + + return webauthn.validateLogin(user, session, parsedResponse) +} + +// validateLogin takes a parsed response and validates it against the user credentials and session data +func (webauthn *WebAuthn) validateLogin(user User, session SessionData, parsedResponse *protocol.ParsedCredentialAssertionData) (*Credential, error) { // Step 1. If the allowCredentials option was given when this authentication ceremony was initiated, // verify that credential.id identifies one of the public key credentials that were listed in // allowCredentials. @@ -143,7 +178,7 @@ func (webauthn *WebAuthn) ValidateLogin(user User, session SessionData, parsedRe // This is in part handled by our Step 1 userHandle := parsedResponse.Response.UserHandle - if userHandle != nil && len(userHandle) > 0 { + if len(userHandle) > 0 { if !bytes.Equal(userHandle, user.WebAuthnID()) { return nil, protocol.ErrBadRequest.WithDetails("userHandle and User ID do not match") } diff --git a/vendor/modules.txt b/vendor/modules.txt index 1dbf0e52..7e2ba46c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -61,7 +61,7 @@ github.com/coreos/go-systemd/v22/daemon github.com/coreos/go-systemd/v22/journal # github.com/cpuguy83/go-md2man/v2 v2.0.0 github.com/cpuguy83/go-md2man/v2/md2man -# github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 +# github.com/duo-labs/webauthn v0.0.0-20221205164246-ebaf9b74c6ec ## explicit github.com/duo-labs/webauthn/metadata github.com/duo-labs/webauthn/protocol -- GitLab