Skip to content

Commit

Permalink
x095util: support VM attestation info
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddrysdale committed Mar 26, 2024
1 parent b520617 commit 71737a1
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 3 deletions.
67 changes: 64 additions & 3 deletions x509util/android.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ var OIDExtensionAndroidAttestation = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 111
// remote key provisioning info.
var OIDExtensionAndroidRkpInfo = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 1, 30}

// OIDExtensionAndroidVmAttestation is the OID value for an X.509 extension that holds
// Android attestation info for a virtual machine.
var OIDExtensionAndroidVmAttestation = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 1, 29, 1}

// AndroidAttestationInfo holds attestation information attached to an Android
// hardware-backed key, describing features of the key and the device that issued
// it. See https://developer.android.com/training/articles/security-key-attestation for
Expand All @@ -48,6 +52,21 @@ type AndroidAttestationInfo struct {
HardwareEnforced AuthorizationList
}

// AndroidVmAttestationInfo holds attestation information attached to an Android virtual
// machine.
type AndroidVmAttestationInfo struct {
AttestationChallenge []byte
IsVmSecure bool
VmComponents []AndroidVmComponent
}

type AndroidVmComponent struct {
Name string
SecurityVersion int64
CodeHash []byte
AuthorityHash []byte
}

func securityLevelToString(lvl asn1.Enumerated) string {
switch lvl {
case 0:
Expand Down Expand Up @@ -151,6 +170,48 @@ func AttestInfoFromCert(cert *x509.Certificate) (*AndroidAttestationInfo, error)
return nil, errors.New("no Android Attestation extension found")
}

// VmInfoFromCert retrieves and parses an Android VM attestation information extension
// from a certificate, if present.
func VmInfoFromCert(cert *x509.Certificate) (*AndroidVmAttestationInfo, error) {
for _, ext := range cert.Extensions {
if ext.Id.Equal(OIDExtensionAndroidVmAttestation) {
var vmInfo AndroidVmAttestationInfo
rest, err := asn1.Unmarshal(ext.Value, &vmInfo)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal attestation info: %v", err)
} else if len(rest) > 0 {
return nil, fmt.Errorf("trailing data (%d bytes) after attestation info", len(rest))
}
return &vmInfo, nil
}
}
return nil, errors.New("no Android VM Attestation extension found")
}

func showAndroidVmAttestation(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(OIDExtensionAndroidVmAttestation, cert.Extensions)
if count == 0 {
return
}
result.WriteString(fmt.Sprintf(" Android VM Information:"))
showCritical(result, critical)
vmInfo, err := VmInfoFromCert(cert)
if err != nil {
result.WriteString(fmt.Sprintf(" Failed to decode VM info: (%s)\n", err))
return
}
showHex(result, " ", "Attestation Challenge", vmInfo.AttestationChallenge)
result.WriteString(fmt.Sprintf(" Is VM Secure: %t\n", vmInfo.IsVmSecure))
result.WriteString(fmt.Sprintf(" Components:\n"))
for _, component := range vmInfo.VmComponents {
result.WriteString(fmt.Sprintf(" Component:\n"))
result.WriteString(fmt.Sprintf(" Name: %s\n", component.Name))
result.WriteString(fmt.Sprintf(" Security Version: %d\n", component.SecurityVersion))
showHex(result, " ", "Code Hash", component.CodeHash)
showHex(result, " ", "Authority Hash", component.AuthorityHash)
}
}

func showAndroidRkpInfo(result *bytes.Buffer, cert *x509.Certificate) {
for _, ext := range cert.Extensions {
if ext.Id.Equal(OIDExtensionAndroidRkpInfo) {
Expand Down Expand Up @@ -270,7 +331,7 @@ func showKeyAuthorizations(buf *bytes.Buffer, auths AuthorizationList, prefix st
buf.WriteString(fmt.Sprintf("%sOS Patchlevel: %d\n", prefix, auths.OsPatchlevel))
}

showOptionalAttestationAppId(buf, prefix, auths.AttestationApplicationId)
showOptionalAttestationAppId(buf, prefix, auths.AttestationApplicationId)
showOptionalHexUtf8(buf, prefix, "Attestation Id Brand", auths.AttestationIdBrand)
showOptionalHexUtf8(buf, prefix, "Attestation Id Device", auths.AttestationIdDevice)
showOptionalHexUtf8(buf, prefix, "Attestation Id Product", auths.AttestationIdProduct)
Expand Down Expand Up @@ -475,13 +536,13 @@ func showHexUtf8(buf *bytes.Buffer, prefix string, name string, val []byte) {
// AndroidAttestationAppId describes an Android application identifier.
type AndroidAttestationAppId struct {
PackageInfoRecords []AndroidPackageInfoRecord `asn1:"set"`
SignatureDigests [][]byte `asn1:"set"`
SignatureDigests [][]byte `asn1:"set"`
}

// AndroidPackageInfoRecord hold a package info record from Android.
type AndroidPackageInfoRecord struct {
PackageName []byte
Version int
Version int
}

func AndroidAppInfoFromData(val []byte) (*AndroidAttestationAppId, error) {
Expand Down
2 changes: 2 additions & 0 deletions x509util/x509util.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ func CertificateToString(cert *x509.Certificate) string {
showCTLogSTHInfo(&result, cert)
showAndroidAttestation(&result, cert)
showAndroidRkpInfo(&result, cert)
showAndroidVmAttestation(&result, cert)

showUnhandledExtensions(&result, cert)
showSignature(&result, cert)
Expand Down Expand Up @@ -832,6 +833,7 @@ func oidAlreadyPrinted(oid asn1.ObjectIdentifier) bool {
oid.Equal(x509.OIDExtensionCTSCT) ||
oid.Equal(x509ext.OIDExtensionCTSTH) ||
oid.Equal(OIDExtensionAndroidAttestation) ||
oid.Equal(OIDExtensionAndroidVmAttestation) ||
oid.Equal(OIDExtensionAndroidRkpInfo) {
return true
}
Expand Down

0 comments on commit 71737a1

Please sign in to comment.