1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.virt.rkpd.vm_attestation.testapp;
18 
19 import static android.system.virtualmachine.VirtualMachineConfig.DEBUG_LEVEL_FULL;
20 
21 import static com.google.common.truth.TruthJUnit.assume;
22 
23 import android.net.ConnectivityManager;
24 import android.net.NetworkCapabilities;
25 import android.net.Network;
26 import android.content.Context;
27 import android.system.virtualmachine.VirtualMachine;
28 import android.system.virtualmachine.VirtualMachineConfig;
29 
30 import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
31 import com.android.virt.vm_attestation.testservice.IAttestationService.SigningResult;
32 import com.android.virt.vm_attestation.util.X509Utils;
33 import android.system.virtualmachine.VirtualMachineManager;
34 
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.junit.runners.Parameterized;
39 
40 import java.security.cert.X509Certificate;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.List;
45 
46 /**
47  * End-to-end test for the pVM remote attestation.
48  *
49  * <p>The test checks the two major steps of the pVM remote attestation:
50  *
51  * <p>1. Key provisioning: The test provisions AVF keys from the RKP server and verifies that the
52  * keys are for AVF.
53  *
54  * <p>2. VM attestation: The test creates a VM with a payload binary that requests to attest the VM,
55  * and then signs a message with the attestation key.
56  *
57  * <p>To run this test, you need to:
58  *
59  * <p>- Have an arm64 device supporting protected VMs.
60  *
61  * <p>- Have a stable network connection on the device.
62  */
63 @RunWith(Parameterized.class)
64 public class RkpdVmAttestationTest extends MicrodroidDeviceTestBase {
65     private static final String TAG = "RkpdVmAttestationTest";
66 
67     private static final String VM_PAYLOAD_PATH = "libvm_attestation_test_payload.so";
68     private static final String MESSAGE = "Hello RKP from AVF!";
69     private static final String TEST_APP_PACKAGE_NAME =
70             "com.android.virt.rkpd.vm_attestation.testapp";
71 
72     @Parameterized.Parameter(0)
73     public String mGki;
74 
75     @Parameterized.Parameters(name = "gki={0}")
params()76     public static Collection<Object[]> params() {
77         List<Object[]> ret = new ArrayList<>();
78         ret.add(new Object[] {null /* use microdroid kernel */});
79         for (String gki : SUPPORTED_GKI_VERSIONS) {
80             ret.add(new Object[] {gki});
81         }
82         return ret;
83     }
84 
85     @Before
setUp()86     public void setUp() throws Exception {
87         assume().withMessage("RKP Integration tests rely on network availability.")
88                 .that(isNetworkConnected(getContext()))
89                 .isTrue();
90         assumeFeatureEnabled(VirtualMachineManager.FEATURE_REMOTE_ATTESTATION);
91         assume().withMessage("Test needs Remote Attestation support")
92                 .that(getVirtualMachineManager().isRemoteAttestationSupported())
93                 .isTrue();
94 
95         if (mGki == null) {
96             // We don't need this permission to use the microdroid kernel.
97             revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
98         } else {
99             // The permission is needed to use the GKI kernel.
100             // Granting the permission is needed as the microdroid kernel test setup
101             // can revoke the permission before the GKI kernel test.
102             grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
103         }
104         prepareTestSetup(true /* protectedVm */, mGki);
105         setMaxPerformanceTaskProfile();
106     }
107 
108     @Test
usingProvisionedKeyForVmAttestationSucceeds()109     public void usingProvisionedKeyForVmAttestationSucceeds() throws Exception {
110         // Arrange.
111         VirtualMachineConfig config =
112                 newVmConfigBuilderWithPayloadBinary(VM_PAYLOAD_PATH)
113                         .setDebugLevel(DEBUG_LEVEL_FULL)
114                         .setVmOutputCaptured(true)
115                         .build();
116         VirtualMachine vm = forceCreateNewVirtualMachine("attestation_with_rkpd_client", config);
117         byte[] challenge = new byte[32];
118         Arrays.fill(challenge, (byte) 0xab);
119 
120         // Act.
121         SigningResult signingResult =
122                 runVmAttestationService(TAG, vm, challenge, MESSAGE.getBytes());
123 
124         // Assert.
125         X509Certificate[] certs =
126                 X509Utils.validateAndParseX509CertChain(signingResult.certificateChain);
127         X509Utils.verifyAvfRelatedCerts(certs, challenge, TEST_APP_PACKAGE_NAME);
128         X509Utils.verifySignature(certs[0], MESSAGE.getBytes(), signingResult.signature);
129     }
130 
isNetworkConnected(Context context)131     private static boolean isNetworkConnected(Context context) {
132         ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
133         Network network = cm.getActiveNetwork();
134         NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
135         return capabilities != null
136                 && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
137                 && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
138     }
139 }
140