Update WebAuthn and U2F dependencies (#16572)

Update `duo-labs/webauthn` up to `20220122034320`, which is the latest version
we can get without dipping into dependency hell (`etcd` and `opentelemetry` woes
ensue after [2365c59d9f][1]).

`tstranex` could be dropped for a while now (we moved on to WebAuthn-like
interfaces for mocks). `cfssl` was only imported due to what I assume was an
IDE mishap.

I've elected to keep `fxamacker/cbor`, instead of trying to move to
[webauthncbor][2]. fxamacker is solid, past v0, seems more appropriate for
client-side libs and still backs webauthncbor.

There are no updates for `flynn/hid` and `flynn/u2f`.

Release notes for fxamacker/cbor:
https://github.com/fxamacker/cbor/releases/tag/v2.4.0.

[1]: https://github.com/duo-labs/webauthn/commit/2365c59d9fb666cb5f5b6bbae86910632198a8d4
[2]: https://pkg.go.dev/github.com/duo-labs/webauthn@v0.0.0-20220815211337-00c9fb5711f5/protocol/webauthncbor

* Drop tstranex/u2f dependency
* Drop direct dependency to cloudflare/cfssl
* Update fxamacker/cbor/v2 to v2.4.0
* Update duo-labs/webauthn to 2022-01-22
* Fix: Make sure all credentials are set in the user
* Simplify: Drop now unnecessary AuthenticationSelection copy
This commit is contained in:
Alan Parra
2022-09-22 17:08:47 +00:00
committed by GitHub
parent b4317d4014
commit fe3f9332ee
6 changed files with 25 additions and 98 deletions
+4 -6
View File
@@ -27,18 +27,17 @@ require (
github.com/aws/aws-sdk-go-v2/service/ec2 v1.16.0
github.com/aws/aws-sdk-go-v2/service/sts v1.10.0
github.com/beevik/etree v1.1.0
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/coreos/go-semver v0.3.0
github.com/creack/pty v1.1.18
github.com/denisenkom/go-mssqldb v0.11.0
github.com/duo-labs/webauthn v0.0.0-20210727191636-9f1b88ef44cc
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951
github.com/dustin/go-humanize v1.0.0
github.com/elastic/go-elasticsearch/v8 v8.4.0
github.com/flynn/hid v0.0.0-20190502022136-f1b9b6cc019a
github.com/flynn/u2f v0.0.0-20180613185708-15554eb68e5d
github.com/fsouza/fake-gcs-server v1.19.5
github.com/fxamacker/cbor/v2 v2.3.0
github.com/fxamacker/cbor/v2 v2.4.0
github.com/ghodss/yaml v1.0.0
github.com/gizak/termui/v3 v3.1.0
github.com/go-ldap/ldap/v3 v3.4.1
@@ -96,7 +95,6 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/snowflakedb/gosnowflake v1.6.9
github.com/stretchr/testify v1.8.0
github.com/tstranex/u2f v0.0.0-20160508205855-eb799ce68da4
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb
github.com/vulcand/predicate v1.2.0
go.etcd.io/etcd/api/v3 v3.5.1
@@ -185,10 +183,10 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/elastic/elastic-transport-go/v8 v8.1.0 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
@@ -207,6 +205,7 @@ require (
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -274,7 +273,6 @@ require (
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/russross/blackfriday v1.5.2 // indirect
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 // indirect
+6 -8
View File
@@ -300,8 +300,8 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/duo-labs/webauthn v0.0.0-20210727191636-9f1b88ef44cc h1:mLNknBMRNrYNf16wFFUyhSAe1tISZN7oAfal4CZ2OxY=
github.com/duo-labs/webauthn v0.0.0-20210727191636-9f1b88ef44cc/go.mod h1:/X2OJiJxjQ7alqWZqX9EtBTmZc+4qQ0LvZ1k5wP67RM=
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951 h1:17esZ09oW+29rklBtCVphIguql2u3NxYH2OasFPPZoo=
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951/go.mod h1:nHy3JdztZWcsjenDeBuE8gn171OAwg12LBN027UP5AE=
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=
@@ -361,8 +361,8 @@ github.com/fsouza/fake-gcs-server v1.19.5 h1:YTBDIWtCSF6T9x5Hm0lw0clIF7/XTZIQ58g
github.com/fsouza/fake-gcs-server v1.19.5/go.mod h1:Jd6DuVGNvNXC+pEoAbRDihNaEIjIW9UuRVPEvBhHJek=
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/fxamacker/cbor/v2 v2.3.0 h1:aM45YGMctNakddNNAezPxDUpv38j44Abh+hifNuqXik=
github.com/fxamacker/cbor/v2 v2.3.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
@@ -426,11 +426,12 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4=
@@ -1022,7 +1023,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@@ -1097,8 +1097,6 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tstranex/u2f v0.0.0-20160508205855-eb799ce68da4 h1:aR+lGR8m0zBjvDlHkHOCmdsk79ipIPeiP75GqUlywKM=
github.com/tstranex/u2f v0.0.0-20160508205855-eb799ce68da4/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ=
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+2 -2
View File
@@ -1,4 +1,3 @@
// go:build linux
//go:build linux
// +build linux
@@ -29,7 +28,6 @@ import (
"path/filepath"
"testing"
"github.com/cloudflare/cfssl/log"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/backend"
"github.com/gravitational/teleport/lib/backend/lite"
@@ -39,6 +37,8 @@ import (
"github.com/gravitational/teleport/lib/utils/host"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
log "github.com/sirupsen/logrus"
)
const testuser = "teleport-testuser"
-76
View File
@@ -22,7 +22,6 @@ package mocku2f
*/
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
@@ -30,16 +29,12 @@ import (
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/binary"
"encoding/json"
"math/big"
"strings"
"time"
"github.com/duo-labs/webauthn/protocol"
"github.com/gravitational/trace"
"github.com/tstranex/u2f"
)
// u2fRegistrationFlags is fixed by the U2F standard.
@@ -74,19 +69,6 @@ type Key struct {
counter uint32
}
// The "websafe-base64 encoding" in the U2F specifications removes the padding
func decodeBase64(s string) ([]byte, error) {
for i := 0; i < len(s)%4; i++ {
s += "="
}
return base64.URLEncoding.DecodeString(s)
}
func encodeBase64(buf []byte) string {
s := base64.URLEncoding.EncodeToString(buf)
return strings.TrimRight(s, "=")
}
func selfSignPublicKey(keyToSign *ecdsa.PublicKey) (cert []byte, err error) {
caPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
@@ -151,31 +133,6 @@ func (muk *Key) SetPasswordless() {
muk.SetUV = true // UV required for passwordless.
}
func (muk *Key) RegisterResponse(req *u2f.RegisterRequest) (*u2f.RegisterResponse, error) {
appIDHash := sha256.Sum256([]byte(req.AppID))
clientData := u2f.ClientData{
Typ: "navigator.id.finishEnrollment",
Challenge: req.Challenge,
Origin: req.AppID,
}
clientDataJSON, err := json.Marshal(clientData)
if err != nil {
return nil, trace.Wrap(err)
}
clientDataHash := sha256.Sum256(clientDataJSON)
res, err := muk.signRegister(appIDHash[:], clientDataHash[:])
if err != nil {
return nil, trace.Wrap(err)
}
return &u2f.RegisterResponse{
RegistrationData: encodeBase64(res.RawResp),
ClientData: encodeBase64(clientDataJSON),
}, nil
}
// RegisterRaw signs low-level U2F registration data.
// Most callers should use either RegisterResponse or SignCredentialCreation.
func (muk *Key) RegisterRaw(appHash, challengeHash []byte) ([]byte, error) {
@@ -229,39 +186,6 @@ func (muk *Key) signRegister(appIDHash, clientDataHash []byte) (*signRegisterRes
}, nil
}
func (muk *Key) SignResponse(req *u2f.SignRequest) (*u2f.SignResponse, error) {
rawKeyHandle, err := decodeBase64(req.KeyHandle)
if err != nil {
return nil, trace.Wrap(err)
}
if !bytes.Equal(rawKeyHandle, muk.KeyHandle) {
return nil, trace.CompareFailed("wrong keyHandle")
}
appIDHash := sha256.Sum256([]byte(req.AppID))
clientData := u2f.ClientData{
Typ: "navigator.id.getAssertion",
Challenge: req.Challenge,
Origin: req.AppID,
}
clientDataJSON, err := json.Marshal(clientData)
if err != nil {
return nil, trace.Wrap(err)
}
clientDataHash := sha256.Sum256(clientDataJSON)
res, err := muk.signAuthn(appIDHash[:], clientDataHash[:])
if err != nil {
return nil, trace.Wrap(err)
}
return &u2f.SignResponse{
KeyHandle: req.KeyHandle,
SignatureData: encodeBase64(res.SignData),
ClientData: encodeBase64(clientDataJSON),
}, nil
}
// AuthenticateRaw signs low-level U2F authentication data.
// Most callers should use either SignResponse or SignAssertion.
func (muk *Key) AuthenticateRaw(appHash, challengeHash []byte) ([]byte, error) {
+11
View File
@@ -256,6 +256,17 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *CredentialAss
}
sessionData := sessionFromPB(sessionDataPB)
// Make sure _all_ credentials in the session are accounted for by the user.
// webauthn.ValidateLogin requires it.
for _, allowedCred := range sessionData.AllowedCredentialIDs {
if bytes.Equal(parsedResp.RawID, allowedCred) {
continue
}
u.credentials = append(u.credentials, wan.Credential{
ID: allowedCred,
})
}
// Create a WebAuthn matching the expected RPID and Origin, then verify the
// signed challenge.
web, err := newWebAuthn(webAuthnParams{
+2 -6
View File
@@ -175,15 +175,11 @@ func (f *RegistrationFlow) Begin(ctx context.Context, user string, passwordless
if err != nil {
return nil, trace.Wrap(err)
}
credentialCreation, sessionData, err := web.BeginRegistration(u, wan.WithExclusions(exclusions))
cc, sessionData, err := web.BeginRegistration(u, wan.WithExclusions(exclusions))
if err != nil {
return nil, trace.Wrap(err)
}
// Copy settings manually, the framework doesn't do it.
credentialCreation.Response.AuthenticatorSelection = web.Config.AuthenticatorSelection
sessionData.UserVerification = web.Config.AuthenticatorSelection.UserVerification
// TODO(codingllama): Send U2F App ID back in creation requests too. Useful to
// detect duplicate devices.
@@ -195,7 +191,7 @@ func (f *RegistrationFlow) Begin(ctx context.Context, user string, passwordless
return nil, trace.Wrap(err)
}
return (*CredentialCreation)(credentialCreation), nil
return (*CredentialCreation)(cc), nil
}
func upsertOrGetWebID(ctx context.Context, user string, identity RegistrationIdentity) ([]byte, error) {