diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-05 12:06:59 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-05 12:06:59 +0000 |
commit | 9ffd56af2546cc964f46c81b233055b370be1470 (patch) | |
tree | 05f75e98ae002918c617f301a6598dd4b907ba01 | |
parent | baedfa45d3e3c95b14a9526b3db07bf8cf91084f (diff) | |
parent | b7a5d0973ffc4bb3feb8cd6896199f5aa93ac7cd (diff) | |
download | RemoteKeyProvisioning-aml_art_341411300.tar.gz |
Snap for 11178562 from b7a5d0973ffc4bb3feb8cd6896199f5aa93ac7cd to mainline-art-releaseaml_art_341411300android14-mainline-art-release
Change-Id: I17445a3aa6b50d3e600929d653da676bf9fb6e2b
6 files changed, 145 insertions, 21 deletions
diff --git a/app/src/com/android/rkpdapp/interfaces/ServiceManagerInterface.java b/app/src/com/android/rkpdapp/interfaces/ServiceManagerInterface.java index 38766b1..3ba716c 100644 --- a/app/src/com/android/rkpdapp/interfaces/ServiceManagerInterface.java +++ b/app/src/com/android/rkpdapp/interfaces/ServiceManagerInterface.java @@ -19,8 +19,11 @@ package com.android.rkpdapp.interfaces; import android.annotation.TestApi; import android.hardware.security.keymint.IRemotelyProvisionedComponent; import android.os.ServiceManager; +import android.util.Log; import java.util.Arrays; +import java.util.Map; +import java.util.Objects; /** * Provides convenience methods for interfacing with ServiceManager class and its static functions. @@ -28,33 +31,54 @@ import java.util.Arrays; public class ServiceManagerInterface { private static final String TAG = "RkpdSvcManagerInterface"; private static SystemInterface[] sInstances; + private static Map<String, IRemotelyProvisionedComponent> sBinders; private ServiceManagerInterface() { } - private static SystemInterface createSystemInterface(String serviceName) { + private static SystemInterface tryCreateSystemInterface(IRemotelyProvisionedComponent binder, + String serviceName) { + try { + return new SystemInterface(binder, serviceName); + } catch (UnsupportedOperationException e) { + Log.i(TAG, serviceName + " is unsupported."); + return null; + } + } + + private static IRemotelyProvisionedComponent getBinder(String serviceName) { IRemotelyProvisionedComponent binder = IRemotelyProvisionedComponent.Stub.asInterface( ServiceManager.waitForDeclaredService(serviceName)); if (binder == null) { throw new IllegalArgumentException("Cannot find any implementation for " + serviceName); } - return new SystemInterface(binder, serviceName); + return binder; } /** * Gets all the instances on this device for IRemotelyProvisionedComponent as an array. The * returned values each contain a binder for interacting with the instance. * - * For testing purposes, the instances may be overridden by setInstances + * For testing purposes, the instances may be overridden by either setInstances or setBinders. */ public static SystemInterface[] getAllInstances() { + if (sBinders != null) { + return sBinders.entrySet().stream() + .map(x -> tryCreateSystemInterface(x.getValue(), x.getKey())) + .filter(Objects::nonNull) + .toArray(SystemInterface[]::new); + } if (sInstances != null) { return sInstances; } String irpcInterface = IRemotelyProvisionedComponent.DESCRIPTOR; return Arrays.stream(ServiceManager.getDeclaredInstances(irpcInterface)) - .map(x -> createSystemInterface(irpcInterface + "/" + x)) + .map(x -> { + String serviceName = irpcInterface + "/" + x; + return tryCreateSystemInterface(getBinder(serviceName), serviceName); + }) + .filter(Objects::nonNull) .toArray(SystemInterface[]::new); } @@ -62,10 +86,17 @@ public class ServiceManagerInterface { * Get a specific system interface instance for a given IRemotelyProvisionedComponent. * If the given serviceName does not map to a known IRemotelyProvisionedComponent, this * method throws IllegalArgumentException. + * If the given serviceName is not supported, this method throws UnsupportedOperationException. * - * For testing purposes, the instances may be overridden by setInstances. + * For testing purposes, the instances may be overridden by either setInstances or setBinders. */ public static SystemInterface getInstance(String serviceName) { + if (sBinders != null) { + if (sBinders.containsKey(serviceName)) { + return new SystemInterface(sBinders.get(serviceName), serviceName); + } + throw new IllegalArgumentException("Cannot find any binder for " + serviceName); + } if (sInstances != null) { for (SystemInterface i : sInstances) { if (i.getServiceName().equals(serviceName)) { @@ -75,11 +106,16 @@ public class ServiceManagerInterface { throw new IllegalArgumentException("Cannot find any implementation for " + serviceName); } - return createSystemInterface(serviceName); + return new SystemInterface(getBinder(serviceName), serviceName); } @TestApi public static void setInstances(SystemInterface[] instances) { sInstances = instances; } + + @TestApi + public static void setBinders(Map<String, IRemotelyProvisionedComponent> binders) { + sBinders = binders; + } } diff --git a/app/tests/e2e/src/com/android/rkpdapp/e2etest/KeystoreIntegrationTest.java b/app/tests/e2e/src/com/android/rkpdapp/e2etest/KeystoreIntegrationTest.java index 46bd879..6f46896 100644 --- a/app/tests/e2e/src/com/android/rkpdapp/e2etest/KeystoreIntegrationTest.java +++ b/app/tests/e2e/src/com/android/rkpdapp/e2etest/KeystoreIntegrationTest.java @@ -46,6 +46,7 @@ import com.android.rkpdapp.interfaces.ServiceManagerInterface; import com.android.rkpdapp.interfaces.SystemInterface; import com.android.rkpdapp.provisioner.PeriodicProvisioner; import com.android.rkpdapp.testutil.FakeRkpServer; +import com.android.rkpdapp.testutil.SystemInterfaceSelector; import com.android.rkpdapp.testutil.SystemPropertySetter; import com.android.rkpdapp.utils.Settings; import com.android.rkpdapp.utils.X509Utils; @@ -129,7 +130,8 @@ public class KeystoreIntegrationTest { mKeyStore.load(null); mKeyDao.deleteAllKeys(); - SystemInterface systemInterface = ServiceManagerInterface.getInstance(mServiceName); + SystemInterface systemInterface = + SystemInterfaceSelector.getSystemInterfaceForServiceName(mServiceName); ServiceManagerInterface.setInstances(new SystemInterface[] {systemInterface}); } @@ -228,9 +230,10 @@ public class KeystoreIntegrationTest { // Verify that if the system is set to rkp only, key creation fails when RKP is unable // to get keys. - try { + try (FakeRkpServer server = new FakeRkpServer(FakeRkpServer.Response.INTERNAL_ERROR, + FakeRkpServer.Response.INTERNAL_ERROR)) { Settings.setDeviceConfig(sContext, Settings.EXTRA_SIGNED_KEYS_AVAILABLE_DEFAULT, - Duration.ofDays(1), "bad url"); + Duration.ofDays(1), server.getUrl()); Settings.setMaxRequestTime(sContext, 100); createKeystoreKeyBackedByRkp(); assertWithMessage("Should have gotten a KeyStoreException").fail(); @@ -249,14 +252,17 @@ public class KeystoreIntegrationTest { .that(SystemProperties.getBoolean(getRkpOnlyProp(), false)) .isFalse(); - Settings.setDeviceConfig(sContext, Settings.EXTRA_SIGNED_KEYS_AVAILABLE_DEFAULT, - Duration.ofDays(1), "bad url"); + try (FakeRkpServer server = new FakeRkpServer(FakeRkpServer.Response.INTERNAL_ERROR, + FakeRkpServer.Response.INTERNAL_ERROR)) { + Settings.setDeviceConfig(sContext, Settings.EXTRA_SIGNED_KEYS_AVAILABLE_DEFAULT, + Duration.ofDays(1), server.getUrl()); - createKeystoreKey(); + createKeystoreKey(); - // Ensure the key has a cert, but it didn't come from rkpd. - assertThat(mKeyStore.getCertificateChain(getTestKeyAlias())).isNotEmpty(); - assertThat(mKeyDao.getTotalKeysForIrpc(mServiceName)).isEqualTo(0); + // Ensure the key has a cert, but it didn't come from rkpd. + assertThat(mKeyStore.getCertificateChain(getTestKeyAlias())).isNotEmpty(); + assertThat(mKeyDao.getTotalKeysForIrpc(mServiceName)).isEqualTo(0); + } } @Test @@ -277,8 +283,9 @@ public class KeystoreIntegrationTest { @Test public void testRetryableRkpError() throws Exception { - try { - Settings.setDeviceConfig(sContext, 1, Duration.ofDays(1), "bad url"); + try (FakeRkpServer server = new FakeRkpServer(FakeRkpServer.Response.INTERNAL_ERROR, + FakeRkpServer.Response.INTERNAL_ERROR)) { + Settings.setDeviceConfig(sContext, 1, Duration.ofDays(1), server.getUrl()); Settings.setMaxRequestTime(sContext, 100); createKeystoreKeyBackedByRkp(); Assert.fail("Expected a keystore exception"); diff --git a/app/tests/e2e/src/com/android/rkpdapp/e2etest/RkpdHostTestHelperTests.java b/app/tests/e2e/src/com/android/rkpdapp/e2etest/RkpdHostTestHelperTests.java index 0eb76be..c1762d5 100644 --- a/app/tests/e2e/src/com/android/rkpdapp/e2etest/RkpdHostTestHelperTests.java +++ b/app/tests/e2e/src/com/android/rkpdapp/e2etest/RkpdHostTestHelperTests.java @@ -42,6 +42,7 @@ 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.testutil.TestDatabase; import com.android.rkpdapp.testutil.TestProvisionedKeyDao; import com.android.rkpdapp.utils.Settings; @@ -107,13 +108,15 @@ public class RkpdHostTestHelperTests { mRealDao = RkpdDatabase.getDatabase(sContext).provisionedKeyDao(); mRealDao.deleteAllKeys(); mTestDao = Room.databaseBuilder(sContext, TestDatabase.class, DB_NAME).build().dao(); - SystemInterface systemInterface = ServiceManagerInterface.getInstance(mServiceName); - ServiceManagerInterface.setInstances(new SystemInterface[] {systemInterface}); mProvisioner = TestWorkerBuilder.from( sContext, PeriodicProvisioner.class, Executors.newSingleThreadExecutor()).build(); + + SystemInterface systemInterface = + SystemInterfaceSelector.getSystemInterfaceForServiceName(mServiceName); + ServiceManagerInterface.setInstances(new SystemInterface[] {systemInterface}); } @After diff --git a/app/tests/hosttest/src/com/android/rkpdapp/hosttest/RkpdStatsTests.java b/app/tests/hosttest/src/com/android/rkpdapp/hosttest/RkpdStatsTests.java index 823179d..e7bf7cc 100644 --- a/app/tests/hosttest/src/com/android/rkpdapp/hosttest/RkpdStatsTests.java +++ b/app/tests/hosttest/src/com/android/rkpdapp/hosttest/RkpdStatsTests.java @@ -40,6 +40,7 @@ import java.util.List; @RunWith(DeviceJUnit4ClassRunner.class) public final class RkpdStatsTests extends AtomsHostTest { private static final int NO_HTTP_STATUS_ERROR = 0; + private static final int HTTP_STATUS_SERVER_ERROR = 500; private static final int HTTPS_OK = 200; private static final String RPC_DEFAULT = "android.hardware.security.keymint.IRemotelyProvisionedComponent/default"; @@ -107,7 +108,7 @@ public final class RkpdStatsTests extends AtomsHostTest { assertThat(attempt.getUptime()).isNotEqualTo(UpTime.UPTIME_UNKNOWN); assertThat(attempt.getEnablement()).isEqualTo(Enablement.ENABLED_RKP_ONLY); assertThat(attempt.getStatus()).isEqualTo( - RemoteKeyProvisioningStatus.FETCH_GEEK_IO_EXCEPTION); + RemoteKeyProvisioningStatus.FETCH_GEEK_HTTP_ERROR); final RemoteKeyProvisioningTiming timing = getTimingMetric(data); assertThat(timing).isNotNull(); @@ -125,7 +126,7 @@ public final class RkpdStatsTests extends AtomsHostTest { assertThat(network).isNotNull(); assertThat(network.getTransportType()).isEqualTo(timing.getTransportType()); assertThat(network.getStatus()).isEqualTo(attempt.getStatus()); - assertThat(network.getHttpStatusError()).isEqualTo(NO_HTTP_STATUS_ERROR); + assertThat(network.getHttpStatusError()).isEqualTo(HTTP_STATUS_SERVER_ERROR); } @Test diff --git a/app/tests/unit/src/com/android/rkpdapp/unittest/SystemInterfaceTest.java b/app/tests/unit/src/com/android/rkpdapp/unittest/SystemInterfaceTest.java index cd86af5..c201e11 100644 --- a/app/tests/unit/src/com/android/rkpdapp/unittest/SystemInterfaceTest.java +++ b/app/tests/unit/src/com/android/rkpdapp/unittest/SystemInterfaceTest.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -53,8 +54,10 @@ import com.android.rkpdapp.interfaces.SystemInterface; import com.android.rkpdapp.metrics.ProvisioningAttempt; import com.android.rkpdapp.utils.CborUtils; +import com.google.common.collect.ImmutableMap; import com.google.crypto.tink.subtle.Ed25519Sign; +import org.junit.After; import org.junit.Assert; import org.junit.Assume; import org.junit.Before; @@ -93,6 +96,12 @@ public class SystemInterfaceTest { Assume.assumeTrue(ServiceManager.isDeclared(SERVICE)); } + @After + public void cleanUp() { + ServiceManagerInterface.setBinders(null); + ServiceManagerInterface.setInstances(null); + } + @Test public void testGetDeclaredInstances() { SystemInterface[] instances = ServiceManagerInterface.getAllInstances(); @@ -115,6 +124,30 @@ public class SystemInterfaceTest { } @Test + public void testGetAllInstancesWithUnsupportedService() throws RemoteException { + IRemotelyProvisionedComponent mockedBinder = mock(IRemotelyProvisionedComponent.class); + doThrow(new UnsupportedOperationException()).when(mockedBinder).getHardwareInfo(); + ServiceManagerInterface.setBinders(ImmutableMap.of(SERVICE, mockedBinder)); + + SystemInterface[] instances = ServiceManagerInterface.getAllInstances(); + assertThat(instances).isEmpty(); + } + + @Test + public void testGetInstanceWithUnsupportedService() throws RemoteException { + IRemotelyProvisionedComponent mockedBinder = mock(IRemotelyProvisionedComponent.class); + doThrow(new UnsupportedOperationException()).when(mockedBinder).getHardwareInfo(); + ServiceManagerInterface.setBinders(ImmutableMap.of(SERVICE, mockedBinder)); + + try { + SystemInterface ignored = ServiceManagerInterface.getInstance(SERVICE); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // pass + } + } + + @Test public void testGenerateKey() throws CborException, RkpdException, RemoteException { IRemotelyProvisionedComponent mockedComponent = mock(IRemotelyProvisionedComponent.class); SystemInterface systemInterface = mockSystemInterface(CborUtils.EC_CURVE_25519, diff --git a/app/tests/util/src/com/android/rkpdapp/testutil/SystemInterfaceSelector.java b/app/tests/util/src/com/android/rkpdapp/testutil/SystemInterfaceSelector.java new file mode 100644 index 0000000..0f49691 --- /dev/null +++ b/app/tests/util/src/com/android/rkpdapp/testutil/SystemInterfaceSelector.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 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.rkpdapp.testutil; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.TruthJUnit.assume; + +import android.hardware.security.keymint.IRemotelyProvisionedComponent; + +import com.android.rkpdapp.interfaces.ServiceManagerInterface; +import com.android.rkpdapp.interfaces.SystemInterface; + +public class SystemInterfaceSelector { + /** + * Gets the system interface object for provided service name. + */ + public static SystemInterface getSystemInterfaceForServiceName(String serviceName) { + SystemInterface matchingInterface = null; + for (SystemInterface systemInterface: ServiceManagerInterface.getAllInstances()) { + if (systemInterface.getServiceName().equals(serviceName)) { + matchingInterface = systemInterface; + } + } + if (matchingInterface == null) { + assertThat(serviceName).isEqualTo(IRemotelyProvisionedComponent.DESCRIPTOR + "/avf"); + assume().withMessage("AVF is not supported by this system").fail(); + } + return matchingInterface; + } +} |