Skip to content

Commit cdfc867

Browse files
authored
feat: refactor of tpm attestation (#60)
This removes a majority of TPM 2.0 related code from the library and utilizes the google TPM library.
1 parent 1ad6f47 commit cdfc867

File tree

8 files changed

+634
-759
lines changed

8 files changed

+634
-759
lines changed

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ require (
66
github.com/fxamacker/cbor/v2 v2.4.0
77
github.com/go-webauthn/revoke v0.1.3
88
github.com/golang-jwt/jwt/v4 v4.4.2
9+
github.com/google/go-tpm v0.3.3
910
github.com/google/uuid v1.3.0
1011
github.com/mitchellh/mapstructure v1.5.0
1112
github.com/stretchr/testify v1.8.0
12-
golang.org/x/crypto d6f0a8c073c2
13+
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
1314
)
1415

1516
require (
1617
github.com/davecgh/go-spew v1.1.1 // indirect
1718
github.com/pmezard/go-difflib v1.0.0 // indirect
1819
github.com/x448/float16 v0.8.4 // indirect
20+
golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb // indirect
1921
gopkg.in/yaml.v3 v3.0.1 // indirect
2022
)

go.sum

+179-3
Large diffs are not rendered by default.

protocol/attestation_tpm.go

+25-29
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,17 @@ import (
77
"encoding/asn1"
88
"errors"
99
"fmt"
10-
"math/big"
1110
"strings"
1211

1312
"github.com/go-webauthn/webauthn/metadata"
1413
"github.com/go-webauthn/webauthn/protocol/webauthncose"
15-
16-
"github.com/go-webauthn/webauthn/protocol/googletpm"
14+
"github.com/google/go-tpm/tpm2"
1715
)
1816

1917
var tpmAttestationKey = "tpm"
2018

2119
func init() {
2220
RegisterAttestationFormat(tpmAttestationKey, verifyTPMFormat)
23-
googletpm.UseTPM20LengthPrefixSize()
2421
}
2522

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

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

8279
key, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey)
8380
if err != nil {
84-
return tpmAttestationKey, nil, err
81+
return "", nil, err
8582
}
8683
switch key := key.(type) {
8784
case webauthncose.EC2PublicKeyData:
8885
if pubArea.ECCParameters.CurveID != key.TPMCurveID() ||
89-
pubArea.ECCParameters.Point.X.Cmp(new(big.Int).SetBytes(key.XCoord)) != 0 ||
90-
pubArea.ECCParameters.Point.Y.Cmp(new(big.Int).SetBytes(key.YCoord)) != 0 {
91-
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Mismatch between ECCParameters in pubArea and credentialPublicKey")
86+
!bytes.Equal(pubArea.ECCParameters.Point.XRaw, key.XCoord) ||
87+
!bytes.Equal(pubArea.ECCParameters.Point.YRaw, key.YCoord) {
88+
return "", nil, ErrAttestationFormat.WithDetails("Mismatch between ECCParameters in pubArea and credentialPublicKey")
9289
}
9390
case webauthncose.RSAPublicKeyData:
94-
mod := new(big.Int).SetBytes(key.Modulus)
9591
exp := uint32(key.Exponent[0]) + uint32(key.Exponent[1])<<8 + uint32(key.Exponent[2])<<16
96-
if pubArea.RSAParameters.Modulus.Cmp(mod) != 0 ||
97-
pubArea.RSAParameters.Exponent != exp {
92+
if !bytes.Equal(pubArea.RSAParameters.ModulusRaw, key.Modulus) ||
93+
pubArea.RSAParameters.Exponent() != exp {
9894
return "", nil, ErrAttestationFormat.WithDetails("Mismatch between RSAParameters in pubArea and credentialPublicKey")
9995
}
10096
default:
@@ -105,34 +101,34 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
105101
attToBeSigned := append(att.RawAuthData, clientDataHash...)
106102

107103
// Validate that certInfo is valid:
108-
certInfo, err := googletpm.DecodeAttestationData(certInfoBytes)
104+
// 1/4 Verify that magic is set to TPM_GENERATED_VALUE, handled here
105+
certInfo, err := tpm2.DecodeAttestationData(certInfoBytes)
109106
if err != nil {
110-
return tpmAttestationKey, nil, err
111-
}
112-
// 1/4 Verify that magic is set to TPM_GENERATED_VALUE.
113-
if certInfo.Magic != 0xff544347 {
114-
return "", nil, ErrAttestationFormat.WithDetails("Magic is not set to TPM_GENERATED_VALUE")
107+
return "", nil, err
115108
}
109+
116110
// 2/4 Verify that type is set to TPM_ST_ATTEST_CERTIFY.
117-
if certInfo.Type != googletpm.TagAttestCertify {
111+
if certInfo.Type != tpm2.TagAttestCertify {
118112
return "", nil, ErrAttestationFormat.WithDetails("Type is not set to TPM_ST_ATTEST_CERTIFY")
119113
}
120114
// 3/4 Verify that extraData is set to the hash of attToBeSigned using the hash algorithm employed in "alg".
121115
f := webauthncose.HasherFromCOSEAlg(coseAlg)
122116
h := f()
123117
h.Write(attToBeSigned)
124118
if !bytes.Equal(certInfo.ExtraData, h.Sum(nil)) {
125-
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("ExtraData is not set to hash of attToBeSigned")
119+
return "", nil, ErrAttestationFormat.WithDetails("ExtraData is not set to hash of attToBeSigned")
126120
}
127121
// 4/4 Verify that attested contains a TPMS_CERTIFY_INFO structure as specified in
128122
// [TPMv2-Part2] section 10.12.3, whose name field contains a valid Name for pubArea,
129123
// as computed using the algorithm in the nameAlg field of pubArea
130124
// using the procedure specified in [TPMv2-Part1] section 16.
131-
f, err = certInfo.AttestedCertifyInfo.Name.Digest.Alg.HashConstructor()
132-
h = f()
133-
h.Write(pubAreaBytes)
134-
if !bytes.Equal(h.Sum(nil), certInfo.AttestedCertifyInfo.Name.Digest.Value) {
135-
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Hash value mismatch attested and pubArea")
125+
matches, err := certInfo.AttestedCertifyInfo.Name.MatchesPublic(pubArea)
126+
if err != nil {
127+
return "", nil, err
128+
}
129+
130+
if !matches {
131+
return "", nil, ErrAttestationFormat.WithDetails("Hash value mismatch attested and pubArea")
136132
}
137133

138134
// Note that the remaining fields in the "Standard Attestation Structure"
@@ -176,7 +172,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
176172
if ext.Id.Equal([]int{2, 5, 29, 17}) {
177173
manufacturer, model, version, err = parseSANExtension(ext.Value)
178174
if err != nil {
179-
return tpmAttestationKey, nil, err
175+
return "", nil, err
180176
}
181177
}
182178
}
@@ -186,7 +182,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
186182
}
187183

188184
if !isValidTPMManufacturer(manufacturer) {
189-
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Invalid TPM manufacturer")
185+
return "", nil, ErrAttestationFormat.WithDetails("Invalid TPM manufacturer")
190186
}
191187

192188
// 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.
@@ -202,7 +198,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
202198
}
203199
}
204200
if !ekuValid {
205-
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate missing EKU")
201+
return "", nil, ErrAttestationFormat.WithDetails("AIK certificate missing EKU")
206202
}
207203

208204
// 5/6 The Basic Constraints extension MUST have the CA component set to false.
@@ -221,7 +217,7 @@ func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []in
221217
}
222218
}
223219
if constraints.IsCA {
224-
return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints missing or CA is true")
220+
return "", nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints missing or CA is true")
225221
}
226222
// 6/6 An Authority Information Access (AIA) extension with entry id-ad-ocsp and a CRL Distribution Point
227223
// extension [RFC5280] are both OPTIONAL as the status of many attestation certificates is available

0 commit comments

Comments
 (0)