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.deviceandprofileowner;
17 
18 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
19 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
21 import static android.app.admin.SecurityLog.LEVEL_ERROR;
22 import static android.app.admin.SecurityLog.LEVEL_INFO;
23 import static android.app.admin.SecurityLog.LEVEL_WARNING;
24 import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD;
25 import static android.app.admin.SecurityLog.TAG_ADB_SHELL_INTERACTIVE;
26 import static android.app.admin.SecurityLog.TAG_APP_PROCESS_START;
27 import static android.app.admin.SecurityLog.TAG_CAMERA_POLICY_SET;
28 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED;
29 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED;
30 import static android.app.admin.SecurityLog.TAG_CERT_VALIDATION_FAILURE;
31 import static android.app.admin.SecurityLog.TAG_CRYPTO_SELF_TEST_COMPLETED;
32 import static android.app.admin.SecurityLog.TAG_KEYGUARD_DISABLED_FEATURES_SET;
33 import static android.app.admin.SecurityLog.TAG_KEYGUARD_DISMISSED;
34 import static android.app.admin.SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT;
35 import static android.app.admin.SecurityLog.TAG_KEYGUARD_SECURED;
36 import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION;
37 import static android.app.admin.SecurityLog.TAG_KEY_GENERATED;
38 import static android.app.admin.SecurityLog.TAG_KEY_IMPORT;
39 import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION;
40 import static android.app.admin.SecurityLog.TAG_LOGGING_STARTED;
41 import static android.app.admin.SecurityLog.TAG_LOGGING_STOPPED;
42 import static android.app.admin.SecurityLog.TAG_LOG_BUFFER_SIZE_CRITICAL;
43 import static android.app.admin.SecurityLog.TAG_MAX_PASSWORD_ATTEMPTS_SET;
44 import static android.app.admin.SecurityLog.TAG_MAX_SCREEN_LOCK_TIMEOUT_SET;
45 import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT;
46 import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT;
47 import static android.app.admin.SecurityLog.TAG_OS_SHUTDOWN;
48 import static android.app.admin.SecurityLog.TAG_OS_STARTUP;
49 import static android.app.admin.SecurityLog.TAG_PASSWORD_COMPLEXITY_REQUIRED;
50 import static android.app.admin.SecurityLog.TAG_PASSWORD_COMPLEXITY_SET;
51 import static android.app.admin.SecurityLog.TAG_PASSWORD_EXPIRATION_SET;
52 import static android.app.admin.SecurityLog.TAG_PASSWORD_HISTORY_LENGTH_SET;
53 import static android.app.admin.SecurityLog.TAG_REMOTE_LOCK;
54 import static android.app.admin.SecurityLog.TAG_SYNC_RECV_FILE;
55 import static android.app.admin.SecurityLog.TAG_SYNC_SEND_FILE;
56 import static android.app.admin.SecurityLog.TAG_USER_RESTRICTION_ADDED;
57 import static android.app.admin.SecurityLog.TAG_USER_RESTRICTION_REMOVED;
58 import static android.app.admin.SecurityLog.TAG_WIPE_FAILURE;
59 
60 import static com.android.cts.devicepolicy.TestCertificates.TEST_CA;
61 import static com.android.cts.devicepolicy.TestCertificates.TEST_CA_SUBJECT;
62 
63 import static com.google.common.collect.ImmutableList.of;
64 import static com.google.common.truth.Truth.assertThat;
65 
66 import android.app.admin.DevicePolicyManager;
67 import android.app.admin.SecurityLog;
68 import android.app.admin.SecurityLog.SecurityEvent;
69 import android.content.Context;
70 import android.content.SharedPreferences;
71 import android.os.Parcel;
72 import android.os.Process;
73 import android.os.UserHandle;
74 import android.os.UserManager;
75 import android.security.keystore.KeyGenParameterSpec;
76 import android.security.keystore.KeyProperties;
77 import android.security.keystore.KeyProtection;
78 import android.support.test.uiautomator.UiDevice;
79 import android.text.TextUtils;
80 import android.util.DebugUtils;
81 import android.util.Log;
82 
83 import androidx.test.InstrumentationRegistry;
84 
85 import com.google.common.collect.ImmutableMap;
86 import com.google.common.collect.ImmutableSet;
87 
88 import junit.framework.AssertionFailedError;
89 
90 import java.security.KeyPair;
91 import java.security.KeyPairGenerator;
92 import java.security.KeyStore;
93 import java.util.Arrays;
94 import java.util.List;
95 import java.util.Map;
96 import java.util.Set;
97 import java.util.concurrent.TimeUnit;
98 import java.util.function.Predicate;
99 import java.util.stream.Collectors;
100 
101 import javax.crypto.spec.SecretKeySpec;
102 
103 public class SecurityLoggingTest extends BaseDeviceAdminTest {
104     private static final String TAG = "SecurityLoggingTest";
105     private static final String ARG_BATCH_NUMBER = "batchNumber";
106     private static final String PREF_KEY_PREFIX = "batch-last-id-";
107     private static final String PREF_NAME = "batchIds";
108     // system/core/liblog/event.logtags: 1006  liblog (dropped|1)
109     private static final int TAG_LIBLOG_DROPPED = 1006;
110     private static final String DELEGATE_APP_PKG = "com.android.cts.delegate";
111     private static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";
112     private static final boolean VERBOSE = false;
113 
114     // For brevity.
115     private static final Class<String> S = String.class;
116     private static final Class<Long> L = Long.class;
117     private static final Class<Integer> I = Integer.class;
118 
119     private static final Map<Integer, List<Class>> PAYLOAD_TYPES_MAP =
120             new ImmutableMap.Builder<Integer, List<Class>>()
121                     .put(TAG_ADB_SHELL_INTERACTIVE, of())
122                     .put(TAG_ADB_SHELL_CMD, of(S))
123                     .put(TAG_SYNC_RECV_FILE, of(S))
124                     .put(TAG_SYNC_SEND_FILE, of(S))
125                     .put(TAG_APP_PROCESS_START, of(S, L, I, I, S, S))
126                     .put(TAG_KEYGUARD_DISMISSED, of())
127                     .put(TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, of(I, I))
128                     .put(TAG_KEYGUARD_SECURED, of())
129                     .put(TAG_OS_STARTUP, of(S, S))
130                     .put(TAG_OS_SHUTDOWN, of())
131                     .put(TAG_LOGGING_STARTED, of())
132                     .put(TAG_LOGGING_STOPPED, of())
133                     .put(TAG_MEDIA_MOUNT, of(S, S))
134                     .put(TAG_MEDIA_UNMOUNT, of(S, S))
135                     .put(TAG_LOG_BUFFER_SIZE_CRITICAL, of())
136                     .put(TAG_PASSWORD_EXPIRATION_SET, of(S, I, I, L))
137                     .put(TAG_PASSWORD_COMPLEXITY_SET, of(S, I, I, I, I, I, I, I, I, I, I))
138                     .put(TAG_PASSWORD_HISTORY_LENGTH_SET, of(S, I, I, I))
139                     .put(TAG_MAX_SCREEN_LOCK_TIMEOUT_SET, of(S, I, I, L))
140                     .put(TAG_MAX_PASSWORD_ATTEMPTS_SET, of(S, I, I, I))
141                     .put(TAG_KEYGUARD_DISABLED_FEATURES_SET, of(S, I, I, I))
142                     .put(TAG_REMOTE_LOCK, of(S, I, I))
143                     .put(TAG_WIPE_FAILURE, of())
144                     .put(TAG_KEY_GENERATED, of(I, S, I))
145                     .put(TAG_KEY_IMPORT, of(I, S, I))
146                     .put(TAG_KEY_DESTRUCTION, of(I, S, I))
147                     .put(TAG_CERT_AUTHORITY_INSTALLED, of(I, S, I))
148                     .put(TAG_CERT_AUTHORITY_REMOVED, of(I, S, I))
149                     .put(TAG_USER_RESTRICTION_ADDED, of(S, I, S))
150                     .put(TAG_USER_RESTRICTION_REMOVED, of(S, I, S))
151                     .put(TAG_CRYPTO_SELF_TEST_COMPLETED, of(I))
152                     .put(TAG_KEY_INTEGRITY_VIOLATION, of(S, I))
153                     .put(TAG_CERT_VALIDATION_FAILURE, of(S))
154                     .put(TAG_CAMERA_POLICY_SET, of(S, I, I, I))
155                     .put(TAG_PASSWORD_COMPLEXITY_REQUIRED, of(S, I, I, I))
156                     .build();
157 
158     private static final String GENERATED_KEY_ALIAS = "generated_key_alias";
159     private static final String IMPORTED_KEY_ALIAS = "imported_key_alias";
160 
161     // Indices of various fields in event payload.
162     private static final int SUCCESS_INDEX = 0;
163     private static final int ALIAS_INDEX = 1;
164     private static final int UID_INDEX = 2;
165     private static final int USERID_INDEX = 2;
166     private static final int SUBJECT_INDEX = 1;
167     private static final int ADMIN_PKG_INDEX = 0;
168     private static final int ADMIN_USER_INDEX = 1;
169     private static final int TARGET_USER_INDEX = 2;
170     private static final int PWD_LEN_INDEX = 3;
171     private static final int PWD_QUALITY_INDEX = 4;
172     private static final int LETTERS_INDEX = 5;
173     private static final int NON_LETTERS_INDEX = 6;
174     private static final int NUMERIC_INDEX = 7;
175     private static final int UPPERCASE_INDEX = 8;
176     private static final int LOWERCASE_INDEX = 9;
177     private static final int SYMBOLS_INDEX = 10;
178     private static final int PWD_EXPIRATION_INDEX = 3;
179     private static final int PWD_HIST_LEN_INDEX = 3;
180     private static final int USER_RESTRICTION_INDEX = 2;
181     private static final int MAX_PWD_ATTEMPTS_INDEX = 3;
182     private static final int KEYGUARD_FEATURES_INDEX = 3;
183     private static final int MAX_SCREEN_TIMEOUT_INDEX = 3;
184     private static final int CAMERA_DISABLED_INDEX = 3;
185 
186     // Value that indicates success in events that have corresponding field in their payload.
187     private static final int SUCCESS_VALUE = 1;
188 
189     private static final int TEST_PWD_LENGTH = 10;
190     // Min number of various character types to use.
191     private static final int TEST_PWD_CHARS = 2;
192 
193     private static final long TEST_PWD_EXPIRATION_TIMEOUT = TimeUnit.DAYS.toMillis(356);
194     private static final int TEST_PWD_HISTORY_LENGTH = 3;
195     private static final int TEST_PWD_MAX_ATTEMPTS = 5;
196     private static final long TEST_MAX_TIME_TO_LOCK = TimeUnit.HOURS.toMillis(1);
197 
198     /**
199      * Test: retrieving security logs can only be done if there's one user on the device or all
200      * secondary users / profiles are affiliated.
201      */
testRetrievingSecurityLogsThrowsSecurityException()202     public void testRetrievingSecurityLogsThrowsSecurityException() {
203         try {
204             mDevicePolicyManager.retrieveSecurityLogs(ADMIN_RECEIVER_COMPONENT);
205             fail("did not throw expected SecurityException");
206         } catch (SecurityException expected) {
207         }
208     }
209 
210     /**
211      * Test: retrieving previous security logs can only be done if there's one user on the device or
212      * all secondary users / profiles are affiliated.
213      */
testRetrievingPreviousSecurityLogsThrowsSecurityException()214     public void testRetrievingPreviousSecurityLogsThrowsSecurityException() {
215         try {
216             mDevicePolicyManager.retrievePreRebootSecurityLogs(ADMIN_RECEIVER_COMPONENT);
217             fail("did not throw expected SecurityException");
218         } catch (SecurityException expected) {
219         }
220     }
221 
222     /**
223      * Test: retrieves security logs and verifies that all events generated as a result of host
224      * side actions and by {@link #testGenerateLogs()} are there.
225      */
testVerifyGeneratedLogs()226     public void testVerifyGeneratedLogs() throws Exception {
227         forceSecurityLogs();
228 
229         final List<SecurityEvent> events = getEvents();
230 
231         verifyAutomaticEventsPresent(events);
232         verifyKeystoreEventsPresent(events);
233         verifyKeyChainEventsPresent(events);
234         verifyAdminEventsPresent(events);
235         verifyAdbShellCommand(events); // Event generated from host side logic
236         if (mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) {
237             verifyEventsRedacted(events);
238         }
239     }
240 
forceSecurityLogs()241     private void forceSecurityLogs() throws Exception {
242         UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
243                 .executeShellCommand("dpm force-security-logs");
244     }
245 
verifyAutomaticEventsPresent(List<SecurityEvent> events)246     private void verifyAutomaticEventsPresent(List<SecurityEvent> events) {
247         verifyOsStartupEventPresent(events);
248         verifyLoggingStartedEventPresent(events);
249         verifyCryptoSelfTestEventPresent(events);
250     }
251 
verifyKeyChainEventsPresent(List<SecurityEvent> events)252     private void verifyKeyChainEventsPresent(List<SecurityEvent> events) {
253         verifyCertInstalledEventPresent(events);
254         verifyCertUninstalledEventPresent(events);
255     }
256 
verifyKeystoreEventsPresent(List<SecurityEvent> events)257     private void verifyKeystoreEventsPresent(List<SecurityEvent> events) {
258         verifyKeyGeneratedEventPresent(events, GENERATED_KEY_ALIAS);
259         verifyKeyDeletedEventPresent(events, GENERATED_KEY_ALIAS);
260         verifyKeyImportedEventPresent(events, IMPORTED_KEY_ALIAS);
261         verifyKeyDeletedEventPresent(events, IMPORTED_KEY_ALIAS);
262     }
263 
verifyAdminEventsPresent(List<SecurityEvent> events)264     private void verifyAdminEventsPresent(List<SecurityEvent> events) {
265         if (mHasSecureLockScreen) {
266             verifyPasswordComplexityEventsPresent(events);
267             verifyNewStylePasswordComplexityEventPresent(events);
268         }
269         verifyLockingPolicyEventsPresent(events);
270         verifyUserRestrictionEventsPresent(events);
271         verifyCameraPolicyEvents(events);
272     }
verifyAdbShellCommand(List<SecurityEvent> events)273     private void verifyAdbShellCommand(List<SecurityEvent> events) {
274         // Won't be able to locate the command on org-owned devices, as it will be redacted.
275         if (!mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) {
276             findEvent("adb command", events,
277                     e -> e.getTag() == TAG_ADB_SHELL_CMD &&
278                             e.getData().equals("whoami"));
279 
280         }
281     }
282 
verifyEventsRedacted(List<SecurityEvent> events)283     private void verifyEventsRedacted(List<SecurityEvent> events) {
284         final int userId = Process.myUserHandle().getIdentifier();
285         for (SecurityEvent event : events) {
286             switch (event.getTag()) {
287                 case TAG_ADB_SHELL_CMD:
288                     assertTrue(TextUtils.isEmpty((String) event.getData()));
289                     break;
290                 case TAG_APP_PROCESS_START:
291                 case TAG_KEY_GENERATED:
292                 case TAG_KEY_IMPORT:
293                 case TAG_KEY_DESTRUCTION:
294                     assertEquals(userId, UserHandle.getUserId(getInt(event, UID_INDEX)));
295                     break;
296                 case TAG_CERT_AUTHORITY_INSTALLED:
297                 case TAG_CERT_AUTHORITY_REMOVED:
298                     assertEquals(userId, getInt(event, USERID_INDEX));
299                     break;
300                 case TAG_KEY_INTEGRITY_VIOLATION:
301                     assertEquals(userId, UserHandle.getUserId(getInt(event, 1)));
302                     break;
303             }
304         }
305     }
306 
307     /**
308      * Generates events for positive test cases.
309      */
testGenerateLogs()310     public void testGenerateLogs() throws Exception {
311         generateKeystoreEvents();
312         generateKeyChainEvents();
313         generateAdminEvents();
314     }
315 
generateKeyChainEvents()316     private void generateKeyChainEvents() {
317         installCaCert();
318         uninstallCaCert();
319     }
320 
generateKeystoreEvents()321     private void generateKeystoreEvents() throws Exception {
322         generateKey(GENERATED_KEY_ALIAS);
323         deleteKey(GENERATED_KEY_ALIAS);
324         importKey(IMPORTED_KEY_ALIAS);
325         deleteKey(IMPORTED_KEY_ALIAS);
326     }
327 
generateAdminEvents()328     private void generateAdminEvents() {
329         if (mHasSecureLockScreen) {
330             generatePasswordComplexityEvents();
331             generateNewStylePasswordComplexityEvents();
332         }
333         generateLockingPolicyEvents();
334         generateUserRestrictionEvents();
335         generateCameraPolicyEvents();
336     }
337 
338     /**
339      * Fetches and checks the events.
340      */
getEvents()341     private List<SecurityEvent> getEvents() throws Exception {
342         List<SecurityEvent> events = null;
343         // Retry once after seeping for 1 second, in case "dpm force-security-logs" hasn't taken
344         // effect just yet.
345         for (int i = 0; i < 2 && events == null; i++) {
346             events = mDevicePolicyManager.retrieveSecurityLogs(ADMIN_RECEIVER_COMPONENT);
347             Log.v(TAG, "getEvents(), batch #" + i + ": "  + (events == null ? -1 : events.size())
348                     + " events");
349             if (events == null) sleep(1000);
350         }
351 
352         Log.d(TAG, "getEvents(): received " + events.size() + " events");
353         if (VERBOSE) dumpSecurityLogs(events);
354 
355         try {
356             verifySecurityLogs(events);
357         } catch (AssertionFailedError e) {
358             dumpSecurityLogs(events);
359             throw e;
360         }
361 
362         return events;
363     }
364 
365     /**
366      * Test: check that there are no gaps between ids in two consecutive batches. Shared preference
367      * is used to store these numbers between test invocations.
368      */
testVerifyLogIds()369     public void testVerifyLogIds() throws Exception {
370         forceSecurityLogs();
371         final String param = InstrumentationRegistry.getArguments().getString(ARG_BATCH_NUMBER);
372         final int batchId = param == null ? 0 : Integer.parseInt(param);
373         final List<SecurityEvent> events = getEvents();
374         final SharedPreferences prefs =
375                 mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
376 
377         final long firstId = events.get(0).getId();
378         if (batchId == 0) {
379             assertEquals("Event id wasn't reset.", 0L, firstId);
380         } else {
381             final String prevBatchLastIdKey = PREF_KEY_PREFIX + (batchId - 1);
382             assertTrue("Last event id from previous batch not found in shared prefs",
383                     prefs.contains(prevBatchLastIdKey));
384             final long prevBatchLastId = prefs.getLong(prevBatchLastIdKey, 0);
385             assertEquals("Event ids aren't consecutive between batches",
386                     firstId, prevBatchLastId + 1);
387         }
388 
389         final String currBatchLastIdKey = PREF_KEY_PREFIX + batchId;
390         final long lastId = events.get(events.size() - 1).getId();
391         prefs.edit().putLong(currBatchLastIdKey, lastId).commit();
392     }
393 
verifySecurityLogs(List<SecurityEvent> events)394     private void verifySecurityLogs(List<SecurityEvent> events) {
395         assertTrue("Unable to get events", events != null && events.size() > 0);
396 
397         // We don't know much about the events, so just call public API methods.
398         for (int i = 0; i < events.size(); i++) {
399             final SecurityEvent event = events.get(i);
400 
401             // Skip liblog dropped event.
402             if (event.getTag() == TAG_LIBLOG_DROPPED) {
403                 continue;
404             }
405 
406             verifyPayloadTypes(event);
407 
408             // Test id for monotonically increasing.
409             if (i > 0) {
410                 assertEquals("Event IDs are not monotonically increasing within the batch",
411                         events.get(i - 1).getId() + 1, event.getId());
412             }
413 
414             // Test parcelling: flatten to a parcel.
415             Parcel p = Parcel.obtain();
416             event.writeToParcel(p, 0);
417             p.setDataPosition(0);
418 
419             // Restore from parcel and check contents.
420             final SecurityEvent restored = SecurityEvent.CREATOR.createFromParcel(p);
421             p.recycle();
422 
423             final int level = event.getLogLevel();
424             assertTrue(level == LEVEL_INFO || level == LEVEL_WARNING || level == LEVEL_ERROR);
425 
426             // For some events data is encapsulated into Object array.
427             if (event.getData() instanceof Object[]) {
428                 assertTrue("Parcelling changed the array returned by getData",
429                         Arrays.equals((Object[]) event.getData(), (Object[]) restored.getData()));
430             } else {
431                 assertEquals("Parcelling changed the result of getData",
432                         event.getData(), restored.getData());
433             }
434             assertEquals("Parcelling changed the result of getId",
435                     event.getId(), restored.getId());
436             assertEquals("Parcelling changed the result of getTag",
437                     event.getTag(), restored.getTag());
438             assertEquals("Parcelling changed the result of getTimeNanos",
439                     event.getTimeNanos(), restored.getTimeNanos());
440             assertEquals("Parcelling changed the result of describeContents",
441                     event.describeContents(), restored.describeContents());
442         }
443     }
444 
verifyPayloadTypes(SecurityEvent event)445     private void verifyPayloadTypes(SecurityEvent event) {
446         final List<Class> payloadTypes = PAYLOAD_TYPES_MAP.get(event.getTag());
447         assertNotNull("event type unknown: " + event.getTag(), payloadTypes);
448 
449         if (payloadTypes.size() == 0) {
450             // No payload.
451             assertNull("non-null payload", event.getData());
452         } else if (payloadTypes.size() == 1) {
453             // Singleton payload.
454             assertTrue(payloadTypes.get(0).isInstance(event.getData()));
455         } else {
456             // Payload is incapsulated into Object[]
457             assertTrue(event.getData() instanceof Object[]);
458             final Object[] dataArray = (Object[]) event.getData();
459             assertEquals(payloadTypes.size(), dataArray.length);
460             for (int i = 0; i < payloadTypes.size(); i++) {
461                 assertTrue(payloadTypes.get(i).isInstance(dataArray[i]));
462             }
463         }
464     }
465 
verifyOsStartupEventPresent(List<SecurityEvent> events)466     private void verifyOsStartupEventPresent(List<SecurityEvent> events) {
467         final SecurityEvent event = findEvent("os startup", events, TAG_OS_STARTUP);
468         // Verified boot state, empty if running on emulator
469         assertOneOf(ImmutableSet.of("", "green", "yellow", "orange"), getString(event, 0));
470         // dm-verity mode, empty if it is disabled
471         assertOneOf(ImmutableSet.of("", "enforcing", "eio", "disabled"), getString(event, 1));
472     }
473 
assertOneOf(Set<String> allowed, String s)474     private void assertOneOf(Set<String> allowed, String s) {
475         assertTrue(String.format("\"%s\" is not one of [%s]", s, String.join(", ", allowed)),
476                 allowed.contains(s));
477     }
478 
verifyCryptoSelfTestEventPresent(List<SecurityEvent> events)479     private void verifyCryptoSelfTestEventPresent(List<SecurityEvent> events) {
480         final SecurityEvent event = findEvent("crypto self test complete",
481                 events, TAG_CRYPTO_SELF_TEST_COMPLETED);
482         // Success code.
483         assertEquals(1, getInt(event));
484     }
485 
verifyLoggingStartedEventPresent(List<SecurityEvent> events)486     private void verifyLoggingStartedEventPresent(List<SecurityEvent> events) {
487         findEvent("logging started", events, TAG_LOGGING_STARTED);
488     }
489 
findEvent(String description, List<SecurityEvent> events, int tag)490     private SecurityEvent findEvent(String description, List<SecurityEvent> events, int tag) {
491         return findEvent(description, events, e -> e.getTag() == tag);
492     }
493 
findEvent(String description, List<SecurityEvent> events, Predicate<SecurityEvent> predicate)494     private SecurityEvent findEvent(String description, List<SecurityEvent> events,
495             Predicate<SecurityEvent> predicate) {
496         final List<SecurityEvent> matches =
497                 events.stream().filter(predicate).collect(Collectors.toList());
498         assertEquals("Invalid number of matching events: " + description, 1, matches.size());
499         return matches.get(0);
500     }
501 
getDatum(SecurityEvent event, int index)502     private static Object getDatum(SecurityEvent event, int index) {
503         final Object[] dataArray = (Object[]) event.getData();
504         return dataArray[index];
505     }
506 
getString(SecurityEvent event, int index)507     private static String getString(SecurityEvent event, int index) {
508         return (String) getDatum(event, index);
509     }
510 
getInt(SecurityEvent event)511     private static int getInt(SecurityEvent event) {
512         return (Integer) event.getData();
513     }
514 
getInt(SecurityEvent event, int index)515     private static int getInt(SecurityEvent event, int index) {
516         return (Integer) getDatum(event, index);
517     }
518 
getLong(SecurityEvent event, int index)519     private static long getLong(SecurityEvent event, int index) {
520         return (Long) getDatum(event, index);
521     }
522 
523     /**
524      * Test: Test enabling security logging. This test should be executed after installing a device
525      * owner so that we check that logging is not enabled by default. This test has a side effect:
526      * security logging is enabled after its execution.
527      */
testEnablingSecurityLogging()528     public void testEnablingSecurityLogging() {
529         assertFalse(mDevicePolicyManager.isSecurityLoggingEnabled(ADMIN_RECEIVER_COMPONENT));
530         mDevicePolicyManager.setSecurityLoggingEnabled(ADMIN_RECEIVER_COMPONENT, true);
531         assertTrue(mDevicePolicyManager.isSecurityLoggingEnabled(ADMIN_RECEIVER_COMPONENT));
532     }
533 
534     /**
535      * Test: Test disabling security logging. This test has a side effect: security logging is
536      * disabled after its execution.
537      */
testDisablingSecurityLogging()538     public void testDisablingSecurityLogging() {
539         mDevicePolicyManager.setSecurityLoggingEnabled(ADMIN_RECEIVER_COMPONENT, false);
540         assertFalse(mDevicePolicyManager.isSecurityLoggingEnabled(ADMIN_RECEIVER_COMPONENT));
541 
542         // Verify that logs are actually not available.
543         assertNull(mDevicePolicyManager.retrieveSecurityLogs(ADMIN_RECEIVER_COMPONENT));
544     }
545 
546     /**
547      * Test: retrieving security logs should be rate limited - subsequent attempts should return
548      * null.
549      */
testSecurityLoggingRetrievalRateLimited()550     public void testSecurityLoggingRetrievalRateLimited() {
551         final List<SecurityEvent> logs = mDevicePolicyManager.retrieveSecurityLogs(
552                 ADMIN_RECEIVER_COMPONENT);
553         // if logs is null it means that that attempt was rate limited => test PASS
554         if (logs != null) {
555             assertNull(mDevicePolicyManager.retrieveSecurityLogs(ADMIN_RECEIVER_COMPONENT));
556             assertNull(mDevicePolicyManager.retrieveSecurityLogs(ADMIN_RECEIVER_COMPONENT));
557         }
558     }
559 
testSetDelegateScope_delegationSecurityLogging()560     public void testSetDelegateScope_delegationSecurityLogging() {
561         setDelegatedScopes(DELEGATE_APP_PKG, Arrays.asList(DELEGATION_SECURITY_LOGGING));
562 
563         assertThat(mDevicePolicyManager.getDelegatedScopes(
564                 ADMIN_RECEIVER_COMPONENT, DELEGATE_APP_PKG)).contains(DELEGATION_SECURITY_LOGGING);
565     }
566 
testSetDelegateScope_noDelegation()567     public void testSetDelegateScope_noDelegation() {
568         setDelegatedScopes(DELEGATE_APP_PKG, Arrays.asList());
569 
570         assertThat(mDevicePolicyManager.getDelegatedScopes(
571                 ADMIN_RECEIVER_COMPONENT, DELEGATE_APP_PKG))
572                 .doesNotContain(DELEGATION_SECURITY_LOGGING);
573     }
574 
generateKey(String keyAlias)575     private void generateKey(String keyAlias) throws Exception {
576         final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
577         generator.initialize(
578                 new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_SIGN).build());
579         final KeyPair keyPair = generator.generateKeyPair();
580         assertNotNull(keyPair);
581     }
582 
verifyKeyGeneratedEventPresent(List<SecurityEvent> events, String alias)583     private void verifyKeyGeneratedEventPresent(List<SecurityEvent> events, String alias) {
584         findEvent("key generated", events,
585                 e -> e.getTag() == TAG_KEY_GENERATED
586                         && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE
587                         && getString(e, ALIAS_INDEX).contains(alias)
588                         && getInt(e, UID_INDEX) == Process.myUid());
589     }
590 
importKey(String alias)591     private void importKey(String alias) throws Exception{
592         final KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
593         ks.load(null);
594         ks.setEntry(alias, new KeyStore.SecretKeyEntry(new SecretKeySpec(new byte[32], "AES")),
595                 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT).build());
596     }
597 
verifyKeyImportedEventPresent(List<SecurityEvent> events, String alias)598     private void verifyKeyImportedEventPresent(List<SecurityEvent> events, String alias) {
599         findEvent("key imported", events,
600                 e -> e.getTag() == TAG_KEY_IMPORT
601                         && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE
602                         && getString(e, ALIAS_INDEX).contains(alias)
603                         && getInt(e, UID_INDEX) == Process.myUid());
604     }
605 
deleteKey(String keyAlias)606     private void deleteKey(String keyAlias) throws Exception {
607         final KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
608         ks.load(null);
609         ks.deleteEntry(keyAlias);
610     }
611 
verifyKeyDeletedEventPresent(List<SecurityEvent> events, String alias)612     private void verifyKeyDeletedEventPresent(List<SecurityEvent> events, String alias) {
613         findEvent("key deleted", events,
614                 e -> e.getTag() == TAG_KEY_DESTRUCTION
615                         && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE
616                         && getString(e, ALIAS_INDEX).contains(alias)
617                         && getInt(e, UID_INDEX) == Process.myUid());
618     }
619 
installCaCert()620     private void installCaCert() {
621         assertTrue(
622                 mDevicePolicyManager.installCaCert(ADMIN_RECEIVER_COMPONENT, TEST_CA.getBytes()));
623     }
624 
verifyCertInstalledEventPresent(List<SecurityEvent> events)625     private void verifyCertInstalledEventPresent(List<SecurityEvent> events) {
626         findEvent("cert authority installed", events,
627                 e -> e.getTag() == TAG_CERT_AUTHORITY_INSTALLED
628                         && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE
629                         && getString(e, SUBJECT_INDEX).equals(TEST_CA_SUBJECT));
630     }
631 
uninstallCaCert()632     private void uninstallCaCert() {
633         mDevicePolicyManager.uninstallCaCert(ADMIN_RECEIVER_COMPONENT, TEST_CA.getBytes());
634     }
635 
verifyCertUninstalledEventPresent(List<SecurityEvent> events)636     private void verifyCertUninstalledEventPresent(List<SecurityEvent> events) {
637         findEvent("cert authority removed", events,
638                 e -> e.getTag() == TAG_CERT_AUTHORITY_REMOVED
639                         && getInt(e, SUCCESS_INDEX) == SUCCESS_VALUE
640                         && getString(e, SUBJECT_INDEX).equals(TEST_CA_SUBJECT));
641     }
642 
generatePasswordComplexityEvents()643     private void generatePasswordComplexityEvents() {
644         DevicePolicyManager dpm = getDpmToGenerateEvents();
645 
646         dpm.setPasswordQuality(ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_COMPLEX);
647         dpm.setPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT, TEST_PWD_LENGTH);
648         dpm.setPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT, TEST_PWD_CHARS);
649         dpm.setPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT, TEST_PWD_CHARS);
650         dpm.setPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT, TEST_PWD_CHARS);
651         dpm.setPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT, TEST_PWD_CHARS);
652         dpm.setPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT, TEST_PWD_CHARS);
653         dpm.setPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT, TEST_PWD_CHARS);
654     }
655 
generateNewStylePasswordComplexityEvents()656     private void generateNewStylePasswordComplexityEvents() {
657         DevicePolicyManager dpm = getDpmToGenerateEvents();
658 
659         dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
660     }
661 
verifyPasswordComplexityEventsPresent(List<SecurityEvent> events)662     private void verifyPasswordComplexityEventsPresent(List<SecurityEvent> events) {
663         final int userId = Process.myUserHandle().getIdentifier();
664         // This reflects default values for password complexity event payload fields.
665         final Object[] expectedPayload = new Object[] {
666                 ADMIN_RECEIVER_COMPONENT.getPackageName(), // admin package
667                 userId,                    // admin user
668                 userId,                    // target user
669                 0,                         // default password length
670                 0,                         // default password quality
671                 1,                         // default min letters
672                 0,                         // default min non-letters
673                 1,                         // default min numeric
674                 0,                         // default min uppercase
675                 0,                         // default min lowercase
676                 1,                         // default min symbols
677         };
678 
679         // The order should be consistent with the order in generatePasswordComplexityEvents(), so
680         // that the expected values change in the same sequence as when setting password policies.
681         expectedPayload[PWD_QUALITY_INDEX] = PASSWORD_QUALITY_COMPLEX;
682         findPasswordComplexityEvent("set pwd quality", events, expectedPayload);
683         expectedPayload[PWD_LEN_INDEX] = TEST_PWD_LENGTH;
684         findPasswordComplexityEvent("set pwd length", events, expectedPayload);
685         expectedPayload[LETTERS_INDEX] = TEST_PWD_CHARS;
686         findPasswordComplexityEvent("set pwd min letters", events, expectedPayload);
687         expectedPayload[NON_LETTERS_INDEX] = TEST_PWD_CHARS;
688         findPasswordComplexityEvent("set pwd min non-letters", events, expectedPayload);
689         expectedPayload[UPPERCASE_INDEX] = TEST_PWD_CHARS;
690         findPasswordComplexityEvent("set pwd min uppercase", events, expectedPayload);
691         expectedPayload[LOWERCASE_INDEX] = TEST_PWD_CHARS;
692         findPasswordComplexityEvent("set pwd min lowercase", events, expectedPayload);
693         expectedPayload[NUMERIC_INDEX] = TEST_PWD_CHARS;
694         findPasswordComplexityEvent("set pwd min numeric", events, expectedPayload);
695         expectedPayload[SYMBOLS_INDEX] = TEST_PWD_CHARS;
696         findPasswordComplexityEvent("set pwd min symbols", events, expectedPayload);
697     }
698 
verifyNewStylePasswordComplexityEventPresent(List<SecurityEvent> events)699     private void verifyNewStylePasswordComplexityEventPresent(List<SecurityEvent> events) {
700         final int userId = Process.myUserHandle().getIdentifier();
701         // This reflects default values for password complexity event payload fields.
702         final Object[] expectedPayload = new Object[] {
703                 ADMIN_RECEIVER_COMPONENT.getPackageName(), // admin package
704                 userId,                    // admin user
705                 userId,                    // target user
706                 PASSWORD_COMPLEXITY_HIGH   // password complexity
707         };
708 
709         findNewStylePasswordComplexityEvent("require password complexity", events, expectedPayload);
710     }
711 
generateLockingPolicyEvents()712     private void generateLockingPolicyEvents() {
713         DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
714 
715         if (mHasSecureLockScreen) {
716             dpm.setPasswordExpirationTimeout(ADMIN_RECEIVER_COMPONENT, TEST_PWD_EXPIRATION_TIMEOUT);
717             dpm.setPasswordHistoryLength(ADMIN_RECEIVER_COMPONENT, TEST_PWD_HISTORY_LENGTH);
718             dpm.setMaximumFailedPasswordsForWipe(ADMIN_RECEIVER_COMPONENT, TEST_PWD_MAX_ATTEMPTS);
719         }
720         dpm.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
721                 KEYGUARD_DISABLE_FINGERPRINT);
722         dpm.setMaximumTimeToLock(ADMIN_RECEIVER_COMPONENT, TEST_MAX_TIME_TO_LOCK);
723         dpm.lockNow();
724     }
725 
verifyLockingPolicyEventsPresent(List<SecurityEvent> events)726     private void verifyLockingPolicyEventsPresent(List<SecurityEvent> events) {
727         final int userId = Process.myUserHandle().getIdentifier();
728         final String packageName = ADMIN_RECEIVER_COMPONENT.getPackageName();
729         if (mHasSecureLockScreen) {
730             findEvent("set password expiration", events,
731                     e -> e.getTag() == TAG_PASSWORD_EXPIRATION_SET &&
732                             getString(e, ADMIN_PKG_INDEX).equals(packageName) &&
733                             getInt(e, ADMIN_USER_INDEX) == userId &&
734                             getInt(e, TARGET_USER_INDEX) == userId &&
735                             getLong(e, PWD_EXPIRATION_INDEX) == TEST_PWD_EXPIRATION_TIMEOUT);
736 
737             findEvent("set password history length", events,
738                     e -> e.getTag() == TAG_PASSWORD_HISTORY_LENGTH_SET &&
739                             getString(e, ADMIN_PKG_INDEX).equals(packageName) &&
740                             getInt(e, ADMIN_USER_INDEX) == userId &&
741                             getInt(e, TARGET_USER_INDEX) == userId &&
742                             getInt(e, PWD_HIST_LEN_INDEX) == TEST_PWD_HISTORY_LENGTH);
743 
744             findEvent("set password attempts", events,
745                     e -> e.getTag() == TAG_MAX_PASSWORD_ATTEMPTS_SET &&
746                             getString(e, ADMIN_PKG_INDEX).equals(packageName) &&
747                             getInt(e, ADMIN_USER_INDEX) == userId &&
748                             getInt(e, TARGET_USER_INDEX) == userId &&
749                             getInt(e, MAX_PWD_ATTEMPTS_INDEX) == TEST_PWD_MAX_ATTEMPTS);
750         }
751 
752         findEvent("set keyguard disabled features", events,
753                 e -> e.getTag() == TAG_KEYGUARD_DISABLED_FEATURES_SET &&
754                         getString(e, ADMIN_PKG_INDEX).equals(packageName) &&
755                         getInt(e, ADMIN_USER_INDEX) == userId &&
756                         getInt(e, TARGET_USER_INDEX) == userId &&
757                         getInt(e, KEYGUARD_FEATURES_INDEX) == KEYGUARD_DISABLE_FINGERPRINT);
758 
759         findEvent("set screen lock timeout", events,
760                 e -> e.getTag() == TAG_MAX_SCREEN_LOCK_TIMEOUT_SET &&
761                         getString(e, ADMIN_PKG_INDEX).equals(packageName) &&
762                         getInt(e, ADMIN_USER_INDEX) == userId &&
763                         getInt(e, TARGET_USER_INDEX) == userId &&
764                         getLong(e, MAX_SCREEN_TIMEOUT_INDEX) == TEST_MAX_TIME_TO_LOCK);
765 
766         findEvent("set screen lock timeout", events,
767                 e -> e.getTag() == TAG_REMOTE_LOCK &&
768                         getString(e, ADMIN_PKG_INDEX).equals(packageName) &&
769                         getInt(e, ADMIN_USER_INDEX) == userId);
770     }
771 
findPasswordComplexityEvent( String description, List<SecurityEvent> events, Object[] expectedPayload)772     private void findPasswordComplexityEvent(
773             String description, List<SecurityEvent> events, Object[] expectedPayload) {
774         findEvent(description, events,
775                 byTagAndPayload(TAG_PASSWORD_COMPLEXITY_SET, expectedPayload));
776     }
777 
findNewStylePasswordComplexityEvent( String description, List<SecurityEvent> events, Object[] expectedPayload)778     private void findNewStylePasswordComplexityEvent(
779             String description, List<SecurityEvent> events, Object[] expectedPayload) {
780         findEvent(description, events,
781                 byTagAndPayload(TAG_PASSWORD_COMPLEXITY_REQUIRED, expectedPayload));
782     }
783 
byTagAndPayload(int expectedTag, Object[] expectedPayload)784     private Predicate<SecurityEvent> byTagAndPayload(int expectedTag, Object[] expectedPayload) {
785         return (event) -> {
786             boolean tagMatch = event.getTag() == expectedTag;
787             if (!tagMatch) return false;
788 
789             Object[] payload = (Object[]) event.getData();
790             boolean payloadMatch = Arrays.equals(payload, expectedPayload);
791 
792             if (!payloadMatch) {
793                 Log.w(TAG, "Found event (id=" + event.getId() + ") with tag "
794                         + eventLogtoString(event.getTag()) + ", but invalid payload: "
795                         + "expected=" + Arrays.toString(expectedPayload)
796                         + ", actual=" + Arrays.toString(payload));
797             } else if (VERBOSE) {
798                 Log.v(TAG, "Found event (id=" + event.getId() + ") with tag "
799                         + eventLogtoString(event.getTag()) + ", and expected payload ("
800                         + Arrays.toString(payload) + ")");
801             }
802             return payloadMatch;
803         };
804     }
805 
generateUserRestrictionEvents()806     private void generateUserRestrictionEvents() {
807         DevicePolicyManager dpm = getDpmToGenerateEvents();
808 
809         dpm.addUserRestriction(ADMIN_RECEIVER_COMPONENT, UserManager.DISALLOW_PRINTING);
810         dpm.clearUserRestriction(ADMIN_RECEIVER_COMPONENT, UserManager.DISALLOW_PRINTING);
811     }
812 
verifyUserRestrictionEventsPresent(List<SecurityEvent> events)813     private void verifyUserRestrictionEventsPresent(List<SecurityEvent> events) {
814         findUserRestrictionEvent("set user restriction", events, TAG_USER_RESTRICTION_ADDED);
815         findUserRestrictionEvent("clear user restriction", events, TAG_USER_RESTRICTION_REMOVED);
816     }
817 
findUserRestrictionEvent(String description, List<SecurityEvent> events, int tag)818     private void findUserRestrictionEvent(String description, List<SecurityEvent> events, int tag) {
819         final int userId = Process.myUserHandle().getIdentifier();
820         findEvent(description, events,
821                 e -> e.getTag() == tag &&
822                         getString(e, ADMIN_PKG_INDEX).equals(
823                                 ADMIN_RECEIVER_COMPONENT.getPackageName()) &&
824                         getInt(e, ADMIN_USER_INDEX) == userId &&
825                         UserManager.DISALLOW_PRINTING.equals(getString(e, USER_RESTRICTION_INDEX)));
826     }
827 
generateCameraPolicyEvents()828     private void generateCameraPolicyEvents() {
829         DevicePolicyManager dpm = getDpmToGenerateEvents();
830 
831         dpm.setCameraDisabled(ADMIN_RECEIVER_COMPONENT, true);
832         dpm.setCameraDisabled(ADMIN_RECEIVER_COMPONENT, false);
833     }
834 
verifyCameraPolicyEvents(List<SecurityEvent> events)835     private void verifyCameraPolicyEvents(List<SecurityEvent> events) {
836         final int userId = Process.myUserHandle().getIdentifier();
837 
838         findEvent("set camera disabled", events,
839                 e -> e.getTag() == TAG_CAMERA_POLICY_SET &&
840                         getString(e, ADMIN_PKG_INDEX).equals(
841                                 ADMIN_RECEIVER_COMPONENT.getPackageName()) &&
842                         getInt(e, ADMIN_USER_INDEX) == userId &&
843                         getInt(e, TARGET_USER_INDEX) == userId &&
844                         getInt(e, CAMERA_DISABLED_INDEX) == 1);
845 
846         findEvent("set camera enabled", events,
847                 e -> e.getTag() == TAG_CAMERA_POLICY_SET &&
848                         getString(e, ADMIN_PKG_INDEX).equals(
849                                 ADMIN_RECEIVER_COMPONENT.getPackageName()) &&
850                         getInt(e, ADMIN_USER_INDEX) == userId &&
851                         getInt(e, TARGET_USER_INDEX) == userId &&
852                         getInt(e, CAMERA_DISABLED_INDEX) == 0);
853     }
854 
getDpmToGenerateEvents()855     private DevicePolicyManager getDpmToGenerateEvents() {
856         // It must use the dpm for the current user, as mDevicePolicyManager tunnels the calls to
857         // the device owner user on headless system user, which would cause a mismatch in the events
858         return mContext.getSystemService(DevicePolicyManager.class);
859     }
860 
eventLogtoString(int log)861     private static String eventLogtoString(int log) {
862         return DebugUtils.constantToString(SecurityLog.class, "TAG_", log);
863     }
864 
toString(SecurityEvent event)865     private static String toString(SecurityEvent event) {
866         return "Event[id=" + event.getId() + ",tag=" + eventLogtoString(event.getTag()) + "]";
867     }
868 
dumpSecurityLogs(List<SecurityEvent> events)869     private void dumpSecurityLogs(List<SecurityEvent> events) {
870         Log.d(TAG, "Security events dump (" + events.size() + " events):");
871         events.forEach((event) -> Log.d(TAG, toString(event)));
872     }
873 }
874