[e2e] Add VM attestation test interacting with RKPD

This CL adds an e2e test that interacts with RKPD and the real
RKP server. It checks the two major stages of pVM attestation:

- AVF key provisioning triggered with RKPD.
  The CSRs generated by the RKP VM are sent to the real RKP server
  for attestation.

- VM attestation.
  RKP VM validates the VM requesting attestation and returns a
  certificate chain covering the public key of a key pair owned by
  the VM.

The test checks the final attestation certificate chain and asks
the VM to sign a message with the attestation key, to ensure that
the VM holds the correct key pair. It runs on an RKPD variation
that has permissions to run a VM.

The test target AvfRkpdVmAttestationTestApp is forked from
RkpdAppIntegrationTests with additional setup to check VM
attestation. It will run on a real device in avf-presubmit in the
future as VM attestation is not supported on cuttlefish.

The test has been added to avf busytown config in cl/614975596.

Bug: 325610326
Test: atest AvfRkpdVmAttestationTestApp
Change-Id: Ia6f52d60327be706c6c0c439ed59255358379b13
diff --git a/TEST_MAPPING b/TEST_MAPPING
index ec9042c..5b0c000 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -62,6 +62,9 @@
       // TODO(b/325610326): Add this target to presubmit once there is enough
       // SLO data for it.
       "name": "AvfRkpdAppIntegrationTests"
+    },
+    {
+      "name": "AvfRkpdVmAttestationTestApp"
     }
   ],
   "postsubmit": [
diff --git a/service_vm/test_apk/Android.bp b/service_vm/test_apk/Android.bp
index 8f5fb41..de731f6 100644
--- a/service_vm/test_apk/Android.bp
+++ b/service_vm/test_apk/Android.bp
@@ -2,12 +2,11 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-android_test {
-    name: "VmAttestationTestApp",
+java_defaults {
+    name: "vm_attestation_testapp_defaults",
     test_suites: [
         "general-tests",
     ],
-    srcs: ["src/java/**/*.java"],
     static_libs: [
         "MicrodroidDeviceTestHelper",
         "androidx.test.runner",
@@ -19,7 +18,12 @@
     jni_uses_platform_apis: true,
     use_embedded_native_libs: true,
     sdk_version: "test_current",
-    compile_multilib: "first",
+}
+
+android_test {
+    name: "VmAttestationTestApp",
+    srcs: ["src/java/com/android/virt/vm_attestation/testapp/*.java"],
+    defaults: ["vm_attestation_testapp_defaults"],
 }
 
 rust_defaults {
@@ -41,4 +45,21 @@
 rust_ffi {
     name: "libvm_attestation_test_payload",
     defaults: ["vm_attestation_test_payload_defaults"],
+    visibility: [":__subpackages__"],
+}
+
+android_test {
+    name: "AvfRkpdVmAttestationTestApp",
+    srcs: ["src/java/com/android/virt/rkpd/vm_attestation/testapp/*.java"],
+    defaults: ["vm_attestation_testapp_defaults"],
+    manifest: "AndroidManifest.rkpd.xml",
+    test_config: "AndroidTest.rkpd.xml",
+    static_libs: [
+        "RkpdAppTestUtil",
+        "androidx.work_work-testing",
+    ],
+    instrumentation_for: "rkpdapp",
+    // This app is a variation of rkpdapp, with additional permissions to run
+    // a VM. It is defined in packages/modules/RemoteKeyProvisioning.
+    data: [":avf-rkpdapp"],
 }
diff --git a/service_vm/test_apk/AndroidManifest.rkpd.xml b/service_vm/test_apk/AndroidManifest.rkpd.xml
new file mode 100644
index 0000000..6ecc5a9
--- /dev/null
+++ b/service_vm/test_apk/AndroidManifest.rkpd.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.virt.rkpd.vm_attestation.testapp">
+
+    <instrumentation
+            android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.rkpdapp"
+            android:label="AVF rkpd app integration tests" />
+</manifest>
diff --git a/service_vm/test_apk/AndroidTest.rkpd.xml b/service_vm/test_apk/AndroidTest.rkpd.xml
new file mode 100644
index 0000000..2c0380c
--- /dev/null
+++ b/service_vm/test_apk/AndroidTest.rkpd.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="VM attestation integration tests with the rkpd app.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+
+    <!-- Need to disable SELinux policy to allow com.android.rkpdapp to run a VM. -->
+    <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="test-file-name" value="AvfRkpdVmAttestationTestApp.apk" />
+        <option name="test-file-name" value="avf-rkpdapp.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.virt.rkpd.vm_attestation.testapp" />
+    </test>
+</configuration>
diff --git a/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl b/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl
index 94a7b8d..34c8549 100644
--- a/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl
+++ b/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl
@@ -21,7 +21,31 @@
     const int PORT = 5679;
 
     /**
-     * Requests attestation for testing.
+     * The result of signing a message with the attested key.
+     */
+    parcelable SigningResult {
+        /** The DER-encoded ECDSA signature of the message. */
+        byte[] signature;
+
+        /** The DER-encoded attestation X509 certificate chain. */
+        byte[] certificateChain;
+    }
+
+    /**
+     * Requests attestation with {@link AVmPayload_requestAttestation} API and signs the
+     * given message with the attested key.
+     *
+     * The remotely provisioned keys are retrieved from RKPD and are provisioned from the
+     * real RKP server.
+     *
+     * @param challenge the challenge to include in the attestation output.
+     * @param message the message to sign.
+     * @return the result of signing the message with the attested key.
+     */
+    SigningResult signWithAttestationKey(in byte[] challenge, in byte[] message);
+
+    /**
+     * Requests attestation for testing with {@link AVmPayload_requestAttestationForTesting} API.
      *
      * A fake key pair should be provisioned with the call to
      * {@link VirtualMachine#enableTestAttestation()} before calling this method.
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
new file mode 100644
index 0000000..e7061e1
--- /dev/null
+++ b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.virt.rkpd.vm_attestation.testapp;
+
+import static android.system.virtualmachine.VirtualMachineConfig.DEBUG_LEVEL_FULL;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static com.google.common.truth.TruthJUnit.assume;
+
+import android.content.Context;
+import android.hardware.security.keymint.IRemotelyProvisionedComponent;
+import android.os.SystemProperties;
+import android.system.virtualmachine.VirtualMachine;
+import android.system.virtualmachine.VirtualMachineConfig;
+
+import androidx.work.ListenableWorker;
+import androidx.work.testing.TestWorkerBuilder;
+
+import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
+import com.android.rkpdapp.database.ProvisionedKeyDao;
+import com.android.rkpdapp.database.RkpdDatabase;
+import com.android.rkpdapp.interfaces.ServerInterface;
+import com.android.rkpdapp.interfaces.ServiceManagerInterface;
+import com.android.rkpdapp.interfaces.SystemInterface;
+import com.android.rkpdapp.provisioner.PeriodicProvisioner;
+import com.android.rkpdapp.testutil.SystemInterfaceSelector;
+import com.android.rkpdapp.utils.Settings;
+import com.android.rkpdapp.utils.X509Utils;
+import com.android.virt.vm_attestation.testservice.IAttestationService;
+import com.android.virt.vm_attestation.testservice.IAttestationService.SigningResult;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.security.Signature;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+
+/**
+ * End-to-end test for the pVM remote attestation.
+ *
+ * <p>The test checks the two major steps of the pVM remote attestation:
+ *
+ * <p>1. Key provisioning: The test provisions AVF keys from the RKP server and verifies that the
+ * keys are for AVF.
+ *
+ * <p>2. VM attestation: The test creates a VM with a payload binary that requests to attest the VM,
+ * and then signs a message with the attestation key.
+ *
+ * <p>To run this test, you need to:
+ *
+ * <p>- Have an arm64 device supporting protected VMs.
+ *
+ * <p>- Have a stable network connection on the device.
+ *
+ * <p>- Have the RKP server hostname configured in the device. If not, you can set it using: $ adb
+ * shell setprop remote_provisioning.hostname remoteprovisioning.googleapis.com
+ */
+@RunWith(Parameterized.class)
+public class RkpdVmAttestationTest extends MicrodroidDeviceTestBase {
+    private static final String TAG = "RkpdVmAttestationTest";
+    private static final String AVF_ATTESTATION_EXTENSION_OID = "1.3.6.1.4.1.11129.2.1.29.1";
+    private static final String SERVICE_NAME = IRemotelyProvisionedComponent.DESCRIPTOR + "/avf";
+    private static final String VM_PAYLOAD_PATH = "libvm_attestation_test_payload.so";
+    private static final String MESSAGE = "Hello RKP from AVF!";
+    private static final String TEST_APP_PACKAGE_NAME =
+            "com.android.virt.rkpd.vm_attestation.testapp";
+
+    private ProvisionedKeyDao mKeyDao;
+    private PeriodicProvisioner mProvisioner;
+
+    @Parameterized.Parameter(0)
+    public String mGki;
+
+    @Parameterized.Parameters(name = "gki={0}")
+    public static Collection<Object[]> params() {
+        List<Object[]> ret = new ArrayList<>();
+        ret.add(new Object[] {null /* use microdroid kernel */});
+        for (String gki : SUPPORTED_GKI_VERSIONS) {
+            ret.add(new Object[] {gki});
+        }
+        return ret;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        assume().withMessage("The RKP server hostname is not configured -- assume RKP disabled.")
+                .that(SystemProperties.get("remote_provisioning.hostname"))
+                .isNotEmpty();
+        assume().withMessage("RKP Integration tests rely on network availability.")
+                .that(ServerInterface.isNetworkConnected(getContext()))
+                .isTrue();
+        // TODO(b/329652894): Assume that pVM remote attestation feature is supported.
+
+        prepareTestSetup(true /* protectedVm */, mGki);
+
+        Settings.clearPreferences(getContext());
+        mKeyDao = RkpdDatabase.getDatabase(getContext()).provisionedKeyDao();
+        mKeyDao.deleteAllKeys();
+
+        mProvisioner =
+                TestWorkerBuilder.from(
+                                getContext(),
+                                PeriodicProvisioner.class,
+                                Executors.newSingleThreadExecutor())
+                        .build();
+
+        SystemInterface systemInterface =
+                SystemInterfaceSelector.getSystemInterfaceForServiceName(SERVICE_NAME);
+        ServiceManagerInterface.setInstances(new SystemInterface[] {systemInterface});
+
+        setMaxPerformanceTaskProfile();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        ServiceManagerInterface.setInstances(null);
+        if (mKeyDao != null) {
+            mKeyDao.deleteAllKeys();
+        }
+        Settings.clearPreferences(getContext());
+    }
+
+    @Test
+    public void usingProvisionedKeyForVmAttestationSucceeds() throws Exception {
+        // Provision keys.
+        assertThat(mProvisioner.doWork()).isEqualTo(ListenableWorker.Result.success());
+        assertThat(mKeyDao.getTotalUnassignedKeysForIrpc(SERVICE_NAME)).isGreaterThan(0);
+
+        // Arrange.
+        Context ctx = getContext();
+        Context otherAppCtx = ctx.createPackageContext(TEST_APP_PACKAGE_NAME, 0);
+        VirtualMachineConfig config =
+                new VirtualMachineConfig.Builder(otherAppCtx)
+                        .setProtectedVm(true)
+                        .setDebugLevel(DEBUG_LEVEL_FULL)
+                        .setPayloadBinaryName(VM_PAYLOAD_PATH)
+                        .setVmOutputCaptured(true)
+                        .build();
+        VirtualMachine vm = forceCreateNewVirtualMachine("attestation_with_rkpd_client", config);
+        byte[] challenge = new byte[32];
+        Arrays.fill(challenge, (byte) 0xab);
+
+        // Act.
+        CompletableFuture<Exception> exception = new CompletableFuture<>();
+        CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
+        CompletableFuture<SigningResult> signingResultFuture = new CompletableFuture<>();
+        VmEventListener listener =
+                new VmEventListener() {
+                    @Override
+                    public void onPayloadReady(VirtualMachine vm) {
+                        payloadReady.complete(true);
+                        try {
+                            IAttestationService service =
+                                    IAttestationService.Stub.asInterface(
+                                            vm.connectToVsockServer(IAttestationService.PORT));
+                            signingResultFuture.complete(
+                                    service.signWithAttestationKey(challenge, MESSAGE.getBytes()));
+                        } catch (Exception e) {
+                            exception.complete(e);
+                        } finally {
+                            forceStop(vm);
+                        }
+                    }
+                };
+        listener.runToFinish(TAG, vm);
+
+        // Assert.
+        assertThat(payloadReady.getNow(false)).isTrue();
+        assertThat(exception.getNow(null)).isNull();
+        SigningResult signingResult = signingResultFuture.getNow(null);
+        assertThat(signingResult).isNotNull();
+
+        // Parsing the certificate chain successfully indicates that the certificate
+        // chain is valid, that each certificate is signed by the next one and the last
+        // one is self-signed.
+        X509Certificate[] certs = X509Utils.formatX509Certs(signingResult.certificateChain);
+        assertThat(certs.length).isGreaterThan(2);
+        assertWithMessage("The first certificate should be generated in the RKP VM")
+                .that(certs[0].getSubjectX500Principal().getName())
+                .isEqualTo("CN=Android Protected Virtual Machine Key");
+        checkAvfAttestationExtension(certs[0], challenge);
+        assertWithMessage("The second certificate should contain AVF in the subject")
+                .that(certs[1].getSubjectX500Principal().getName())
+                .contains("O=AVF");
+
+        // Verify the signature using the public key from the leaf certificate generated
+        // in the RKP VM.
+        Signature sig = Signature.getInstance("SHA256withECDSA");
+        sig.initVerify(certs[0].getPublicKey());
+        sig.update(MESSAGE.getBytes());
+        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 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;
+            }
+        }
+        return false;
+    }
+}
diff --git a/service_vm/test_apk/src/native/main.rs b/service_vm/test_apk/src/native/main.rs
index 199b45c..a04fb1f 100644
--- a/service_vm/test_apk/src/native/main.rs
+++ b/service_vm/test_apk/src/native/main.rs
@@ -18,7 +18,7 @@
 use avflog::LogResult;
 use com_android_virt_vm_attestation_testservice::{
     aidl::com::android::virt::vm_attestation::testservice::IAttestationService::{
-        BnAttestationService, IAttestationService, PORT,
+        BnAttestationService, IAttestationService, SigningResult::SigningResult, PORT,
     },
     binder::{self, unstable_api::AsNative, BinderFeatures, Interface, IntoBinderResult, Strong},
 };
@@ -34,7 +34,7 @@
     AIBinder, AVmAttestationResult, AVmAttestationResult_free,
     AVmAttestationResult_getCertificateAt, AVmAttestationResult_getCertificateCount,
     AVmAttestationResult_getPrivateKey, AVmAttestationResult_sign, AVmAttestationStatus,
-    AVmAttestationStatus_toString, AVmPayload_notifyPayloadReady,
+    AVmAttestationStatus_toString, AVmPayload_notifyPayloadReady, AVmPayload_requestAttestation,
     AVmPayload_requestAttestationForTesting, AVmPayload_runVsockRpcServer,
 };
 
@@ -89,13 +89,8 @@
 
 impl IAttestationService for AttestationService {
     fn requestAttestationForTesting(&self) -> binder::Result<()> {
-        // The data below is only a placeholder generated randomly with urandom
-        let challenge = &[
-            0x6c, 0xad, 0x52, 0x50, 0x15, 0xe7, 0xf4, 0x1d, 0xa5, 0x60, 0x7e, 0xd2, 0x7d, 0xf1,
-            0x51, 0x67, 0xc3, 0x3e, 0x73, 0x9b, 0x30, 0xbd, 0x04, 0x20, 0x2e, 0xde, 0x3b, 0x1d,
-            0xc8, 0x07, 0x11, 0x7b,
-        ];
-        let res = AttestationResult::request_attestation(challenge)
+        const CHALLENGE: &[u8] = &[0xaa; 32];
+        let res = AttestationResult::request_attestation_for_testing(CHALLENGE)
             .map_err(|e| anyhow!("Unexpected status: {:?}", status_to_cstr(e)))
             .with_log()
             .or_service_specific_exception(-1)?;
@@ -103,6 +98,21 @@
         Ok(())
     }
 
+    fn signWithAttestationKey(
+        &self,
+        challenge: &[u8],
+        message: &[u8],
+    ) -> binder::Result<SigningResult> {
+        let res = AttestationResult::request_attestation(challenge)
+            .map_err(|e| anyhow!("Unexpected status: {:?}", status_to_cstr(e)))
+            .with_log()
+            .or_service_specific_exception(-1)?;
+        let certificate_chain =
+            res.certificate_chain().with_log().or_service_specific_exception(-1)?;
+        let signature = res.sign(message).with_log().or_service_specific_exception(-1)?;
+        Ok(SigningResult { certificateChain: certificate_chain, signature })
+    }
+
     fn validateAttestationResult(&self) -> binder::Result<()> {
         // TODO(b/191073073): Returns the attestation result to the host for validation.
         self.res.lock().unwrap().as_ref().unwrap().log().or_service_specific_exception(-1)
@@ -116,7 +126,9 @@
 unsafe impl Send for AttestationResult {}
 
 impl AttestationResult {
-    fn request_attestation(challenge: &[u8]) -> result::Result<Self, AVmAttestationStatus> {
+    fn request_attestation_for_testing(
+        challenge: &[u8],
+    ) -> result::Result<Self, AVmAttestationStatus> {
         let mut res: *mut AVmAttestationResult = ptr::null_mut();
         // SAFETY: It is safe as we only read the challenge within its bounds and the
         // function does not retain any reference to it.
@@ -136,11 +148,31 @@
         }
     }
 
-    fn certificate_chain(&self) -> Result<Vec<Box<[u8]>>> {
+    fn request_attestation(challenge: &[u8]) -> result::Result<Self, AVmAttestationStatus> {
+        let mut res: *mut AVmAttestationResult = ptr::null_mut();
+        // SAFETY: It is safe as we only read the challenge within its bounds and the
+        // function does not retain any reference to it.
+        let status = unsafe {
+            AVmPayload_requestAttestation(
+                challenge.as_ptr() as *const c_void,
+                challenge.len(),
+                &mut res,
+            )
+        };
+        if status == AVmAttestationStatus::ATTESTATION_OK {
+            info!("Attestation succeeds. Status: {:?}", status_to_cstr(status));
+            let res = NonNull::new(res).expect("The attestation result is null");
+            Ok(Self(res))
+        } else {
+            Err(status)
+        }
+    }
+
+    fn certificate_chain(&self) -> Result<Vec<u8>> {
         let num_certs = get_certificate_count(self.as_ref());
-        let mut certs = Vec::with_capacity(num_certs);
+        let mut certs = Vec::new();
         for i in 0..num_certs {
-            certs.push(get_certificate_at(self.as_ref(), i)?);
+            certs.extend(get_certificate_at(self.as_ref(), i)?.iter());
         }
         Ok(certs)
     }
@@ -149,7 +181,7 @@
         get_private_key(self.as_ref())
     }
 
-    fn sign(&self, message: &[u8]) -> Result<Box<[u8]>> {
+    fn sign(&self, message: &[u8]) -> Result<Vec<u8>> {
         sign_with_attested_key(self.as_ref(), message)
     }
 
@@ -231,7 +263,7 @@
     Ok(private_key.into_boxed_slice())
 }
 
-fn sign_with_attested_key(res: &AVmAttestationResult, message: &[u8]) -> Result<Box<[u8]>> {
+fn sign_with_attested_key(res: &AVmAttestationResult, message: &[u8]) -> Result<Vec<u8>> {
     // SAFETY: The result is returned by `AVmPayload_requestAttestation` and should be valid
     // before getting freed.
     let size = unsafe {
@@ -258,7 +290,7 @@
     };
     ensure!(size <= signature.len());
     signature.truncate(size);
-    Ok(signature.into_boxed_slice())
+    Ok(signature)
 }
 
 fn status_to_cstr(status: AVmAttestationStatus) -> &'static CStr {