Home | History | Annotate | Download | only in deviceowner
      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      */
    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      */
    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      */
    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 
    238     private void verifyAutomaticEventsPresent(List<SecurityEvent> events) {
    239         verifyOsStartupEventPresent(events);
    240         verifyLoggingStartedEventPresent(events);
    241         verifyCryptoSelfTestEventPresent(events);
    242     }
    243 
    244     private void verifyKeyChainEventsPresent(List<SecurityEvent> events) {
    245         verifyCertInstalledEventPresent(events);
    246         verifyCertUninstalledEventPresent(events);
    247     }
    248 
    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 
    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      */
    267     public void testGenerateLogs() throws Exception {
    268         generateKeystoreEvents();
    269         generateKeyChainEvents();
    270         generateAdminEvents();
    271     }
    272 
    273     private void generateKeyChainEvents() {
    274         installCaCert();
    275         uninstallCaCert();
    276     }
    277 
    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 
    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      */
    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      */
    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 
    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 
    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 
    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 
    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 
    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 
    425     private void verifyLoggingStartedEventPresent(List<SecurityEvent> events) {
    426         findEvent("logging started", events, TAG_LOGGING_STARTED);
    427     }
    428 
    429     private SecurityEvent findEvent(String description, List<SecurityEvent> events, int tag) {
    430         return findEvent(description, events, e -> e.getTag() == tag);
    431     }
    432 
    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 
    441     private static Object getDatum(SecurityEvent event, int index) {
    442         final Object[] dataArray = (Object[]) event.getData();
    443         return dataArray[index];
    444     }
    445 
    446     private static String getString(SecurityEvent event, int index) {
    447         return (String) getDatum(event, index);
    448     }
    449 
    450     private static int getInt(SecurityEvent event) {
    451         return (Integer) event.getData();
    452     }
    453 
    454     private static int getInt(SecurityEvent event, int index) {
    455         return (Integer) getDatum(event, index);
    456     }
    457 
    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      */
    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      */
    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      */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    543     private void installCaCert() {
    544         mDevicePolicyManager.installCaCert(getWho(), TEST_CA.getBytes());
    545     }
    546 
    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 
    554     private void uninstallCaCert() {
    555         mDevicePolicyManager.uninstallCaCert(getWho(), TEST_CA.getBytes());
    556     }
    557 
    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 
    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 
    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 
    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 
    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 
    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 
    678     private void generateUserRestrictionEvents() {
    679         mDevicePolicyManager.addUserRestriction(getWho(), UserManager.DISALLOW_FUN);
    680         mDevicePolicyManager.clearUserRestriction(getWho(), UserManager.DISALLOW_FUN);
    681     }
    682 
    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 
    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