Skip to content

Commit 5b245f2

Browse files
committed
x509util: support VM attestation info
1 parent b520617 commit 5b245f2

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

x509util/android.go

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ var OIDExtensionAndroidAttestation = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 111
3333
// remote key provisioning info.
3434
var 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+
5171
func 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+
154216
func 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.
476538
type 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.
482544
type AndroidPackageInfoRecord struct {
483545
PackageName []byte
484-
Version int
546+
Version int
485547
}
486548

487549
func AndroidAppInfoFromData(val []byte) (*AndroidAttestationAppId, error) {

x509util/x509util.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ func CertificateToString(cert *x509.Certificate) string {
472472
showCTLogSTHInfo(&result, cert)
473473
showAndroidAttestation(&result, cert)
474474
showAndroidRkpInfo(&result, cert)
475+
showAndroidVmAttestation(&result, cert)
475476

476477
showUnhandledExtensions(&result, cert)
477478
showSignature(&result, cert)
@@ -832,6 +833,7 @@ func oidAlreadyPrinted(oid asn1.ObjectIdentifier) bool {
832833
oid.Equal(x509.OIDExtensionCTSCT) ||
833834
oid.Equal(x509ext.OIDExtensionCTSTH) ||
834835
oid.Equal(OIDExtensionAndroidAttestation) ||
836+
oid.Equal(OIDExtensionAndroidVmAttestation) ||
835837
oid.Equal(OIDExtensionAndroidRkpInfo) {
836838
return true
837839
}

0 commit comments

Comments
 (0)