diff options
author | Max Bires <jbires@google.com> | 2022-06-06 18:24:55 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-06-06 18:24:55 +0000 |
commit | ba6eb21232fee7e37bd564331b5b6f3e3cd1d3d5 (patch) | |
tree | 3956827060df2e6572cb776778933950d9352495 | |
parent | cfbc29672faf40a3c3b93d30d34b9d143b5e8205 (diff) | |
parent | 52e981199088a42145c0bf63656bc5524f5f1276 (diff) | |
download | RemoteProvisioner-ba6eb21232fee7e37bd564331b5b6f3e3cd1d3d5.tar.gz |
Test registration status of device directly. am: 52e9811990
Original change: https://android-review.googlesource.com/c/platform/packages/apps/RemoteProvisioner/+/2114495
Change-Id: I66995bee2abab59ef87e32be1c8d9fecb9309619
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
6 files changed, 228 insertions, 7 deletions
diff --git a/src/com/android/remoteprovisioner/CborUtils.java b/src/com/android/remoteprovisioner/CborUtils.java index d3fc3d7..05bd8a4 100644 --- a/src/com/android/remoteprovisioner/CborUtils.java +++ b/src/com/android/remoteprovisioner/CborUtils.java @@ -264,7 +264,8 @@ public class CborUtils { * IRemotelyProvisionedComponent HAL AIDL files. */ public static byte[] buildCertificateRequest(byte[] deviceInfo, byte[] challenge, - byte[] protectedData, byte[] macedKeysToSign) { + byte[] protectedData, byte[] macedKeysToSign, + Map unverifiedDeviceInfo) { // This CBOR library doesn't support adding already serialized CBOR structures into a // CBOR builder. Because of this, we have to first deserialize the provided parameters // back into the library's CBOR object types, and then reserialize them into the @@ -296,17 +297,18 @@ public class CborUtils { return null; } Map verifiedDeviceInfoMap = (Map) dataItems.get(0); - Map unverifiedDeviceInfoMap = new Map(); - unverifiedDeviceInfoMap.put(new UnicodeString("fingerprint"), - new UnicodeString(Build.FINGERPRINT)); + if (unverifiedDeviceInfo.get(new UnicodeString("fingerprint")) == null) { + Log.e(TAG, "UnverifiedDeviceInfo is missing a fingerprint entry"); + return null; + } // Serialize the actual CertificateSigningRequest structure ByteArrayOutputStream baos = new ByteArrayOutputStream(); new CborEncoder(baos).encode(new CborBuilder() .addArray() .addArray() .add(verifiedDeviceInfoMap) - .add(unverifiedDeviceInfoMap) + .add(unverifiedDeviceInfo) .end() .add(challenge) .add(protectedDataArray) @@ -319,4 +321,17 @@ public class CborUtils { return null; } } + + /** + * Produce a CBOR Map object which contains the unverified device information for a certificate + * signing request. + * + * @return the CBOR Map object. + */ + public static Map buildUnverifiedDeviceInfo() { + Map unverifiedDeviceInfo = new Map(); + unverifiedDeviceInfo.put(new UnicodeString("fingerprint"), + new UnicodeString(Build.FINGERPRINT)); + return unverifiedDeviceInfo; + } } diff --git a/src/com/android/remoteprovisioner/Provisioner.java b/src/com/android/remoteprovisioner/Provisioner.java index c259abe..3bd0f90 100644 --- a/src/com/android/remoteprovisioner/Provisioner.java +++ b/src/com/android/remoteprovisioner/Provisioner.java @@ -84,7 +84,8 @@ public class Provisioner { CborUtils.buildCertificateRequest(deviceInfo.deviceInfo, challenge, protectedData.protectedData, - macedKeysToSign); + macedKeysToSign, + CborUtils.buildUnverifiedDeviceInfo()); if (certificateRequest == null) { throw new RemoteProvisioningException(IGenerateRkpKeyService.Status.INTERNAL_ERROR, "Failed to serialize the payload generated by keystore."); diff --git a/tests/unittests/Android.bp b/tests/unittests/Android.bp index 5c81b4b..ae88bc9 100644 --- a/tests/unittests/Android.bp +++ b/tests/unittests/Android.bp @@ -18,6 +18,7 @@ package { android_test { name: "RemoteProvisionerUnitTests", srcs: ["src/**/*.java"], + exclude_srcs: ["src/**/KeyRegisteredTest.java"], static_libs: [ "Nene", "androidx.test.core", @@ -38,6 +39,23 @@ android_test { instrumentation_for: "RemoteProvisioner", } +// Specifically tests to see if the key is registered for the given device under test. +android_test { + name: "RemoteProvisionerRegistrationTest", + srcs: ["src/**/KeyRegisteredTest.java"], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "android.security.remoteprovisioning-java", + "platform-test-annotations", + "cbor-java", + ], + platform_apis: true, + test_config: "AndroidRegistrationTest.xml", + test_suites: ["device-tests"], + instrumentation_for: "RemoteProvisioner", +} + java_import { name: "tink-prebuilt", jars: ["tink-android-1.5.0.jar"], diff --git a/tests/unittests/AndroidRegistrationTest.xml b/tests/unittests/AndroidRegistrationTest.xml new file mode 100644 index 0000000..f01139a --- /dev/null +++ b/tests/unittests/AndroidRegistrationTest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 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="Runs RemoteProvisioner app unit tests."> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MinApiLevelModuleController"> + <option name="min-api-level" value="31" /> + <option name="api-level-prop" value="ro.product.first_api_level" /> + </object> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"> + <option name="force-root" value="true" /> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="RemoteProvisionerRegistrationTest.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.remoteprovisioner.unittest" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="test-filter-dir" value="/data/data/com.android.remoteprovisioner" /> + </test> +</configuration> diff --git a/tests/unittests/src/com/android/remoteprovisioner/unittest/CborUtilsTest.java b/tests/unittests/src/com/android/remoteprovisioner/unittest/CborUtilsTest.java index cc561a8..b112dcb 100644 --- a/tests/unittests/src/com/android/remoteprovisioner/unittest/CborUtilsTest.java +++ b/tests/unittests/src/com/android/remoteprovisioner/unittest/CborUtilsTest.java @@ -18,8 +18,10 @@ package com.android.remoteprovisioner.unittest; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import android.os.Build; import android.platform.test.annotations.Presubmit; import androidx.test.runner.AndroidJUnit4; @@ -375,7 +377,8 @@ public class CborUtilsTest { CborUtils.buildCertificateRequest(deviceInfo, challenge, protectedDataPayload, - macedKeysToSign); + macedKeysToSign, + CborUtils.buildUnverifiedDeviceInfo()); ByteArrayInputStream bais = new ByteArrayInputStream(certReq); List<DataItem> dataItems = new CborDecoder(bais).decode(); assertEquals(1, dataItems.size()); @@ -397,4 +400,14 @@ public class CborUtilsTest { // MacedKeysToSign assertEquals(MajorType.ARRAY, dataItems.get(3).getMajorType()); } + + @Test + public void testBuildUnverifiedDeviceInfo() throws Exception { + Map devInfo = CborUtils.buildUnverifiedDeviceInfo(); + assertEquals("Unverified device info only has one entry.", 1, devInfo.getKeys().size()); + DataItem fingerprint = devInfo.get(new UnicodeString("fingerprint")); + assertNotNull("Device info doesn't contain fingerprint", fingerprint); + assertEquals(MajorType.UNICODE_STRING, fingerprint.getMajorType()); + assertEquals(Build.FINGERPRINT, fingerprint.toString()); + } } diff --git a/tests/unittests/src/com/android/remoteprovisioner/unittest/KeyRegisteredTest.java b/tests/unittests/src/com/android/remoteprovisioner/unittest/KeyRegisteredTest.java new file mode 100644 index 0000000..109d6a4 --- /dev/null +++ b/tests/unittests/src/com/android/remoteprovisioner/unittest/KeyRegisteredTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2022 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.remoteprovisioner.unittest; + +import static android.hardware.security.keymint.SecurityLevel.TRUSTED_ENVIRONMENT; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; + +import android.content.Context; +import android.hardware.security.keymint.DeviceInfo; +import android.hardware.security.keymint.ProtectedData; +import android.os.Build; +import android.os.ServiceManager; +import android.security.IGenerateRkpKeyService.Status; +import android.security.remoteprovisioning.IRemoteProvisioning; +import android.security.remoteprovisioning.ImplInfo; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +import com.android.remoteprovisioner.CborUtils; +import com.android.remoteprovisioner.GeekResponse; +import com.android.remoteprovisioner.ProvisionerMetrics; +import com.android.remoteprovisioner.RemoteProvisioningException; +import com.android.remoteprovisioner.ServerInterface; +import com.android.remoteprovisioner.SettingsManager; +import com.android.remoteprovisioner.SystemInterface; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +import co.nstant.in.cbor.model.Map; +import co.nstant.in.cbor.model.UnicodeString; + +@RunWith(AndroidJUnit4.class) +public class KeyRegisteredTest { + + private static final String SERVICE = "android.security.remoteprovisioning"; + + private static Context sContext; + private static IRemoteProvisioning sBinder; + private static int sCurve; + + @BeforeClass + public static void init() throws Exception { + sContext = ApplicationProvider.getApplicationContext(); + sBinder = + IRemoteProvisioning.Stub.asInterface(ServiceManager.getService(SERVICE)); + assertNotNull(sBinder); + ImplInfo[] info = sBinder.getImplementationInfo(); + for (int i = 0; i < info.length; i++) { + if (info[i].secLevel == TRUSTED_ENVIRONMENT) { + sCurve = info[i].supportedCurve; + break; + } + } + } + + @Before + public void setUp() throws Exception { + sBinder.deleteAllKeys(); + } + + @After + public void tearDown() throws Exception { + sBinder.deleteAllKeys(); + } + + private void requestCerts(int numKeys, int secLevel, byte[] geekChain, byte[] challenge, + IRemoteProvisioning binder, Context context, + ProvisionerMetrics metrics) throws Exception { + DeviceInfo deviceInfo = new DeviceInfo(); + ProtectedData protectedData = new ProtectedData(); + byte[] macedKeysToSign = SystemInterface.generateCsr(SettingsManager.isTestMode(), numKeys, + secLevel, geekChain, challenge, protectedData, deviceInfo, binder, metrics); + String fingerprint = Build.FINGERPRINT; + // The backend should provision test certs if the build isn't a user build. + // Registration status only factors into user builds, so set a debug property that + // will instruct the underlying provisioning code to appear as a user build to the + // backend if it isn't. + if (!Build.TYPE.equals("user")) { + fingerprint = fingerprint.replace("userdebug", "user"); + fingerprint = fingerprint.replace("eng", "user"); + } + Map unverifiedDeviceInfo = new Map(); + unverifiedDeviceInfo.put(new UnicodeString("fingerprint"), + new UnicodeString(fingerprint)); + byte[] certificateRequest = + CborUtils.buildCertificateRequest(deviceInfo.deviceInfo, + challenge, + protectedData.protectedData, + macedKeysToSign, + unverifiedDeviceInfo); + List<byte[]> certChains = ServerInterface.requestSignedCertificates(context, + certificateRequest, challenge, metrics); + } + + @Test + public void testKeyRegisteredTee() throws Exception { + try { + ProvisionerMetrics metrics = ProvisionerMetrics.createScheduledAttemptMetrics(sContext); + int numTestKeys = 1; + sBinder.generateKeyPair(SettingsManager.isTestMode(), TRUSTED_ENVIRONMENT); + GeekResponse geek = ServerInterface.fetchGeek(sContext, metrics); + assertNotNull(geek); + requestCerts(numTestKeys, TRUSTED_ENVIRONMENT, geek.getGeekChain(sCurve), + geek.getChallenge(), sBinder, sContext, metrics); + } catch (RemoteProvisioningException e) { + // Any exception will be a failure here, but specifically call out DEVICE_NOT_REGISTERED + // as a registration failure before throwing whatever other problem may have occurred. + assertNotEquals("Device isn't registered.", + Status.DEVICE_NOT_REGISTERED, e.getErrorCode()); + throw e; + } + } +} |