[attestation_ext] Check attestation extension in e2e test
Bug: 325610326
Test: atest AvfRkpdVmAttestationTestApp
Change-Id: I93d49303d09685609a7c3b975667c523a39d428c
diff --git a/service_vm/test_apk/Android.bp b/service_vm/test_apk/Android.bp
index de731f6..cd992db 100644
--- a/service_vm/test_apk/Android.bp
+++ b/service_vm/test_apk/Android.bp
@@ -57,6 +57,7 @@
static_libs: [
"RkpdAppTestUtil",
"androidx.work_work-testing",
+ "bouncycastle-unbundled",
],
instrumentation_for: "rkpdapp",
// This app is a variation of rkpdapp, with additional permissions to run
diff --git a/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
index e7061e1..2a771f3 100644
--- a/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
+++ b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
@@ -44,6 +44,12 @@
import com.android.virt.vm_attestation.testservice.IAttestationService;
import com.android.virt.vm_attestation.testservice.IAttestationService.SigningResult;
+import org.bouncycastle.asn1.ASN1Boolean;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERUTF8String;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -215,28 +221,46 @@
assertThat(sig.verify(signingResult.signature)).isTrue();
}
- private void checkAvfAttestationExtension(X509Certificate cert, byte[] challenge) {
- byte[] extension = cert.getExtensionValue(AVF_ATTESTATION_EXTENSION_OID);
- assertThat(extension).isNotNull();
- // TODO(b/325610326): Use bouncycastle to parse the extension and check other fields.
- assertWithMessage("The extension should contain the challenge")
- .that(containsSubarray(extension, challenge))
- .isTrue();
+ private void checkAvfAttestationExtension(X509Certificate cert, byte[] challenge)
+ throws Exception {
+ byte[] extensionValue = cert.getExtensionValue(AVF_ATTESTATION_EXTENSION_OID);
+ ASN1OctetString extString = ASN1OctetString.getInstance(extensionValue);
+ ASN1Sequence seq = ASN1Sequence.getInstance(extString.getOctets());
+ // AVF attestation extension should contain 3 elements in the following format:
+ //
+ // AttestationExtension ::= SEQUENCE {
+ // attestationChallenge OCTET_STRING,
+ // isVmSecure BOOLEAN,
+ // vmComponents SEQUENCE OF VmComponent,
+ // }
+ // VmComponent ::= SEQUENCE {
+ // name UTF8String,
+ // securityVersion INTEGER,
+ // codeHash OCTET STRING,
+ // authorityHash OCTET STRING,
+ // }
+ assertThat(seq).hasSize(3);
+
+ ASN1OctetString expectedChallenge = new DEROctetString(challenge);
+ assertThat(seq.getObjectAt(0)).isEqualTo(expectedChallenge);
+ assertWithMessage("The VM should be unsecure as it is debuggable.")
+ .that(seq.getObjectAt(1))
+ .isEqualTo(ASN1Boolean.FALSE);
+ ASN1Sequence vmComponents = ASN1Sequence.getInstance(seq.getObjectAt(2));
+ assertExtensionContainsPayloadApk(vmComponents);
}
- private boolean containsSubarray(byte[] array, byte[] subarray) {
- for (int i = 0; i < array.length - subarray.length + 1; i++) {
- boolean found = true;
- for (int j = 0; j < subarray.length; j++) {
- if (array[i + j] != subarray[j]) {
- found = false;
- break;
- }
- }
- if (found) {
- return true;
+ private void assertExtensionContainsPayloadApk(ASN1Sequence vmComponents) throws Exception {
+ DERUTF8String payloadApkName = new DERUTF8String("apk:" + TEST_APP_PACKAGE_NAME);
+ boolean found = false;
+ for (ASN1Encodable encodable : vmComponents) {
+ ASN1Sequence vmComponent = ASN1Sequence.getInstance(encodable);
+ assertThat(vmComponent).hasSize(4);
+ if (payloadApkName.equals(vmComponent.getObjectAt(0))) {
+ assertWithMessage("Payload APK should not be found twice.").that(found).isFalse();
+ found = true;
}
}
- return false;
+ assertWithMessage("vmComponents should contain the payload APK.").that(found).isTrue();
}
}