Skip to content

Commit

Permalink
Merge branch 'master' into renovate/github.com-go-webauthn-revoke-0.1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-elliott committed Oct 12, 2022
2 parents 9063460 + cdfc867 commit af4e297
Show file tree
Hide file tree
Showing 8 changed files with 634 additions and 759 deletions.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ require (
github.com/fxamacker/cbor/v2 v2.4.0
github.com/go-webauthn/revoke v0.1.4
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/google/go-tpm v0.3.3
github.com/google/uuid v1.3.0
github.com/mitchellh/mapstructure v1.5.0
github.com/stretchr/testify v1.8.0
golang.org/x/crypto d6f0a8c073c2
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
182 changes: 179 additions & 3 deletions go.sum

Large diffs are not rendered by default.

54 changes: 25 additions & 29 deletions protocol/attestation_tpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,17 @@ import (
"encoding/asn1"
"errors"
"fmt"
"math/big"
"strings"

"github.com/go-webauthn/webauthn/metadata"
"github.com/go-webauthn/webauthn/protocol/webauthncose"

"github.com/go-webauthn/webauthn/protocol/googletpm"
"github.com/google/go-tpm/tpm2"
)

var tpmAttestationKey = "tpm"

func init() {
RegisterAttestationFormat(tpmAttestationKey, verifyTPMFormat)
googletpm.UseTPM20LengthPrefixSize()
}

func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) {
Expand Down Expand Up @@ -74,27 +71,26 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in

// Verify that the public key specified by the parameters and unique fields of pubArea
// is identical to the credentialPublicKey in the attestedCredentialData in authenticatorData.
pubArea, err := googletpm.DecodePublic(pubAreaBytes)
pubArea, err := tpm2.DecodePublic(pubAreaBytes)
if err != nil {
return "", nil, ErrAttestationFormat.WithDetails("Unable to decode TPMT_PUBLIC in attestation statement")
}

key, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey)
if err != nil {
return tpmAttestationKey, nil, err
return "", nil, err
}
switch key := key.(type) {
case webauthncose.EC2PublicKeyData:
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")
!bytes.Equal(pubArea.ECCParameters.Point.XRaw, key.XCoord) ||
!bytes.Equal(pubArea.ECCParameters.Point.YRaw, key.YCoord) {
return "", nil, ErrAttestationFormat.WithDetails("Mismatch between ECCParameters in pubArea and credentialPublicKey")
}
case webauthncose.RSAPublicKeyData:
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 {
if !bytes.Equal(pubArea.RSAParameters.ModulusRaw, key.Modulus) ||
pubArea.RSAParameters.Exponent() != exp {
return "", nil, ErrAttestationFormat.WithDetails("Mismatch between RSAParameters in pubArea and credentialPublicKey")
}
default:
Expand All @@ -105,34 +101,34 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
attToBeSigned := append(att.RawAuthData, clientDataHash...)

// Validate that certInfo is valid:
certInfo, err := googletpm.DecodeAttestationData(certInfoBytes)
// 1/4 Verify that magic is set to TPM_GENERATED_VALUE, handled here
certInfo, err := tpm2.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 "", nil, ErrAttestationFormat.WithDetails("Magic is not set to TPM_GENERATED_VALUE")
return "", nil, err
}

// 2/4 Verify that type is set to TPM_ST_ATTEST_CERTIFY.
if certInfo.Type != googletpm.TagAttestCertify {
if certInfo.Type != tpm2.TagAttestCertify {
return "", nil, ErrAttestationFormat.WithDetails("Type is not set to TPM_ST_ATTEST_CERTIFY")
}
// 3/4 Verify that extraData is set to the hash of attToBeSigned using the hash algorithm employed in "alg".
f := webauthncose.HasherFromCOSEAlg(coseAlg)
h := f()
h.Write(attToBeSigned)
if !bytes.Equal(certInfo.ExtraData, h.Sum(nil)) {
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("ExtraData is not set to hash of attToBeSigned")
return "", 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
// [TPMv2-Part2] section 10.12.3, whose name field contains a valid Name for pubArea,
// as computed using the algorithm in the nameAlg field of pubArea
// using the procedure specified in [TPMv2-Part1] section 16.
f, err = certInfo.AttestedCertifyInfo.Name.Digest.Alg.HashConstructor()
h = f()
h.Write(pubAreaBytes)
if !bytes.Equal(h.Sum(nil), certInfo.AttestedCertifyInfo.Name.Digest.Value) {
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Hash value mismatch attested and pubArea")
matches, err := certInfo.AttestedCertifyInfo.Name.MatchesPublic(pubArea)
if err != nil {
return "", nil, err
}

if !matches {
return "", nil, ErrAttestationFormat.WithDetails("Hash value mismatch attested and pubArea")
}

// Note that the remaining fields in the "Standard Attestation Structure"
Expand Down Expand Up @@ -176,7 +172,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
if ext.Id.Equal([]int{2, 5, 29, 17}) {
manufacturer, model, version, err = parseSANExtension(ext.Value)
if err != nil {
return tpmAttestationKey, nil, err
return "", nil, err
}
}
}
Expand All @@ -186,7 +182,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
}

if !isValidTPMManufacturer(manufacturer) {
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Invalid TPM manufacturer")
return "", nil, ErrAttestationFormat.WithDetails("Invalid TPM manufacturer")
}

// 4/6 The Extended Key Usage extension MUST contain the "joint-iso-itu-t(2) internationalorganizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)" OID.
Expand All @@ -202,7 +198,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
}
}
if !ekuValid {
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate missing EKU")
return "", nil, ErrAttestationFormat.WithDetails("AIK certificate missing EKU")
}

// 5/6 The Basic Constraints extension MUST have the CA component set to false.
Expand All @@ -221,7 +217,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
}
}
if constraints.IsCA {
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints missing or CA is true")
return "", 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
// extension [RFC5280] are both OPTIONAL as the status of many attestation certificates is available
Expand Down
Loading

0 comments on commit af4e297

Please sign in to comment.