@@ -2,20 +2,16 @@ package protocol
22
33import  (
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
1713func  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.
10892type  AppleAnonymousAttestation  struct  {
10993	Nonce  []byte  `asn1:"tag:1,explicit"` 
11094}
95+ 
96+ var  (
97+ 	attAppleHardwareRootsCertPool  * x509.CertPool 
98+ )
0 commit comments