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