Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fixtures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package mfa
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/duo-labs/webauthn/webauthn"
"github.com/go-webauthn/webauthn/webauthn"
)

type baseTestConfig struct {
Expand All @@ -14,7 +14,6 @@ type baseTestConfig struct {
}

func getDBConfig(ms *MfaSuite) baseTestConfig {

awsConfig := testAwsConfig()
envCfg := testEnvConfig(awsConfig)
localStorage, err := NewStorage(&awsConfig)
Expand All @@ -24,6 +23,7 @@ func getDBConfig(ms *MfaSuite) baseTestConfig {
RPDisplayName: "TestRPName", // Display Name for your site
RPID: "111.11.11.11", // Generally the FQDN for your site
Debug: true,
RPOrigins: []string{testRpOrigin},
})

ms.NoError(err, "failed creating new webAuthnClient for test")
Expand Down
15 changes: 9 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,29 @@ go 1.18
require (
github.com/aws/aws-lambda-go v1.37.0
github.com/aws/aws-sdk-go v1.44.201
github.com/duo-labs/webauthn v0.0.0-20221205164246-ebaf9b74c6ec
github.com/fxamacker/cbor/v2 v2.4.0
github.com/go-webauthn/webauthn v0.8.6
github.com/gorilla/mux v1.8.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/pkg/errors v0.9.1
github.com/satori/go.uuid v1.2.0
github.com/stretchr/testify v1.8.1
golang.org/x/crypto v0.6.0
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.11.0
)

require (
github.com/cloudflare/cfssl v1.6.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
github.com/google/certificate-transparency-go v1.1.4 // indirect
github.com/go-webauthn/x v0.1.4 // indirect
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/sys v0.10.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
1,140 changes: 14 additions & 1,126 deletions go.sum

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions terraform/lambda-role-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
"dynamodb:GetItem"
],
"Resource": [
"arn:aws:dynamodb:*:${aws_account}:table/${api_key_table}",
"arn:aws:dynamodb:*:${aws_account}:table/${api_key_table}_global"
"arn:aws:dynamodb:*:${aws_account}:table/${api_key_table}"
],
"Effect": "Allow"
},
Expand All @@ -51,8 +50,7 @@
"dynamodb:DeleteItem"
],
"Resource": [
"arn:aws:dynamodb:*:${aws_account}:table/${webauthn_table}",
"arn:aws:dynamodb:*:${aws_account}:table/${webauthn_table}_global"
"arn:aws:dynamodb:*:${aws_account}:table/${webauthn_table}"
],
"Effect": "Allow"
}
Expand Down
32 changes: 17 additions & 15 deletions u2fsimulator/u2fsimulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import (
"strings"
"time"

"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/protocol/webauthncbor"
"github.com/duo-labs/webauthn/protocol/webauthncose"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/protocol/webauthncbor"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
)

const (
Expand Down Expand Up @@ -120,7 +120,7 @@ func getPrivateKey() *ecdsa.PrivateKey {
}

// GetAuthDataAndPrivateKey return the authentication data as a string and as a byte slice
// and also returns the private key
// and also returns the private key
func GetAuthDataAndPrivateKey(rpID, keyHandle string) (authDataStr string, authData []byte, privateKey *ecdsa.PrivateKey) {
// Add in the RP ID Hash (32 bytes)
RPIDHash := sha256.Sum256([]byte(rpID))
Expand Down Expand Up @@ -197,7 +197,6 @@ func getCertBytes(privateKey *ecdsa.PrivateKey, serialNumber *big.Int, certReade
// GetASN1Signature signs a hash (which should be the result of hashing a larger message)
// using the private key.
func GetASN1Signature(notRandom io.Reader, privateKey *ecdsa.PrivateKey, sha256Digest []byte) (DsaSignature, []byte) {

r, s, err := ecdsa.Sign(notRandom, privateKey, sha256Digest[:])
if err != nil {
panic("error generating signature: " + err.Error())
Expand All @@ -214,11 +213,9 @@ func GetASN1Signature(notRandom io.Reader, privateKey *ecdsa.PrivateKey, sha256D
}

// getSignatureForAttObject starts with byte(0) and appends the sha256 sum of the rpOrigin and of the clientData
// and then appends the keyHandle and an elliptic Marshalled version of the public key
// It does a sha256 sum of that and creates a dsa signature of it with the private key and without using any
// randomizing
// and then appends the keyHandle and an elliptic Marshalled version of the public key. It does a sha256 sum of
// that and creates a dsa signature of it with the private key and without using any randomizing.
func getSignatureForAttObject(notRandom io.Reader, clientData []byte, keyHandle string, privateKey *ecdsa.PrivateKey, rpOrigin string) []byte {

appParam := sha256.Sum256([]byte(rpOrigin))
challenge := sha256.Sum256(clientData)

Expand Down Expand Up @@ -284,17 +281,22 @@ type U2fRegistrationResponse struct {
}

// U2fRegistration is intended to assist with automated testing by
// returning to an api server something similar to what a client
// would return following a registration ceremony with a U2F key
// returning to an api server something similar to what a client
// would return following a registration ceremony with a U2F key
//
// It expects a POST call with the following elements in the body/form
//
// "challenge"
// "keyHandle" (optional)
// (Although the api server wouldn't normally deal with a challenge and keyHandle,
// including them here allows for more predictability with the test results.)
//
// (Although the api server wouldn't normally deal with a challenge and keyHandle,
// including them here allows for more predictability with the test results.)
//
// It also expects the following headers to be set on the request
//
// "x-mfa-RPID"
// "x-mfa-RPOrigin"
// "x-mfa-UserUUID"
// "x-mfa-RPOrigin"
// "x-mfa-UserUUID"
func U2fRegistration(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
Expand Down
20 changes: 9 additions & 11 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
"log"
"net/http"

cbor "github.com/fxamacker/cbor/v2"
"github.com/fxamacker/cbor/v2"
"github.com/pkg/errors"

"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/protocol/webauthncose"
"github.com/duo-labs/webauthn/webauthn"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
"github.com/go-webauthn/webauthn/webauthn"
)

const (
Expand Down Expand Up @@ -133,12 +133,10 @@ func (u *DynamoUser) saveNewCredential(credential webauthn.Credential) error {
return u.encryptAndStoreCredentials()
}

// DeleteCredential expects a hashed-encoded credential id.
// It finds a matching credential for that user and saves the user
// without that credential included.
// Alternatively, if the given credential id indicates that a legacy U2F key should be removed
// (e.g. by matching the string "u2f")
// then that user is saved with all of its legacy u2f fields blanked out.
// DeleteCredential expects a hashed-encoded credential id. It finds a matching credential for that user and saves the
// user without that credential included. Alternatively, if the given credential id indicates that a legacy U2F key
// should be removed (e.g. by matching the string "u2f") then that user is saved with all of its legacy u2f fields
// blanked out.
func (u *DynamoUser) DeleteCredential(credIDHash string) (int, error) {
// load to be sure working with the latest data
err := u.Load()
Expand Down Expand Up @@ -371,7 +369,7 @@ func (u *DynamoUser) FinishLogin(r *http.Request) (*webauthn.Credential, error)
}

// there is an issue with URLEncodeBase64.UnmarshalJSON and null values
// see https://github.com/duo-labs/webauthn/issues/69
// see https://github.com/go-webauthn/webauthn/issues/69
// null byte sequence is []byte{158,233,101}
if isNullByteSlice(parsedResponse.Response.UserHandle) {
parsedResponse.Response.UserHandle = nil
Expand Down
4 changes: 2 additions & 2 deletions webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"net/http"
"strings"

"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/webauthn"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/gorilla/mux"
uuid "github.com/satori/go.uuid"
)
Expand Down
16 changes: 7 additions & 9 deletions webauthn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/webauthn"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"

Expand All @@ -35,7 +35,7 @@ const (
testRpId = "dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA"

AssertionTypeFido = "fido-u2f"
testRpOrigin = "localhost"
testRpOrigin = "https://example.com"
)

func getTestAssertionResponse(credID, authData, clientData, attestationObject string) []byte {
Expand All @@ -52,7 +52,6 @@ func getTestAssertionResponse(credID, authData, clientData, attestationObject st
}

func getTestAssertionRequest(credID1, authData1, clientData1, attestObject1 string, user *DynamoUser) *http.Request {

assertResp := getTestAssertionResponse(credID1, authData1, clientData1, attestObject1)

body := ioutil.NopCloser(bytes.NewReader(assertResp))
Expand Down Expand Up @@ -138,6 +137,7 @@ func (ms *MfaSuite) Test_BeginRegistration() {
RPDisplayName: "TestRPName", // Display Name for your site
RPID: "111.11.11.11", // Generally the FQDN for your site
Debug: true,
RPOrigins: []string{testRpOrigin},
})

ms.NoError(err, "failed creating new webAuthnClient for test")
Expand Down Expand Up @@ -429,6 +429,7 @@ func (ms *MfaSuite) Test_BeginLogin() {
RPDisplayName: "TestRPName", // Display Name for your site
RPID: "111.11.11.11", // Generally the FQDN for your site
Debug: true,
RPOrigins: []string{testRpOrigin},
})

ms.NoError(err, "failed creating new webAuthnClient for test")
Expand Down Expand Up @@ -629,7 +630,7 @@ func (ms *MfaSuite) Test_FinishLogin() {

signature1 := GenerateAuthenticationSig(authDataBytes1, cdBytes, privateKey1)

var assertionResponse1 = `{
assertionResponse1 := `{
"id":"` + credIDEncoded1 + `",
"rawId":"` + credIDEncoded1 + `",
"type":"public-key",
Expand All @@ -651,7 +652,7 @@ func (ms *MfaSuite) Test_FinishLogin() {

signature2 := GenerateAuthenticationSig(authDataBytes2, cdBytes, privateKey1)

var assertionResponse2 = `{
assertionResponse2 := `{
"id":"` + credIDEncoded2 + `",
"rawId":"` + credIDEncoded2 + `",
"type":"public-key",
Expand Down Expand Up @@ -768,7 +769,6 @@ func Test_GetPublicKeyAsBytes(t *testing.T) {
want := []byte{4, 6, 214, 26, 66, 24, 173, 50, 249, 174, 188, 167, 158, 81, 153, 174, 135, 222, 147, 153, 116, 209, 27, 16, 127, 233, 183, 236, 149, 105, 147, 84, 94, 138, 214, 31, 142, 253, 63, 17, 232, 200, 228, 33, 96, 172, 95, 227, 235, 203, 196, 73, 134, 227, 177, 108, 60, 40, 190, 118, 9, 6, 237, 18, 103}

assert.Equal(want, got, "incorrect public Key")

}

func Router() *mux.Router {
Expand Down Expand Up @@ -802,7 +802,6 @@ func testAuthnMiddleware(next http.Handler) http.Handler {
}

func (ms *MfaSuite) Test_DeleteCredential() {

baseConfigs := getDBConfig(ms)

users := getTestWebauthnUsers(ms, baseConfigs)
Expand Down Expand Up @@ -876,7 +875,6 @@ func (ms *MfaSuite) Test_DeleteCredential() {
}
for _, tt := range tests {
ms.T().Run(tt.name, func(t *testing.T) {

request, _ := http.NewRequest("DELETE", fmt.Sprintf("/webauthn/credential/%s", tt.credID), nil)

request.Header.Set("x-mfa-apikey", tt.user.ApiKeyValue)
Expand Down