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