1 /* 2 * Copyright (C) 2015 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.cts.deviceandprofileowner; 18 19 import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import android.app.admin.DevicePolicyManager; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.os.Build; 30 import android.os.Process; 31 import android.security.KeyChainException; 32 import android.test.MoreAsserts; 33 34 import com.android.cts.devicepolicy.TestCertificates; 35 36 import java.io.ByteArrayInputStream; 37 import java.io.IOException; 38 import java.security.GeneralSecurityException; 39 import java.security.KeyStore; 40 import java.security.KeyStoreException; 41 import java.security.cert.Certificate; 42 import java.security.cert.CertificateFactory; 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.concurrent.Semaphore; 46 import java.util.concurrent.TimeUnit; 47 48 /** 49 * Exercise delegated cert installer APIs in {@link DevicePolicyManager} by setting the test app 50 * (CtsCertInstallerApp) as a delegated cert installer and then asking it to invoke various 51 * cert-related APIs. The expected certificate changes are validated both remotely and locally. 52 */ 53 public class DelegatedCertInstallerTest extends BaseDeviceAdminTest { 54 55 private static final String CERT_INSTALLER_PACKAGE = "com.android.cts.certinstaller"; 56 private static final String NOT_EXIST_CERT_INSTALLER_PACKAGE 57 = "com.android.cts.certinstaller.not_exist"; 58 59 private static final String ACTION_INSTALL_CERT = "com.android.cts.certinstaller.install_cert"; 60 private static final String ACTION_REMOVE_CERT = "com.android.cts.certinstaller.remove_cert"; 61 private static final String ACTION_VERIFY_CERT = "com.android.cts.certinstaller.verify_cert"; 62 private static final String ACTION_INSTALL_KEYPAIR = 63 "com.android.cts.certinstaller.install_keypair"; 64 private static final String ACTION_CERT_OPERATION_DONE = "com.android.cts.certinstaller.done"; 65 private static final String ACTION_READ_ENROLLMENT_SPECIFIC_ID = 66 "com.android.cts.certinstaller.read_esid"; 67 68 private static final String EXTRA_CERT_DATA = "extra_cert_data"; 69 private static final String EXTRA_KEY_DATA = "extra_key_data"; 70 private static final String EXTRA_KEY_ALIAS = "extra_key_alias"; 71 private static final String EXTRA_RESULT_VALUE = "extra_result_value"; 72 private static final String EXTRA_RESULT_EXCEPTION = "extra_result_exception"; 73 // package name of receiver has to be specified explicitly as the receiver is registered in 74 // manifest 75 private static final ComponentName CERT_INSTALLER_COMPONENT = new ComponentName( 76 CERT_INSTALLER_PACKAGE, "com.android.cts.certinstaller.CertInstallerReceiver"); 77 78 private static final List<String> CERT_INSTALL_SCOPES = Arrays.asList(DELEGATION_CERT_INSTALL); 79 80 private volatile boolean mReceivedResult; 81 private volatile Exception mReceivedException; 82 private Semaphore mAvailableResultSemaphore; 83 84 private final BroadcastReceiver receiver = new BroadcastReceiver() { 85 @Override 86 public void onReceive(Context context, Intent intent) { 87 if (ACTION_CERT_OPERATION_DONE.equals(intent.getAction())) { 88 synchronized (DelegatedCertInstallerTest.this) { 89 mReceivedResult = intent.getBooleanExtra(EXTRA_RESULT_VALUE, false); 90 mReceivedException = 91 (Exception) intent.getSerializableExtra(EXTRA_RESULT_EXCEPTION); 92 mAvailableResultSemaphore.release(); 93 } 94 } 95 } 96 }; 97 98 @Override setUp()99 public void setUp() throws Exception { 100 super.setUp(); 101 102 mAvailableResultSemaphore = new Semaphore(0); 103 mReceivedResult = false; 104 mReceivedException = null; 105 IntentFilter filter = new IntentFilter(); 106 filter.addAction(ACTION_CERT_OPERATION_DONE); 107 mContext.registerReceiver(receiver, filter); 108 } 109 110 @Override tearDown()111 public void tearDown() throws Exception { 112 mContext.unregisterReceiver(receiver); 113 mDevicePolicyManager.uninstallCaCert(ADMIN_RECEIVER_COMPONENT, 114 TestCertificates.TEST_CA.getBytes()); 115 // Installed private key pair will be removed once the lockscreen password is cleared, 116 // which is done in the hostside test. 117 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null); 118 super.tearDown(); 119 } 120 testCaCertsOperations()121 public void testCaCertsOperations() throws InterruptedException, GeneralSecurityException, 122 KeyStoreException, IOException { 123 final byte[] cert = TestCertificates.TEST_CA.getBytes(); 124 final Certificate caCert = CertificateFactory.getInstance("X.509") 125 .generateCertificate(new ByteArrayInputStream(cert)); 126 127 128 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, 129 CERT_INSTALLER_PACKAGE); 130 assertEquals(CERT_INSTALLER_PACKAGE, 131 mDevicePolicyManager.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)); 132 133 // Exercise installCaCert() 134 KeyStore keyStore = KeyStore.getInstance("AndroidCAStore"); 135 keyStore.load(null, null); 136 assertNull(keyStore.getCertificateAlias(caCert)); 137 installCaCert(cert); 138 assertResult("installCaCert", true); 139 assertTrue("Certificate is not installed properly", mDevicePolicyManager.hasCaCertInstalled( 140 ADMIN_RECEIVER_COMPONENT, cert)); 141 142 // Exercise getInstalledCaCerts() 143 verifyCaCert(cert); 144 assertResult("getInstalledCaCerts()", true); 145 146 // Verify that the CA cert was marked as installed by the Device Owner / Profile Owner. 147 final String alias = keyStore.getCertificateAlias(caCert); 148 assertNotNull(alias); 149 verifyOwnerInstalledStatus(alias, true); 150 151 // Exercise uninstallCaCert() 152 removeCaCert(cert); 153 assertResult("uninstallCaCert()", true); 154 assertFalse("Certificate is not removed properly", mDevicePolicyManager.hasCaCertInstalled( 155 ADMIN_RECEIVER_COMPONENT, cert)); 156 157 // Verify that the CA cert is no longer reported as installed by the Device Owner / Profile 158 // Owner. 159 verifyOwnerInstalledStatus(alias, false); 160 161 // Clear delegated cert installer. 162 // Tests after this are expected to fail. 163 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null); 164 165 installCaCert(cert); 166 assertResult("installCaCert", false); 167 } 168 testInstallKeyPair()169 public void testInstallKeyPair() throws InterruptedException, KeyChainException { 170 final String alias = "delegated-cert-installer-test-key"; 171 172 // Clear delegated cert installer. 173 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null); 174 // The app is not the cert installer , it shouldn't have have privilege to call 175 // installKeyPair(). 176 installKeyPair(TestCertificates.TEST_KEY, TestCertificates.TEST_CERT, alias); 177 assertResult("installKeyPair", false); 178 179 // Set the app to be cert installer. 180 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, 181 CERT_INSTALLER_PACKAGE); 182 assertEquals(CERT_INSTALLER_PACKAGE, 183 mDevicePolicyManager.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)); 184 185 // Exercise installKeyPair() 186 installKeyPair(TestCertificates.TEST_KEY, TestCertificates.TEST_CERT, alias); 187 assertResult("installKeyPair", true); 188 } 189 190 /** 191 * If DPC is targeting N+, @{link IllegalArgumentException } should be thrown if the package 192 * is missing. 193 */ testSetNotExistCertInstallerPackage()194 public void testSetNotExistCertInstallerPackage() throws Exception { 195 boolean shouldThrowException = getTargetApiLevel() >= Build.VERSION_CODES.N; 196 try { 197 mDevicePolicyManager.setCertInstallerPackage( 198 ADMIN_RECEIVER_COMPONENT, NOT_EXIST_CERT_INSTALLER_PACKAGE); 199 if (shouldThrowException) { 200 fail("Did not throw IllegalArgumentException"); 201 } 202 } catch (IllegalArgumentException ex) { 203 if (!shouldThrowException) { 204 fail("Should not throw exception"); 205 } 206 MoreAsserts.assertContainsRegex("is not installed on the current user", 207 ex.getMessage()); 208 } 209 if (!shouldThrowException) { 210 assertTrue("Cert install delegate was not set on uninstalled package", 211 NOT_EXIST_CERT_INSTALLER_PACKAGE.equals( 212 mDevicePolicyManager 213 .getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT))); 214 } 215 } 216 testSettingDelegatedCertInstallerAPICompatibility_oldSetNewGet()217 public void testSettingDelegatedCertInstallerAPICompatibility_oldSetNewGet() { 218 // Set a delegated cert installer using the deprecated API and verify that the same 219 // package is considered as the delegated cert installer using the new API. 220 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, 221 CERT_INSTALLER_PACKAGE); 222 assertThat(mDevicePolicyManager.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)) 223 .isEqualTo(CERT_INSTALLER_PACKAGE); 224 assertThat(mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT, 225 DELEGATION_CERT_INSTALL)).containsExactly(CERT_INSTALLER_PACKAGE); 226 227 // Remove a delegate using the old API, make sure no delegates are found using 228 // the new API. 229 mDevicePolicyManager.setCertInstallerPackage(ADMIN_RECEIVER_COMPONENT, null); 230 assertThat(mDevicePolicyManager.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)).isNull(); 231 assertThat(mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT, 232 DELEGATION_CERT_INSTALL)).isEmpty(); 233 } 234 testSettingDelegatedCertInstallerAPICompatibility_newSetOldGet()235 public void testSettingDelegatedCertInstallerAPICompatibility_newSetOldGet() { 236 // Set a delegate using the new API, verify that the deprecated API returns the same 237 // delegate. 238 setDelegatedScopes(CERT_INSTALLER_PACKAGE, CERT_INSTALL_SCOPES); 239 assertThat(mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT, 240 DELEGATION_CERT_INSTALL)).containsExactly(CERT_INSTALLER_PACKAGE); 241 assertThat(mDevicePolicyManager.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)) 242 .isEqualTo(CERT_INSTALLER_PACKAGE); 243 244 // Remove the delegate using the new API, verify that the deprecated API returns null 245 // as the current delegated cert installer. 246 setDelegatedScopes(CERT_INSTALLER_PACKAGE, Arrays.asList()); 247 assertThat(mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT, 248 DELEGATION_CERT_INSTALL)).isEmpty(); 249 assertThat(mDevicePolicyManager.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)).isNull(); 250 } 251 testCanReadEnrollmentSpecificId()252 public void testCanReadEnrollmentSpecificId() throws InterruptedException { 253 // Set the organization ID only if not already set, to avoid potential conflict 254 // with other tests. 255 if (mDevicePolicyManager.getEnrollmentSpecificId().isEmpty()) { 256 mDevicePolicyManager.setOrganizationId("SOME_ID"); 257 } 258 setDelegatedScopes(CERT_INSTALLER_PACKAGE, CERT_INSTALL_SCOPES); 259 260 readEnrollmentId(); 261 assertResult("testCanReadEnrollmentSpecificId", true); 262 } 263 installCaCert(byte[] cert)264 private void installCaCert(byte[] cert) { 265 Intent intent = new Intent(); 266 intent.setAction(ACTION_INSTALL_CERT); 267 intent.setComponent(CERT_INSTALLER_COMPONENT); 268 intent.putExtra(EXTRA_CERT_DATA, cert); 269 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 270 mContext.sendBroadcast(intent); 271 } 272 removeCaCert(byte[] cert)273 private void removeCaCert(byte[] cert) { 274 Intent intent = new Intent(); 275 intent.setAction(ACTION_REMOVE_CERT); 276 intent.setComponent(CERT_INSTALLER_COMPONENT); 277 intent.putExtra(EXTRA_CERT_DATA, cert); 278 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 279 mContext.sendBroadcast(intent); 280 } 281 verifyCaCert(byte[] cert)282 private void verifyCaCert(byte[] cert) { 283 Intent intent = new Intent(); 284 intent.setAction(ACTION_VERIFY_CERT); 285 intent.setComponent(CERT_INSTALLER_COMPONENT); 286 intent.putExtra(EXTRA_CERT_DATA, cert); 287 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 288 mContext.sendBroadcast(intent); 289 } 290 verifyOwnerInstalledStatus(String alias, boolean expectOwnerInstalled)291 private void verifyOwnerInstalledStatus(String alias, boolean expectOwnerInstalled) { 292 final List<String> ownerInstalledCerts = 293 mDevicePolicyManager.getOwnerInstalledCaCerts(Process.myUserHandle()); 294 assertNotNull(ownerInstalledCerts); 295 assertEquals(expectOwnerInstalled, ownerInstalledCerts.contains(alias)); 296 } 297 assertResult(String testName, Boolean expectSuccess)298 private void assertResult(String testName, Boolean expectSuccess) throws InterruptedException { 299 assertTrue("Cert installer did not respond in time.", 300 mAvailableResultSemaphore.tryAcquire(180, TimeUnit.SECONDS)); 301 synchronized (this) { 302 if (expectSuccess) { 303 assertTrue(testName + " failed unexpectedly.", mReceivedResult); 304 assertNull(testName + " raised exception", mReceivedException); 305 } else { 306 assertFalse(testName + " succeeded unexpectedly.", mReceivedResult); 307 assertTrue(testName + " did not raise SecurityException", 308 mReceivedException != null && 309 mReceivedException instanceof SecurityException); 310 } 311 } 312 } 313 installKeyPair(String key, String cert, String alias)314 private void installKeyPair(String key, String cert, String alias) { 315 Intent intent = new Intent(); 316 intent.setAction(ACTION_INSTALL_KEYPAIR); 317 intent.setComponent(CERT_INSTALLER_COMPONENT); 318 intent.putExtra(EXTRA_CERT_DATA, cert); 319 intent.putExtra(EXTRA_KEY_DATA, key); 320 intent.putExtra(EXTRA_KEY_ALIAS, alias); 321 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 322 mContext.sendBroadcast(intent); 323 } 324 readEnrollmentId()325 private void readEnrollmentId() { 326 Intent intent = new Intent(); 327 intent.setAction(ACTION_READ_ENROLLMENT_SPECIFIC_ID); 328 intent.setComponent(CERT_INSTALLER_COMPONENT); 329 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 330 mContext.sendBroadcast(intent); 331 } 332 } 333