Skip to content

Commit 0ca9335

Browse files
refactor: final adjustments
1 parent 83f2295 commit 0ca9335

19 files changed

+373
-274
lines changed

protocol/attestation_androidkey.go

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
)
1313

1414
func init() {
15-
RegisterAttestationFormat(AttestationFormatAndroidKey, verifyAndroidKeyFormat)
15+
RegisterAttestationFormat(AttestationFormatAndroidKey, attestationFormatValidationHandlerAndroidKey)
1616
}
1717

1818
// The android-key attestation statement looks like:
@@ -30,7 +30,7 @@ func init() {
3030
// }
3131
//
3232
// Specification: §8.4. Android Key Attestation Statement Format (https://www.w3.org/TR/webauthn/#sctn-android-key-attestation)
33-
func verifyAndroidKeyFormat(att AttestationObject, clientDataHash []byte, _ metadata.Provider) (attestationType string, x5cs []any, err error) {
33+
func attestationFormatValidationHandlerAndroidKey(att AttestationObject, clientDataHash []byte, _ metadata.Provider) (attestationType string, x5cs []any, err error) {
3434
// Given the verification procedure inputs attStmt, authenticatorData and clientDataHash, the verification procedure is as follows:
3535
// §8.4.1. Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract
3636
// the contained fields.
@@ -63,7 +63,7 @@ func verifyAndroidKeyFormat(att AttestationObject, clientDataHash []byte, _ meta
6363
return "", nil, ErrAttestation.WithDetails("Error parsing x5c cert chain").WithError(err)
6464
}
6565

66-
leaf := certs[0]
66+
credCert := certs[0]
6767

6868
if _, err = certChainVerify(certs, attAndroidKeyHardwareRootsCertPool, true, time.Now().Add(time.Hour*8760).UTC()); err != nil {
6969
return "", nil, ErrInvalidAttestation.WithDetails("Error validating x5c cert chain").WithError(err)
@@ -72,32 +72,27 @@ func verifyAndroidKeyFormat(att AttestationObject, clientDataHash []byte, _ meta
7272
signatureData := append(att.RawAuthData, clientDataHash...) //nolint:gocritic // This is intentional.
7373

7474
coseAlg := webauthncose.COSEAlgorithmIdentifier(alg)
75-
if err = leaf.CheckSignature(webauthncose.SigAlgFromCOSEAlg(coseAlg), signatureData, sig); err != nil {
75+
if err = credCert.CheckSignature(webauthncose.SigAlgFromCOSEAlg(coseAlg), signatureData, sig); err != nil {
7676
return "", nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Signature validation error: %+v", err)).WithError(err)
7777
}
7878

7979
// Verify that the public key in the first certificate in x5c matches the credentialPublicKey in the attestedCredentialData in authenticatorData.
80-
pubKey, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey)
81-
if err != nil {
82-
return "", nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error parsing public key: %+v", err)).WithError(err)
83-
}
84-
85-
e, ok := pubKey.(webauthncose.EC2PublicKeyData)
86-
if !ok {
87-
return "", nil, ErrInvalidAttestation.WithDetails("Attestation public key is not EC2")
80+
var attPublicKeyData webauthncose.EC2PublicKeyData
81+
if attPublicKeyData, err = verifyAttestationECDSAPublicKeyMatch(att, credCert); err != nil {
82+
return "", nil, err
8883
}
8984

9085
var valid bool
91-
if valid, err = e.Verify(signatureData, sig); err != nil || !valid {
86+
if valid, err = attPublicKeyData.Verify(signatureData, sig); err != nil || !valid {
9287
return "", nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error parsing public key: %+v", err)).WithError(err)
9388
}
9489

9590
// §8.4.3. Verify that the attestationChallenge field in the attestation certificate extension data is identical to clientDataHash.
9691
// attCert.Extensions.
9792
var attExtBytes []byte
9893

99-
for _, ext := range leaf.Extensions {
100-
if ext.Id.Equal([]int{1, 3, 6, 1, 4, 1, 11129, 2, 1, 17}) {
94+
for _, ext := range credCert.Extensions {
95+
if ext.Id.Equal(oidExtensionAndroidKeystore) {
10196
attExtBytes = ext.Value
10297
}
10398
}

protocol/attestation_androidkey_const.go

Lines changed: 0 additions & 152 deletions
This file was deleted.

protocol/attestation_androidkey_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ func TestVerifyAndroidKeyFormat(t *testing.T) {
8989
tc.setup(t, mds)
9090
}
9191

92-
attestationType, x5cs, err = verifyAndroidKeyFormat(tc.args.att, tc.args.clientDataHash, mds)
92+
attestationType, x5cs, err = attestationFormatValidationHandlerAndroidKey(tc.args.att, tc.args.clientDataHash, mds)
9393
} else {
9494
if tc.setup != nil {
9595
tc.setup(t, nil)
9696
}
9797

98-
attestationType, x5cs, err = verifyAndroidKeyFormat(tc.args.att, tc.args.clientDataHash, nil)
98+
attestationType, x5cs, err = attestationFormatValidationHandlerAndroidKey(tc.args.att, tc.args.clientDataHash, nil)
9999
}
100100

101101
if tc.err != "" {

protocol/attestation_apple.go

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,16 @@ package protocol
22

33
import (
44
"bytes"
5-
"crypto/ecdsa"
6-
"crypto/elliptic"
75
"crypto/sha256"
86
"crypto/x509"
97
"encoding/asn1"
10-
"fmt"
11-
"math/big"
8+
"time"
129

1310
"github.com/go-webauthn/webauthn/metadata"
14-
"github.com/go-webauthn/webauthn/protocol/webauthncose"
1511
)
1612

1713
func init() {
18-
RegisterAttestationFormat(AttestationFormatApple, verifyAppleFormat)
14+
RegisterAttestationFormat(AttestationFormatApple, attestationFormatValidationHandlerAppleAnonymous)
1915
}
2016

2117
// The apple attestation statement looks like:
@@ -31,7 +27,7 @@ func init() {
3127
// }
3228
//
3329
// Specification: §8.8. Apple Anonymous Attestation Statement Format (https://www.w3.org/TR/webauthn/#sctn-apple-anonymous-attestation)
34-
func verifyAppleFormat(att AttestationObject, clientDataHash []byte, _ metadata.Provider) (attestationType string, x5cs []any, err error) {
30+
func attestationFormatValidationHandlerAppleAnonymous(att AttestationObject, clientDataHash []byte, _ metadata.Provider) (attestationType string, x5cs []any, err error) {
3531
// Step 1. Verify that attStmt is valid CBOR conforming to the syntax defined
3632
// above and perform CBOR decoding on it to extract the contained fields.
3733
// If x5c is not present, return an error.
@@ -41,27 +37,29 @@ func verifyAppleFormat(att AttestationObject, clientDataHash []byte, _ metadata.
4137
return "", nil, ErrAttestationFormat.WithDetails("Error retrieving x5c value")
4238
}
4339

44-
credCertBytes, valid := x5c[0].([]byte)
45-
if !valid {
46-
return "", nil, ErrAttestation.WithDetails("Error getting certificate from x5c cert chain")
47-
}
48-
49-
credCert, err := x509.ParseCertificate(credCertBytes)
50-
if err != nil {
51-
return "", nil, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing certificate from ASN.1 data: %+v", err)).WithError(err)
52-
}
53-
5440
// Step 2. Concatenate authenticatorData and clientDataHash to form nonceToHash.
5541
nonceToHash := append(att.RawAuthData, clientDataHash...) //nolint:gocritic // This is intentional.
5642

5743
// Step 3. Perform SHA-256 hash of nonceToHash to produce nonce.
5844
nonce := sha256.Sum256(nonceToHash)
5945

6046
// Step 4. Verify that nonce equals the value of the extension with OID 1.2.840.113635.100.8.2 in credCert.
47+
var certs []*x509.Certificate
48+
49+
if certs, err = parseX5C(x5c); err != nil {
50+
return "", nil, ErrAttestation.WithDetails("Error parsing x5c cert chain").WithError(err)
51+
}
52+
53+
credCert := certs[0]
54+
55+
if _, err = certChainVerify(certs, attAppleHardwareRootsCertPool, true, time.Now().Add(time.Hour*8760).UTC()); err != nil {
56+
return "", nil, ErrInvalidAttestation.WithDetails("Error validating x5c cert chain").WithError(err)
57+
}
58+
6159
var attExtBytes []byte
6260

6361
for _, ext := range credCert.Extensions {
64-
if ext.Id.Equal([]int{1, 2, 840, 113635, 100, 8, 2}) {
62+
if ext.Id.Equal(oidExtensionAppleAnonymousAttestation) {
6563
attExtBytes = ext.Value
6664
}
6765
}
@@ -81,22 +79,8 @@ func verifyAppleFormat(att AttestationObject, clientDataHash []byte, _ metadata.
8179
}
8280

8381
// Step 5. Verify that the credential public key equals the Subject Public Key of credCert.
84-
// TODO: Probably move this part to webauthncose.go.
85-
pubKey, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey)
86-
if err != nil {
87-
return "", nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error parsing public key: %+v", err)).WithError(err)
88-
}
89-
90-
credPK := pubKey.(webauthncose.EC2PublicKeyData)
91-
subjectPK := credCert.PublicKey.(*ecdsa.PublicKey)
92-
credPKInfo := &ecdsa.PublicKey{
93-
Curve: elliptic.P256(),
94-
X: big.NewInt(0).SetBytes(credPK.XCoord),
95-
Y: big.NewInt(0).SetBytes(credPK.YCoord),
96-
}
97-
98-
if !credPKInfo.Equal(subjectPK) {
99-
return "", nil, ErrInvalidAttestation.WithDetails("Certificate public key does not match public key in authData")
82+
if _, err = verifyAttestationECDSAPublicKeyMatch(att, credCert); err != nil {
83+
return "", nil, err
10084
}
10185

10286
// Step 6. If successful, return implementation-specific values representing attestation type Anonymization CA and attestation trust path x5c.
@@ -108,3 +92,7 @@ func verifyAppleFormat(att AttestationObject, clientDataHash []byte, _ metadata.
10892
type AppleAnonymousAttestation struct {
10993
Nonce []byte `asn1:"tag:1,explicit"`
11094
}
95+
96+
var (
97+
attAppleHardwareRootsCertPool *x509.CertPool
98+
)

0 commit comments

Comments
 (0)