• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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