diff options
Diffstat (limited to 'vendor/github.com/tstranex/u2f/util.go')
-rw-r--r-- | vendor/github.com/tstranex/u2f/util.go | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/vendor/github.com/tstranex/u2f/util.go b/vendor/github.com/tstranex/u2f/util.go new file mode 100644 index 0000000000..f035aa417b --- /dev/null +++ b/vendor/github.com/tstranex/u2f/util.go @@ -0,0 +1,125 @@ +// Go FIDO U2F Library +// Copyright 2015 The Go FIDO U2F Library Authors. All rights reserved. +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE file. + +/* +Package u2f implements the server-side parts of the +FIDO Universal 2nd Factor (U2F) specification. + +Applications will usually persist Challenge and Registration objects in a +database. + +To enrol a new token: + + app_id := "http://localhost" + c, _ := NewChallenge(app_id, []string{app_id}) + req, _ := u2f.NewWebRegisterRequest(c, existingTokens) + // Send the request to the browser. + var resp RegisterResponse + // Read resp from the browser. + reg, err := Register(resp, c) + if err != nil { + // Registration failed. + } + // Store reg in the database. + +To perform an authentication: + + var regs []Registration + // Fetch regs from the database. + c, _ := NewChallenge(app_id, []string{app_id}) + req, _ := c.SignRequest(regs) + // Send the request to the browser. + var resp SignResponse + // Read resp from the browser. + new_counter, err := reg.Authenticate(resp, c) + if err != nil { + // Authentication failed. + } + reg.Counter = new_counter + // Store updated Registration in the database. + +The FIDO U2F specification can be found here: +https://fidoalliance.org/specifications/download +*/ +package u2f + +import ( + "crypto/rand" + "crypto/subtle" + "encoding/base64" + "encoding/json" + "errors" + "strings" + "time" +) + +const u2fVersion = "U2F_V2" +const timeout = 5 * time.Minute + +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, "=") +} + +// Challenge represents a single transaction between the server and +// authenticator. This data will typically be stored in a database. +type Challenge struct { + Challenge []byte + Timestamp time.Time + AppID string + TrustedFacets []string +} + +// NewChallenge generates a challenge for the given application. +func NewChallenge(appID string, trustedFacets []string) (*Challenge, error) { + challenge := make([]byte, 32) + n, err := rand.Read(challenge) + if err != nil { + return nil, err + } + if n != 32 { + return nil, errors.New("u2f: unable to generate random bytes") + } + + var c Challenge + c.Challenge = challenge + c.Timestamp = time.Now() + c.AppID = appID + c.TrustedFacets = trustedFacets + return &c, nil +} + +func verifyClientData(clientData []byte, challenge Challenge) error { + var cd ClientData + if err := json.Unmarshal(clientData, &cd); err != nil { + return err + } + + foundFacetID := false + for _, facetID := range challenge.TrustedFacets { + if facetID == cd.Origin { + foundFacetID = true + break + } + } + if !foundFacetID { + return errors.New("u2f: untrusted facet id") + } + + c := encodeBase64(challenge.Challenge) + if len(c) != len(cd.Challenge) || + subtle.ConstantTimeCompare([]byte(c), []byte(cd.Challenge)) != 1 { + return errors.New("u2f: challenge does not match") + } + + return nil +} |