diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-03-04 22:13:27 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-03-04 22:13:27 +0000 |
commit | 706c20dce4715fd7e7ca506245cbb5a012060492 (patch) | |
tree | a1bed122b76f0b5ba43215a0fc9afc8975e3f92d | |
parent | 0b7d54e4b210ce1d86a85410b2db000da494f5c8 (diff) | |
parent | 1e5b402b24805c2d30336d7269ae8dd9df5d778e (diff) | |
download | RemoteKeyProvisioning-706c20dce4715fd7e7ca506245cbb5a012060492.tar.gz |
Snap for 11526323 from 1e5b402b24805c2d30336d7269ae8dd9df5d778e to simpleperf-releasesimpleperf-release
Change-Id: I54975de51bcab56c6ed8ffa1aec233a3dc622958
-rw-r--r-- | app/TEST_MAPPING | 7 | ||||
-rw-r--r-- | app/tests/avf/Android.bp | 29 | ||||
-rw-r--r-- | app/tests/avf/AndroidManifest.xml | 26 | ||||
-rw-r--r-- | app/tests/avf/AndroidTest.xml | 36 | ||||
-rw-r--r-- | app/tests/avf/src/com/android/avf/rkpdapp/e2etest/AvfIntegrationTest.java | 142 |
5 files changed, 240 insertions, 0 deletions
diff --git a/app/TEST_MAPPING b/app/TEST_MAPPING index 824fc9e..af4013a 100644 --- a/app/TEST_MAPPING +++ b/app/TEST_MAPPING @@ -15,6 +15,13 @@ "keywords": ["internal"] } ], + "avf-postsubmit": [ + { + // TODO(b/325610326): Add this target to presubmit once there is enough + // SLO data for it. + "name": "AvfRkpdAppIntegrationTests" + } + ], "mainline-presubmit": [ { "name": "RkpdAppGoogleUnitTests[com.google.android.rkpd.apex]" diff --git a/app/tests/avf/Android.bp b/app/tests/avf/Android.bp new file mode 100644 index 0000000..b32eed3 --- /dev/null +++ b/app/tests/avf/Android.bp @@ -0,0 +1,29 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test { + name: "AvfRkpdAppIntegrationTests", + srcs: ["src/**/*.java"], + static_libs: [ + "MicrodroidDeviceTestHelper", + "Nene", + "RkpdAppTestUtil", + "androidx.test.ext.junit", + "androidx.test.core", + "androidx.test.rules", + "androidx.work_work-testing", + "compatibility-common-util-devicesidelib", + "platform-test-annotations", + "truth", + ], + platform_apis: true, + test_suites: [ + "general-tests", + "device-tests", + "mcts-rkpd", + "mts-rkpd", + ], + min_sdk_version: "33", + instrumentation_for: "rkpdapp", +} diff --git a/app/tests/avf/AndroidManifest.xml b/app/tests/avf/AndroidManifest.xml new file mode 100644 index 0000000..0924ded --- /dev/null +++ b/app/tests/avf/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?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.avf.rkpdapp.e2etest"> + + <application /> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.rkpdapp" + android:label="AVF rkpd app integration tests" /> +</manifest> diff --git a/app/tests/avf/AndroidTest.xml b/app/tests/avf/AndroidTest.xml new file mode 100644 index 0000000..e57ca1d --- /dev/null +++ b/app/tests/avf/AndroidTest.xml @@ -0,0 +1,36 @@ +<?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="AVF integration tests for the rkpd app."> + <option name="test-suite-tag" value="cts" /> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="AvfRkpdAppIntegrationTests.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.avf.rkpdapp.e2etest" /> + </test> + + <!-- Only run if RKPD mainline module is installed --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="enable" value="true" /> + <option name="mainline-module-package-name" value="com.android.rkpd" /> + </object> +</configuration> diff --git a/app/tests/avf/src/com/android/avf/rkpdapp/e2etest/AvfIntegrationTest.java b/app/tests/avf/src/com/android/avf/rkpdapp/e2etest/AvfIntegrationTest.java new file mode 100644 index 0000000..46386a5 --- /dev/null +++ b/app/tests/avf/src/com/android/avf/rkpdapp/e2etest/AvfIntegrationTest.java @@ -0,0 +1,142 @@ +/* + * 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.avf.rkpdapp.e2etest; + +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.hardware.security.keymint.IRemotelyProvisionedComponent; +import android.os.Process; +import android.os.SystemProperties; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.work.ListenableWorker; +import androidx.work.testing.TestWorkerBuilder; + +import com.android.compatibility.common.util.CddTest; +import com.android.microdroid.test.device.MicrodroidDeviceTestBase; +import com.android.rkpdapp.database.ProvisionedKey; +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 org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.util.concurrent.Executors; + +/** + * End-to-end test for the pVM remote attestation (key provisioning/VM attestation). + * + * <p>To run this test, you need to: + * + * - Have an arm64 device supporting protected VMs. + * - Have a stable network connection on the device. + * - 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(AndroidJUnit4.class) +public class AvfIntegrationTest extends MicrodroidDeviceTestBase { + private static final String SERVICE_NAME = IRemotelyProvisionedComponent.DESCRIPTOR + "/avf"; + + private ProvisionedKeyDao mKeyDao; + private PeriodicProvisioner mProvisioner; + + @Before + public void setUp() throws Exception { + assume().withMessage("AVF key provisioning is not supported on CF.") + .that(isCuttlefish()) + .isFalse(); + 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(); + + 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}); + } + + @After + public void tearDown() throws Exception { + ServiceManagerInterface.setInstances(null); + if (mKeyDao != null) { + mKeyDao.deleteAllKeys(); + } + Settings.clearPreferences(getContext()); + } + + @Test + @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"}) + public void provisioningSucceeds() throws Exception { + assertWithMessage("There should be no keys in the database before provisioning") + .that(mKeyDao.getTotalKeysForIrpc(SERVICE_NAME)) + .isEqualTo(0); + + // Check provisioning succeeds. + assertThat(mProvisioner.doWork()).isEqualTo(ListenableWorker.Result.success()); + int totalUnassignedKeys = mKeyDao.getTotalUnassignedKeysForIrpc(SERVICE_NAME); + assertWithMessage("There should be unassigned keys in the database after provisioning") + .that(totalUnassignedKeys) + .isGreaterThan(0); + + ProvisionedKey attestationKey = + mKeyDao.getKeyForClientAndIrpc(SERVICE_NAME, Process.SYSTEM_UID, Process.myUid()); + assertThat(attestationKey).isNull(); + // Assign a key to a new client. + attestationKey = + mKeyDao.getOrAssignKey( + SERVICE_NAME, Instant.now(), Process.SYSTEM_UID, Process.myUid()); + + // Assert. + assertThat(attestationKey).isNotNull(); + assertThat(attestationKey.irpcHal).isEqualTo(SERVICE_NAME); + assertWithMessage("One key should be assigned") + .that(mKeyDao.getTotalUnassignedKeysForIrpc(SERVICE_NAME)) + .isEqualTo(totalUnassignedKeys - 1); + + // Parsing the certificate chain successfully indicates that the chain is well-formed, + // each certificate is signed by the next one, and the root certificate is self-signed. + X509Certificate[] certs = X509Utils.formatX509Certs(attestationKey.certificateChain); + assertThat(certs.length).isGreaterThan(1); + assertThat(certs[0].getSubjectX500Principal().getName()).contains("O=AVF"); + } +} |