[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();
     }
 }