1 /* 2 * Copyright (C) 2016 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 package com.android.cts.deviceowner; 17 18 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; 19 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 20 import static android.app.admin.SecurityLog.LEVEL_ERROR; 21 import static android.app.admin.SecurityLog.LEVEL_INFO; 22 import static android.app.admin.SecurityLog.LEVEL_WARNING; 23 import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD; 24 import static android.app.admin.SecurityLog.TAG_ADB_SHELL_INTERACTIVE; 25 import static android.app.admin.SecurityLog.TAG_APP_PROCESS_START; 26 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED; 27 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED; 28 import static android.app.admin.SecurityLog.TAG_CERT_VALIDATION_FAILURE; 29 import static android.app.admin.SecurityLog.TAG_CRYPTO_SELF_TEST_COMPLETED; 30 import static android.app.admin.SecurityLog.TAG_KEYGUARD_DISABLED_FEATURES_SET; 31 import static android.app.admin.SecurityLog.TAG_KEYGUARD_DISMISSED; 32 import static android.app.admin.SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT; 33 import static android.app.admin.SecurityLog.TAG_KEYGUARD_SECURED; 34 import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION; 35 import static android.app.admin.SecurityLog.TAG_KEY_GENERATED; 36 import static android.app.admin.SecurityLog.TAG_KEY_IMPORT; 37 import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION; 38 import static android.app.admin.SecurityLog.TAG_LOGGING_STARTED; 39 import static android.app.admin.SecurityLog.TAG_LOGGING_STOPPED; 40 import static android.app.admin.SecurityLog.TAG_LOG_BUFFER_SIZE_CRITICAL; 41 import static android.app.admin.SecurityLog.TAG_MAX_PASSWORD_ATTEMPTS_SET; 42 import static android.app.admin.SecurityLog.TAG_MAX_SCREEN_LOCK_TIMEOUT_SET; 43 import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT; 44 import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT; 45 import static android.app.admin.SecurityLog.TAG_OS_SHUTDOWN; 46 import static android.app.admin.SecurityLog.TAG_OS_STARTUP; 47 import static android.app.admin.SecurityLog.TAG_PASSWORD_COMPLEXITY_SET; 48 import static android.app.admin.SecurityLog.TAG_PASSWORD_EXPIRATION_SET; 49 import static android.app.admin.SecurityLog.TAG_PASSWORD_HISTORY_LENGTH_SET; 50 import static android.app.admin.SecurityLog.TAG_REMOTE_LOCK; 51 import static android.app.admin.SecurityLog.TAG_SYNC_RECV_FILE; 52 import static android.app.admin.SecurityLog.TAG_SYNC_SEND_FILE; 53 import static android.app.admin.SecurityLog.TAG_USER_RESTRICTION_ADDED; 54 import static android.app.admin.SecurityLog.TAG_USER_RESTRICTION_REMOVED; 55 import static android.app.admin.SecurityLog.TAG_WIPE_FAILURE; 56 57 import static com.google.common.collect.ImmutableList.of; 58 59 import android.app.admin.SecurityLog.SecurityEvent; 60 import android.content.Context; 61 import android.content.SharedPreferences; 62 import android.os.Parcel; 63 import android.os.Process; 64 import android.os.UserManager; 65 import android.security.keystore.KeyGenParameterSpec; 66 import android.security.keystore.KeyProperties; 67 import android.security.keystore.KeyProtection; 68 69 import androidx.test.InstrumentationRegistry; 70 71 import com.google.common.collect.ImmutableMap; 72 import com.google.common.collect.ImmutableSet; 73 74 import java.security.KeyPair; 75 import java.security.KeyPairGenerator; 76 import java.security.KeyStore; 77 import java.util.Arrays; 78 import java.util.List; 79 import java.util.Map; 80 import java.util.Set; 81 import java.util.concurrent.TimeUnit; 82 import java.util.function.Predicate; 83 import java.util.stream.Collectors; 84 85 import javax.crypto.spec.SecretKeySpec; 86 87 public class SecurityLoggingTest extends BaseDeviceOwnerTest { 88 private static final String ARG_BATCH_NUMBER = "batchNumber"; 89 private static final String PREF_KEY_PREFIX = "batch-last-id-"; 90 private static final String PREF_NAME = "batchIds"; 91 92 // For brevity. 93 private static final Class<String> S = String.class; 94 private static final Class<Long> L = Long.class; 95 private static final Class<Integer> I = Integer.class; 96 97 private static final Map<Integer, List<Class>> PAYLOAD_TYPES_MAP = 98 new ImmutableMap.Builder<Integer, List<Class>>() 99 .put(TAG_ADB_SHELL_INTERACTIVE, of()) 100 .put(TAG_ADB_SHELL_CMD, of(S)) 101 .put(TAG_SYNC_RECV_FILE, of(S)) 102 .put(TAG_SYNC_SEND_FILE, of(S)) 103 .put(TAG_APP_PROCESS_START, of(S, L, I, I, S, S)) 104 .put(TAG_KEYGUARD_DISMISSED, of()) 105 .put(TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, of(I, I)) 106 .put(TAG_KEYGUARD_SECURED, of()) 107 .put(TAG_OS_STARTUP, of(S, S)) 108 .put(TAG_OS_SHUTDOWN, of()) 109 .put(TAG_LOGGING_STARTED, of()) 110 .put(TAG_LOGGING_STOPPED, of()) 111 .put(TAG_MEDIA_MOUNT, of(S, S)) 112 .put(TAG_MEDIA_UNMOUNT, of(S, S)) 113 .put(TAG_LOG_BUFFER_SIZE_CRITICAL, of()) 114 .put(TAG_PASSWORD_EXPIRATION_SET, of(S, I, I, L)) 115 .put(TAG_PASSWORD_COMPLEXITY_SET, of(S, I, I, I, I, I, I, I, I, I, I)) 116 .put(TAG_PASSWORD_HISTORY_LENGTH_SET, of(S, I, I, I)) 117 .put(TAG_MAX_SCREEN_LOCK_TIMEOUT_SET, of(S, I, I, L)) 118 .put(TAG_MAX_PASSWORD_ATTEMPTS_SET, of(S, I, I, I)) 119 .put(TAG_KEYGUARD_DISABLED_FEATURES_SET, of(S, I, I, I)) 120 .put(TAG_REMOTE_LOCK, of(S, I, I)) 121 .put(TAG_WIPE_FAILURE, of()) 122 .put(TAG_KEY_GENERATED, of(I, S, I)) 123 .put(TAG_KEY_IMPORT, of(I, S, I)) 124 .put(TAG_KEY_DESTRUCTION, of(I, S, I)) 125 .put(TAG_CERT_AUTHORITY_INSTALLED, of(I, S)) 126 .put(TAG_CERT_AUTHORITY_REMOVED, of(I, S)) 127 .put(TAG_USER_RESTRICTION_ADDED, of(S, I, S)) 128 .put(TAG_USER_RESTRICTION_REMOVED, of(S, I, S)) 129 .put(TAG_CRYPTO_SELF_TEST_COMPLETED, of(I)) 130 .put(TAG_KEY_INTEGRITY_VIOLATION, of(S, I)) 131 .put(TAG_CERT_VALIDATION_FAILURE, of(S)) 132 .build(); 133 134 private static final String GENERATED_KEY_ALIAS = "generated_key_alias"; 135 private static final String IMPORTED_KEY_ALIAS = "imported_key_alias"; 136 137 /* 138 * The CA cert below is the content of cacert.pem as generated by: 139 * 140 * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem 141 */ 142 private static final String TEST_CA = 143 "-----BEGIN CERTIFICATE-----\n" + 144 "MIIDXTCCAkWgAwIBAgIJAK9Tl/F9V8kSMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n" + 145 "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n" + 146 "aWRnaXRzIFB0eSBMdGQwHhcNMTUwMzA2MTczMjExWhcNMjUwMzAzMTczMjExWjBF\n" + 147 "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n" + 148 "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + 149 "CgKCAQEAvItOutsE75WBTgTyNAHt4JXQ3JoseaGqcC3WQij6vhrleWi5KJ0jh1/M\n" + 150 "Rpry7Fajtwwb4t8VZa0NuM2h2YALv52w1xivql88zce/HU1y7XzbXhxis9o6SCI+\n" + 151 "oVQSbPeXRgBPppFzBEh3ZqYTVhAqw451XhwdA4Aqs3wts7ddjwlUzyMdU44osCUg\n" + 152 "kVg7lfPf9sTm5IoHVcfLSCWH5n6Nr9sH3o2ksyTwxuOAvsN11F/a0mmUoPciYPp+\n" + 153 "q7DzQzdi7akRG601DZ4YVOwo6UITGvDyuAAdxl5isovUXqe6Jmz2/myTSpAKxGFs\n" + 154 "jk9oRoG6WXWB1kni490GIPjJ1OceyQIDAQABo1AwTjAdBgNVHQ4EFgQUH1QIlPKL\n" + 155 "p2OQ/AoLOjKvBW4zK3AwHwYDVR0jBBgwFoAUH1QIlPKLp2OQ/AoLOjKvBW4zK3Aw\n" + 156 "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcMi4voMMJHeQLjtq8Oky\n" + 157 "Azpyk8moDwgCd4llcGj7izOkIIFqq/lyqKdtykVKUWz2bSHO5cLrtaOCiBWVlaCV\n" + 158 "DYAnnVLM8aqaA6hJDIfaGs4zmwz0dY8hVMFCuCBiLWuPfiYtbEmjHGSmpQTG6Qxn\n" + 159 "ZJlaK5CZyt5pgh5EdNdvQmDEbKGmu0wpCq9qjZImwdyAul1t/B0DrsWApZMgZpeI\n" + 160 "d2od0VBrCICB1K4p+C51D93xyQiva7xQcCne+TAnGNy9+gjQ/MyR8MRpwRLv5ikD\n" + 161 "u0anJCN8pXo6IMglfMAsoton1J6o5/ae5uhC6caQU8bNUsCK570gpNfjkzo6rbP0\n" + 162 "wQ==\n" + 163 "-----END CERTIFICATE-----"; 164 165 private static final String TEST_CA_SUBJECT = "o=internet widgits pty ltd,st=some-state,c=au"; 166 167 // Indices of various fields in event payload. 168 private static final int SUCCESS_INDEX = 0; 169 private static final int ALIAS_INDEX = 1; 170 private static final int UID_INDEX = 2; 171 private static final int SUBJECT_INDEX = 1; 172 private static final int ADMIN_PKG_INDEX = 0; 173 private static final int ADMIN_USER_INDEX = 1; 174 private static final int TARGET_USER_INDEX = 2; 175 private static final int PWD_LEN_INDEX = 3; 176 private static final int PWD_QUALITY_INDEX = 4; 177 private static final int LETTERS_INDEX = 5; 178 private static final int NON_LETTERS_INDEX = 6; 179 private static final int NUMERIC_INDEX = 7; 180 private static final int UPPERCASE_INDEX = 8; 181 private static final int LOWERCASE_INDEX = 9; 182 private static final int SYMBOLS_INDEX = 10; 183 private static final int PWD_EXPIRATION_INDEX = 3; 184 private static final int PWD_HIST_LEN_INDEX = 3; 185 private static final int USER_RESTRICTION_INDEX = 2; 186 private static final int MAX_PWD_ATTEMPTS_INDEX = 3; 187 private static final int KEYGUARD_FEATURES_INDEX = 3; 188 private static final int MAX_SCREEN_TIMEOUT_INDEX = 3; 189 190 // Value that indicates success in events that have corresponding field in their payload. 191 private static final int SUCCESS_VALUE = 1; 192 193 private static final int TEST_PWD_LENGTH = 10; 194 // Min number of various character types to use. 195 private static final int TEST_PWD_CHARS = 2; 196 197 private static final long TEST_PWD_EXPIRATION_TIMEOUT = TimeUnit.DAYS.toMillis(356); 198 private static final int TEST_PWD_HISTORY_LENGTH = 3; 199 private static final int TEST_PWD_MAX_ATTEMPTS = 5; 200 private static final long TEST_MAX_TIME_TO_LOCK = TimeUnit.HOURS.toMillis(1); 201 202 /** 203 * Test: retrieving security logs can only be done if there's one user on the device or all 204 * secondary users / profiles are affiliated. 205 */ testRetrievingSecurityLogsThrowsSecurityException()206 public void testRetrievingSecurityLogsThrowsSecurityException() { 207 try { 208 mDevicePolicyManager.retrieveSecurityLogs(getWho()); 209 fail("did not throw expected SecurityException"); 210 } catch (SecurityException expected) { 211 } 212 } 213 214 /** 215 * Test: retrieving previous security logs can only be done if there's one user on the device or 216 * all secondary users / profiles are affiliated. 217 */ testRetrievingPreviousSecurityLogsThrowsSecurityException()218 public void testRetrievingPreviousSecurityLogsThrowsSecurityException() { 219 try { 220 mDevicePolicyManager.retrievePreRebootSecurityLogs(getWho()); 221 fail("did not throw expected SecurityException"); 222 } catch (SecurityException expected) { 223 } 224 } 225 226 /** 227 * Test: retrieves security logs and verifies that all events generated as a result of host 228 * side actions and by {@link #testGenerateLogs()} are there. 229 */ testVerifyGeneratedLogs()230 public void testVerifyGeneratedLogs() throws Exception { 231 final List<SecurityEvent> events = getEvents(); 232 verifyAutomaticEventsPresent(events); 233 verifyKeystoreEventsPresent(events); 234 verifyKeyChainEventsPresent(events); 235 verifyAdminEventsPresent(events); 236 } 237 verifyAutomaticEventsPresent(List<SecurityEvent> events)238 private void verifyAutomaticEventsPresent(List<SecurityEvent> events) { 239 verifyOsStartupEventPresent(events); 240 verifyLoggingStartedEventPresent(events); 241 verifyCryptoSelfTestEventPresent(events); 242 } 243 verifyKeyChainEventsPresent(List<SecurityEvent> events)244 private void verifyKeyChainEventsPresent(List<SecurityEvent> events) { 245 verifyCertInstalledEventPresent(events); 246 verifyCertUninstalledEventPresent(events); 247 } 248 verifyKeystoreEventsPresent(List<SecurityEvent> events)249 private void verifyKeystoreEventsPresent(List<SecurityEvent> events) { 250 verifyKeyGeneratedEventPresent(events, GENERATED_KEY_ALIAS); 251 verifyKeyDeletedEventPresent(events, GENERATED_KEY_ALIAS); 252 verifyKeyImportedEventPresent(events, IMPORTED_KEY_ALIAS); 253 verifyKeyDeletedEventPresent(events, IMPORTED_KEY_ALIAS); 254 } 255 verifyAdminEventsPresent(List<SecurityEvent> events)256 private void verifyAdminEventsPresent(List<SecurityEvent> events) { 257 if (mHasSecureLockScreen) { 258 verifyPasswordComplexityEventsPresent(events); 259 } 260 verifyLockingPolicyEventsPresent(events); 261 verifyUserRestrictionEventsPresent(events); 262 } 263 264 /** 265 * Generates events for positive test cases. 266 */ testGenerateLogs()267 public void testGenerateLogs() throws Exception { 268 generateKeystoreEvents(); 269 generateKeyChainEvents(); 270 generateAdminEvents(); 271 } 272 generateKeyChainEvents()273 private void generateKeyChainEvents() { 274 installCaCert(); 275 uninstallCaCert(); 276 } 277 generateKeystoreEvents()278 private void generateKeystoreEvents() throws Exception { 279 generateKey(GENERATED_KEY_ALIAS); 280 deleteKey(GENERATED_KEY_ALIAS); 281 importKey(IMPORTED_KEY_ALIAS); 282 deleteKey(IMPORTED_KEY_ALIAS); 283 } 284 generateAdminEvents()285 private void generateAdminEvents() { 286 if (mHasSecureLockScreen) { 287 generatePasswordComplexityEvents(); 288 } 289 generateLockingPolicyEvents(); 290 generateUserRestrictionEvents(); 291 } 292 293 /** 294 * Fetches and sanity-checks the events. 295 */ getEvents()296 private List<SecurityEvent> getEvents() throws Exception { 297 List<SecurityEvent> events = null; 298 // Retry once after seeping for 1 second, in case "dpm force-security-logs" hasn't taken 299 // effect just yet. 300 for (int i = 0; i < 2 && events == null; i++) { 301 events = mDevicePolicyManager.retrieveSecurityLogs(getWho()); 302 if (events == null) Thread.sleep(1000); 303 } 304 305 verifySecurityLogs(events); 306 307 return events; 308 } 309 310 /** 311 * Test: check that there are no gaps between ids in two consecutive batches. Shared preference 312 * is used to store these numbers between test invocations. 313 */ testVerifyLogIds()314 public void testVerifyLogIds() throws Exception { 315 final String param = InstrumentationRegistry.getArguments().getString(ARG_BATCH_NUMBER); 316 final int batchId = param == null ? 0 : Integer.parseInt(param); 317 final List<SecurityEvent> events = getEvents(); 318 final SharedPreferences prefs = 319 mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); 320 321 final long firstId = events.get(0).getId(); 322 if (batchId == 0) { 323 assertEquals("Event id wasn't reset.", 0L, firstId); 324 } else { 325 final String prevBatchLastIdKey = PREF_KEY_PREFIX + (batchId - 1); 326 assertTrue("Last event id from previous batch not found in shared prefs", 327 prefs.contains(prevBatchLastIdKey)); 328 final long prevBatchLastId = prefs.getLong(prevBatchLastIdKey, 0); 329 assertEquals("Event ids aren't consecutive between batches", 330 firstId, prevBatchLastId + 1); 331 } 332 333 final String currBatchLastIdKey = PREF_KEY_PREFIX + batchId; 334 final long lastId = events.get(events.size() - 1).getId(); 335 prefs.edit().putLong(currBatchLastIdKey, lastId).commit(); 336 } 337 verifySecurityLogs(List<SecurityEvent> events)338 private void verifySecurityLogs(List<SecurityEvent> events) { 339 assertTrue("Unable to get events", events != null && events.size() > 0); 340 341 // We don't know much about the events, so just call public API methods. 342 for (int i = 0; i < events.size(); i++) { 343 final SecurityEvent event = events.get(i); 344 345 verifyPayloadTypes(event); 346 347 // Test id for monotonically increasing. 348 if (i > 0) { 349 assertEquals("Event IDs are not monotonically increasing within the batch", 350 events.get(i - 1).getId() + 1, event.getId()); 351 } 352 353 // Test parcelling: flatten to a parcel. 354 Parcel p = Parcel.obtain(); 355 event.writeToParcel(p, 0); 356 p.setDataPosition(0); 357 358 // Restore from parcel and check contents. 359 final SecurityEvent restored = SecurityEvent.CREATOR.createFromParcel(p); 360 p.recycle(); 361 362 final int level = event.getLogLevel(); 363 assertTrue(level == LEVEL_INFO || level == LEVEL_WARNING || level == LEVEL_ERROR); 364 365 // For some events data is encapsulated into Object array. 366 if (event.getData() instanceof Object[]) { 367 assertTrue("Parcelling changed the array returned by getData", 368 Arrays.equals((Object[]) event.getData(), (Object[]) restored.getData())); 369 } else { 370 assertEquals("Parcelling changed the result of getData", 371 event.getData(), restored.getData()); 372 } 373 assertEquals("Parcelling changed the result of getId", 374 event.getId(), restored.getId()); 375 assertEquals("Parcelling changed the result of getTag", 376 event.getTag(), restored.getTag()); 377 assertEquals("Parcelling changed the result of getTimeNanos", 378 event.getTimeNanos(), restored.getTimeNanos()); 379 assertEquals("Parcelling changed the result of describeContents", 380 event.describeContents(), restored.describeContents()); 381 } 382 } 383 verifyPayloadTypes(SecurityEvent event)384 private void verifyPayloadTypes(SecurityEvent event) { 385 final List<Class> payloadTypes = PAYLOAD_TYPES_MAP.get(event.getTag()); 386 assertNotNull("event type unknown: " + event.getTag(), payloadTypes); 387 388 if (payloadTypes.size() == 0) { 389 // No payload. 390 assertNull("non-null payload", event.getData()); 391 } else if (payloadTypes.size() == 1) { 392 // Singleton payload. 393 assertTrue(payloadTypes.get(0).isInstance(event.getData())); 394 } else { 395 // Payload is incapsulated into Object[] 396 assertTrue(event.getData() instanceof Object[]); 397 final Object[] dataArray = (Object[]) event.getData(); 398 assertEquals(payloadTypes.size(), dataArray.length); 399 for (int i = 0; i < payloadTypes.size(); i++) { 400 assertTrue(payloadTypes.get(i).isInstance(dataArray[i])); 401 } 402 } 403 } 404 verifyOsStartupEventPresent(List<SecurityEvent> events)405 private void verifyOsStartupEventPresent(List<SecurityEvent> events) { 406 final SecurityEvent event = findEvent("os startup", events, TAG_OS_STARTUP); 407 // Verified boot state, empty if running on emulator 408 assertOneOf(ImmutableSet.of("", "green", "yellow", "orange"), getString(event, 0)); 409 // dm-verity mode, empty if it is disabled 410 assertOneOf(ImmutableSet.of("", "enforcing", "eio", "disabled"), getString(event, 1)); 411 } 412 assertOneOf(Set<String> allowed, String s)413 private void assertOneOf(Set<String> allowed, String s) { 414 assertTrue(String.format("\"%s\" is not one of [%s]", s, String.join(", ", allowed)), 415 allowed.contains(s)); 416 } 417 verifyCryptoSelfTestEventPresent(List<SecurityEvent> events)418 private void verifyCryptoSelfTestEventPresent(List<SecurityEvent> events) { 419 final SecurityEvent event = findEvent("crypto self test complete", 420 events, TAG_CRYPTO_SELF_TEST_COMPLETED); 421 // Success code. 422 assertEquals(1, getInt(event)); 423 } 424 verifyLoggingStartedEventPresent(List<SecurityEvent> events)425 private void verifyLoggingStartedEventPresent(List<SecurityEvent> events) { 426 findEvent("logging started", events, TAG_LOGGING_STARTED); 427 } 428 findEvent(String description, List<SecurityEvent> events, int tag)429 private SecurityEvent findEvent(String description, List<SecurityEvent> events, int tag) { 430 return findEvent(description, events, e -> e.getTag() == tag); 431 } 432 findEvent(String description, List<SecurityEvent> events, Predicate<SecurityEvent> predicate)433 private SecurityEvent findEvent(String description, List<SecurityEvent> events, 434 Predicate<SecurityEvent> predicate) { 435 final List<SecurityEvent> matches = 436 events.stream().filter(predicate).collect(Collectors.toList()); 437 assertEquals("Invalid number of matching events: " + description, 1, matches.size()); 438 return matches.get(0); 439 } 440 getDatum(SecurityEvent event, int index)441 private static Object getDatum(SecurityEvent event, int index) { 442 final Object[] dataArray = (Object[]) event.getData(); 443 return dataArray[index]; 444 } 445 getString(SecurityEvent event, int index)446 private static String getString(SecurityEvent event, int index) { 447 return (String) getDatum(event, index); 448 } 449 getInt(SecurityEvent event)450 private static int getInt(SecurityEvent event) { 451 return (Integer) event.getData(); 452 } 453 getInt(SecurityEvent event, int index)454 private static int getInt(SecurityEvent event, int index) { 455 return (Integer) getDatum(event, index); 456 } 457 getLong(SecurityEvent event, int index)458 private static long getLong(SecurityEvent event, int index) { 459 return (Long) getDatum(event, index); 460 } 461 462 /** 463 * Test: Test enabling security logging. This test should be executed after installing a device 464 * owner so that we check that logging is not enabled by default. This test has a side effect: 465 * security logging is enabled after its execution. 466 */ testEnablingSecurityLogging()467 public void testEnablingSecurityLogging() { 468 assertFalse(mDevicePolicyManager.isSecurityLoggingEnabled(getWho())); 469 mDevicePolicyManager.setSecurityLoggingEnabled(getWho(), true); 470 assertTrue(mDevicePolicyManager.isSecurityLoggingEnabled(getWho())); 471 } 472 473 /** 474 * Test: Test disabling security logging. This test has a side effect: security logging is 475 * disabled after its execution. 476 */ testDisablingSecurityLogging()477 public void testDisablingSecurityLogging() { 478 mDevicePolicyManager.setSecurityLoggingEnabled(getWho(), false); 479 assertFalse(mDevicePolicyManager.isSecurityLoggingEnabled(getWho())); 480 481 // Verify that logs are actually not available. 482 assertNull(mDevicePolicyManager.retrieveSecurityLogs(getWho())); 483 } 484 485 /** 486 * Test: retrieving security logs should be rate limited - subsequent attempts should return 487 * null. 488 */ testSecurityLoggingRetrievalRateLimited()489 public void testSecurityLoggingRetrievalRateLimited() { 490 final List<SecurityEvent> logs = mDevicePolicyManager.retrieveSecurityLogs(getWho()); 491 // if logs is null it means that that attempt was rate limited => test PASS 492 if (logs != null) { 493 assertNull(mDevicePolicyManager.retrieveSecurityLogs(getWho())); 494 assertNull(mDevicePolicyManager.retrieveSecurityLogs(getWho())); 495 } 496 } 497 generateKey(String keyAlias)498 private void generateKey(String keyAlias) throws Exception { 499 final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); 500 generator.initialize( 501 new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_SIGN).build()); 502 final KeyPair keyPair = generator.generateKeyPair(); 503 assertNotNull(keyPair); 504 } 505 verifyKeyGeneratedEventPresent(List<SecurityEvent> events, String alias)506 private void verifyKeyGeneratedEventPresent(List<SecurityEvent> events, String alias) { 507 findEvent("key generated", events, 508 e -> e.getTag() == TAG_KEY_GENERATED 509 && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE 510 && getString(e, ALIAS_INDEX).contains(alias) 511 && getInt(e, UID_INDEX) == Process.myUid()); 512 } 513 importKey(String alias)514 private void importKey(String alias) throws Exception{ 515 final KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); 516 ks.load(null); 517 ks.setEntry(alias, new KeyStore.SecretKeyEntry(new SecretKeySpec(new byte[32], "AES")), 518 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT).build()); 519 } 520 verifyKeyImportedEventPresent(List<SecurityEvent> events, String alias)521 private void verifyKeyImportedEventPresent(List<SecurityEvent> events, String alias) { 522 findEvent("key imported", events, 523 e -> e.getTag() == TAG_KEY_IMPORT 524 && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE 525 && getString(e, ALIAS_INDEX).contains(alias) 526 && getInt(e, UID_INDEX) == Process.myUid()); 527 } 528 deleteKey(String keyAlias)529 private void deleteKey(String keyAlias) throws Exception { 530 final KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); 531 ks.load(null); 532 ks.deleteEntry(keyAlias); 533 } 534 verifyKeyDeletedEventPresent(List<SecurityEvent> events, String alias)535 private void verifyKeyDeletedEventPresent(List<SecurityEvent> events, String alias) { 536 findEvent("key deleted", events, 537 e -> e.getTag() == TAG_KEY_DESTRUCTION 538 && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE 539 && getString(e, ALIAS_INDEX).contains(alias) 540 && getInt(e, UID_INDEX) == Process.myUid()); 541 } 542 installCaCert()543 private void installCaCert() { 544 mDevicePolicyManager.installCaCert(getWho(), TEST_CA.getBytes()); 545 } 546 verifyCertInstalledEventPresent(List<SecurityEvent> events)547 private void verifyCertInstalledEventPresent(List<SecurityEvent> events) { 548 findEvent("cert authority installed", events, 549 e -> e.getTag() == TAG_CERT_AUTHORITY_INSTALLED 550 && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE 551 && getString(e, SUBJECT_INDEX).equals(TEST_CA_SUBJECT)); 552 } 553 uninstallCaCert()554 private void uninstallCaCert() { 555 mDevicePolicyManager.uninstallCaCert(getWho(), TEST_CA.getBytes()); 556 } 557 verifyCertUninstalledEventPresent(List<SecurityEvent> events)558 private void verifyCertUninstalledEventPresent(List<SecurityEvent> events) { 559 findEvent("cert authority removed", events, 560 e -> e.getTag() == TAG_CERT_AUTHORITY_REMOVED 561 && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE 562 && getString(e, SUBJECT_INDEX).equals(TEST_CA_SUBJECT)); 563 } 564 generatePasswordComplexityEvents()565 private void generatePasswordComplexityEvents() { 566 mDevicePolicyManager.setPasswordQuality(getWho(), PASSWORD_QUALITY_COMPLEX); 567 mDevicePolicyManager.setPasswordMinimumLength(getWho(), TEST_PWD_LENGTH); 568 mDevicePolicyManager.setPasswordMinimumLetters(getWho(), TEST_PWD_CHARS); 569 mDevicePolicyManager.setPasswordMinimumNonLetter(getWho(), TEST_PWD_CHARS); 570 mDevicePolicyManager.setPasswordMinimumUpperCase(getWho(), TEST_PWD_CHARS); 571 mDevicePolicyManager.setPasswordMinimumLowerCase(getWho(), TEST_PWD_CHARS); 572 mDevicePolicyManager.setPasswordMinimumNumeric(getWho(), TEST_PWD_CHARS); 573 mDevicePolicyManager.setPasswordMinimumSymbols(getWho(), TEST_PWD_CHARS); 574 } 575 verifyPasswordComplexityEventsPresent(List<SecurityEvent> events)576 private void verifyPasswordComplexityEventsPresent(List<SecurityEvent> events) { 577 final int userId = Process.myUserHandle().getIdentifier(); 578 // This reflects default values for password complexity event payload fields. 579 final Object[] expectedPayload = new Object[] { 580 getWho().getPackageName(), // admin package 581 userId, // admin user 582 userId, // target user 583 0, // default password length 584 0, // default password quality 585 1, // default min letters 586 0, // default min non-letters 587 1, // default min numeric 588 0, // default min uppercase 589 0, // default min lowercase 590 1, // default min symbols 591 }; 592 593 // The order should be consistent with the order in generatePasswordComplexityEvents(), so 594 // that the expected values change in the same sequence as when setting password policies. 595 expectedPayload[PWD_QUALITY_INDEX] = PASSWORD_QUALITY_COMPLEX; 596 findPasswordComplexityEvent("set pwd quality", events, expectedPayload); 597 expectedPayload[PWD_LEN_INDEX] = TEST_PWD_LENGTH; 598 findPasswordComplexityEvent("set pwd length", events, expectedPayload); 599 expectedPayload[LETTERS_INDEX] = TEST_PWD_CHARS; 600 findPasswordComplexityEvent("set pwd min letters", events, expectedPayload); 601 expectedPayload[NON_LETTERS_INDEX] = TEST_PWD_CHARS; 602 findPasswordComplexityEvent("set pwd min non-letters", events, expectedPayload); 603 expectedPayload[UPPERCASE_INDEX] = TEST_PWD_CHARS; 604 findPasswordComplexityEvent("set pwd min uppercase", events, expectedPayload); 605 expectedPayload[LOWERCASE_INDEX] = TEST_PWD_CHARS; 606 findPasswordComplexityEvent("set pwd min lowercase", events, expectedPayload); 607 expectedPayload[NUMERIC_INDEX] = TEST_PWD_CHARS; 608 findPasswordComplexityEvent("set pwd min numeric", events, expectedPayload); 609 expectedPayload[SYMBOLS_INDEX] = TEST_PWD_CHARS; 610 findPasswordComplexityEvent("set pwd min symbols", events, expectedPayload); 611 } 612 generateLockingPolicyEvents()613 private void generateLockingPolicyEvents() { 614 if (mHasSecureLockScreen) { 615 mDevicePolicyManager.setPasswordExpirationTimeout(getWho(), 616 TEST_PWD_EXPIRATION_TIMEOUT); 617 mDevicePolicyManager.setPasswordHistoryLength(getWho(), TEST_PWD_HISTORY_LENGTH); 618 mDevicePolicyManager.setMaximumFailedPasswordsForWipe(getWho(), TEST_PWD_MAX_ATTEMPTS); 619 } 620 mDevicePolicyManager.setKeyguardDisabledFeatures(getWho(), KEYGUARD_DISABLE_FINGERPRINT); 621 mDevicePolicyManager.setMaximumTimeToLock(getWho(), TEST_MAX_TIME_TO_LOCK); 622 mDevicePolicyManager.lockNow(); 623 } 624 verifyLockingPolicyEventsPresent(List<SecurityEvent> events)625 private void verifyLockingPolicyEventsPresent(List<SecurityEvent> events) { 626 final int userId = Process.myUserHandle().getIdentifier(); 627 628 if (mHasSecureLockScreen) { 629 findEvent("set password expiration", events, 630 e -> e.getTag() == TAG_PASSWORD_EXPIRATION_SET && 631 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 632 getInt(e, ADMIN_USER_INDEX) == userId && 633 getInt(e, TARGET_USER_INDEX) == userId && 634 getLong(e, PWD_EXPIRATION_INDEX) == TEST_PWD_EXPIRATION_TIMEOUT); 635 636 findEvent("set password history length", events, 637 e -> e.getTag() == TAG_PASSWORD_HISTORY_LENGTH_SET && 638 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 639 getInt(e, ADMIN_USER_INDEX) == userId && 640 getInt(e, TARGET_USER_INDEX) == userId && 641 getInt(e, PWD_HIST_LEN_INDEX) == TEST_PWD_HISTORY_LENGTH); 642 643 findEvent("set password attempts", events, 644 e -> e.getTag() == TAG_MAX_PASSWORD_ATTEMPTS_SET && 645 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 646 getInt(e, ADMIN_USER_INDEX) == userId && 647 getInt(e, TARGET_USER_INDEX) == userId && 648 getInt(e, MAX_PWD_ATTEMPTS_INDEX) == TEST_PWD_MAX_ATTEMPTS); 649 } 650 651 findEvent("set keyguard disabled features", events, 652 e -> e.getTag() == TAG_KEYGUARD_DISABLED_FEATURES_SET && 653 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 654 getInt(e, ADMIN_USER_INDEX) == userId && 655 getInt(e, TARGET_USER_INDEX) == userId && 656 getInt(e, KEYGUARD_FEATURES_INDEX) == KEYGUARD_DISABLE_FINGERPRINT); 657 658 findEvent("set screen lock timeout", events, 659 e -> e.getTag() == TAG_MAX_SCREEN_LOCK_TIMEOUT_SET && 660 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 661 getInt(e, ADMIN_USER_INDEX) == userId && 662 getInt(e, TARGET_USER_INDEX) == userId && 663 getLong(e, MAX_SCREEN_TIMEOUT_INDEX) == TEST_MAX_TIME_TO_LOCK); 664 665 findEvent("set screen lock timeout", events, 666 e -> e.getTag() == TAG_REMOTE_LOCK && 667 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 668 getInt(e, ADMIN_USER_INDEX) == userId); 669 } 670 findPasswordComplexityEvent( String description, List<SecurityEvent> events, Object[] expectedPayload)671 private void findPasswordComplexityEvent( 672 String description, List<SecurityEvent> events, Object[] expectedPayload) { 673 findEvent(description, events, 674 e -> e.getTag() == TAG_PASSWORD_COMPLEXITY_SET && 675 Arrays.equals((Object[]) e.getData(), expectedPayload)); 676 } 677 generateUserRestrictionEvents()678 private void generateUserRestrictionEvents() { 679 mDevicePolicyManager.addUserRestriction(getWho(), UserManager.DISALLOW_FUN); 680 mDevicePolicyManager.clearUserRestriction(getWho(), UserManager.DISALLOW_FUN); 681 } 682 verifyUserRestrictionEventsPresent(List<SecurityEvent> events)683 private void verifyUserRestrictionEventsPresent(List<SecurityEvent> events) { 684 findUserRestrictionEvent("set user restriction", events, TAG_USER_RESTRICTION_ADDED); 685 findUserRestrictionEvent("clear user restriction", events, TAG_USER_RESTRICTION_REMOVED); 686 } 687 findUserRestrictionEvent(String description, List<SecurityEvent> events, int tag)688 private void findUserRestrictionEvent(String description, List<SecurityEvent> events, int tag) { 689 final int userId = Process.myUserHandle().getIdentifier(); 690 findEvent(description, events, 691 e -> e.getTag() == tag && 692 getString(e, ADMIN_PKG_INDEX).equals(getWho().getPackageName()) && 693 getInt(e, ADMIN_USER_INDEX) == userId && 694 UserManager.DISALLOW_FUN.equals(getString(e, USER_RESTRICTION_INDEX))); 695 } 696 } 697