@@ -33,6 +33,10 @@ var OIDExtensionAndroidAttestation = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 111
3333// remote key provisioning info.
3434var OIDExtensionAndroidRkpInfo = asn1.ObjectIdentifier {1 , 3 , 6 , 1 , 4 , 1 , 11129 , 2 , 1 , 30 }
3535
36+ // OIDExtensionAndroidVmAttestation is the OID value for an X.509 extension that holds
37+ // Android attestation info for a virtual machine.
38+ var OIDExtensionAndroidVmAttestation = asn1.ObjectIdentifier {1 , 3 , 6 , 1 , 4 , 1 , 11129 , 2 , 1 , 29 , 1 }
39+
3640// AndroidAttestationInfo holds attestation information attached to an Android
3741// hardware-backed key, describing features of the key and the device that issued
3842// it. See https://developer.android.com/training/articles/security-key-attestation for
@@ -48,6 +52,22 @@ type AndroidAttestationInfo struct {
4852 HardwareEnforced AuthorizationList
4953}
5054
55+ // AndroidVmAttestationInfo holds attestation information attached to an Android virtual
56+ // machine.
57+ type AndroidVmAttestationInfo struct {
58+ AttestationChallenge []byte
59+ IsVmSecure bool
60+ VmComponents []AndroidVmComponent
61+ }
62+
63+ // AndroidVmComponent describes one attested component of an Android VM.
64+ type AndroidVmComponent struct {
65+ Name string
66+ SecurityVersion int64
67+ CodeHash []byte
68+ AuthorityHash []byte
69+ }
70+
5171func securityLevelToString (lvl asn1.Enumerated ) string {
5272 switch lvl {
5373 case 0 :
@@ -151,6 +171,48 @@ func AttestInfoFromCert(cert *x509.Certificate) (*AndroidAttestationInfo, error)
151171 return nil , errors .New ("no Android Attestation extension found" )
152172}
153173
174+ // VmInfoFromCert retrieves and parses an Android VM attestation information extension
175+ // from a certificate, if present.
176+ func VmInfoFromCert (cert * x509.Certificate ) (* AndroidVmAttestationInfo , error ) {
177+ for _ , ext := range cert .Extensions {
178+ if ext .Id .Equal (OIDExtensionAndroidVmAttestation ) {
179+ var vmInfo AndroidVmAttestationInfo
180+ rest , err := asn1 .Unmarshal (ext .Value , & vmInfo )
181+ if err != nil {
182+ return nil , fmt .Errorf ("failed to unmarshal attestation info: %v" , err )
183+ } else if len (rest ) > 0 {
184+ return nil , fmt .Errorf ("trailing data (%d bytes) after attestation info" , len (rest ))
185+ }
186+ return & vmInfo , nil
187+ }
188+ }
189+ return nil , errors .New ("no Android VM Attestation extension found" )
190+ }
191+
192+ func showAndroidVmAttestation (result * bytes.Buffer , cert * x509.Certificate ) {
193+ count , critical := OIDInExtensions (OIDExtensionAndroidVmAttestation , cert .Extensions )
194+ if count == 0 {
195+ return
196+ }
197+ result .WriteString (fmt .Sprintf (" Android VM Information:" ))
198+ showCritical (result , critical )
199+ vmInfo , err := VmInfoFromCert (cert )
200+ if err != nil {
201+ result .WriteString (fmt .Sprintf (" Failed to decode VM info: (%s)\n " , err ))
202+ return
203+ }
204+ showHex (result , " " , "Attestation Challenge" , vmInfo .AttestationChallenge )
205+ result .WriteString (fmt .Sprintf (" Is VM Secure: %t\n " , vmInfo .IsVmSecure ))
206+ result .WriteString (fmt .Sprintf (" Components:\n " ))
207+ for _ , component := range vmInfo .VmComponents {
208+ result .WriteString (fmt .Sprintf (" Component:\n " ))
209+ result .WriteString (fmt .Sprintf (" Name: %s\n " , component .Name ))
210+ result .WriteString (fmt .Sprintf (" Security Version: %d\n " , component .SecurityVersion ))
211+ showHex (result , " " , "Code Hash" , component .CodeHash )
212+ showHex (result , " " , "Authority Hash" , component .AuthorityHash )
213+ }
214+ }
215+
154216func showAndroidRkpInfo (result * bytes.Buffer , cert * x509.Certificate ) {
155217 for _ , ext := range cert .Extensions {
156218 if ext .Id .Equal (OIDExtensionAndroidRkpInfo ) {
@@ -270,7 +332,7 @@ func showKeyAuthorizations(buf *bytes.Buffer, auths AuthorizationList, prefix st
270332 buf .WriteString (fmt .Sprintf ("%sOS Patchlevel: %d\n " , prefix , auths .OsPatchlevel ))
271333 }
272334
273- showOptionalAttestationAppId (buf , prefix , auths .AttestationApplicationId )
335+ showOptionalAttestationAppId (buf , prefix , auths .AttestationApplicationId )
274336 showOptionalHexUtf8 (buf , prefix , "Attestation Id Brand" , auths .AttestationIdBrand )
275337 showOptionalHexUtf8 (buf , prefix , "Attestation Id Device" , auths .AttestationIdDevice )
276338 showOptionalHexUtf8 (buf , prefix , "Attestation Id Product" , auths .AttestationIdProduct )
@@ -475,13 +537,13 @@ func showHexUtf8(buf *bytes.Buffer, prefix string, name string, val []byte) {
475537// AndroidAttestationAppId describes an Android application identifier.
476538type AndroidAttestationAppId struct {
477539 PackageInfoRecords []AndroidPackageInfoRecord `asn1:"set"`
478- SignatureDigests [][]byte `asn1:"set"`
540+ SignatureDigests [][]byte `asn1:"set"`
479541}
480542
481543// AndroidPackageInfoRecord hold a package info record from Android.
482544type AndroidPackageInfoRecord struct {
483545 PackageName []byte
484- Version int
546+ Version int
485547}
486548
487549func AndroidAppInfoFromData (val []byte ) (* AndroidAttestationAppId , error ) {
0 commit comments