• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 
17 package com.android.server.locksettings;
18 
19 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
21 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
22 
23 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
24 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
25 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
26 
27 import static org.mockito.Mockito.any;
28 import static org.mockito.Mockito.atLeastOnce;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.reset;
31 import static org.mockito.Mockito.verify;
32 
33 import android.app.admin.PasswordMetrics;
34 import android.os.RemoteException;
35 import android.os.UserHandle;
36 import android.platform.test.annotations.Presubmit;
37 
38 import androidx.test.filters.SmallTest;
39 
40 import com.android.internal.widget.LockPatternUtils;
41 import com.android.internal.widget.VerifyCredentialResponse;
42 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
43 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
44 import com.android.server.locksettings.SyntheticPasswordManager.PasswordData;
45 
46 import org.mockito.ArgumentCaptor;
47 
48 import java.util.ArrayList;
49 
50 
51 /**
52  * runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests
53  */
54 @SmallTest
55 @Presubmit
56 public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
57 
58     public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 55};
59     public static final byte[] PAYLOAD2 = new byte[] {2, 3, -2, -3, 44, 1};
60 
61     @Override
setUp()62     protected void setUp() throws Exception {
63         super.setUp();
64     }
65 
66     @Override
tearDown()67     protected void tearDown() throws Exception {
68         super.tearDown();
69     }
70 
testPasswordBasedSyntheticPassword()71     public void testPasswordBasedSyntheticPassword() throws RemoteException {
72         final int USER_ID = 10;
73         final byte[] password = "user-password".getBytes();
74         final byte[] badPassword = "bad-password".getBytes();
75         MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
76                 mGateKeeperService, mUserManager, mPasswordSlotManager);
77         AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
78                 null, USER_ID);
79         long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService,
80                 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken,
81                 PASSWORD_QUALITY_ALPHABETIC, USER_ID);
82 
83         AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(
84                 mGateKeeperService, handle, password, USER_ID, null);
85         assertArrayEquals(result.authToken.deriveKeyStorePassword(),
86                 authToken.deriveKeyStorePassword());
87 
88         result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle,
89                 badPassword, USER_ID, null);
90         assertNull(result.authToken);
91     }
92 
disableSyntheticPassword()93     private void disableSyntheticPassword() throws RemoteException {
94         mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
95     }
96 
enableSyntheticPassword()97     private void enableSyntheticPassword() throws RemoteException {
98         mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
99     }
100 
hasSyntheticPassword(int userId)101     private boolean hasSyntheticPassword(int userId) throws RemoteException {
102         return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0;
103     }
104 
testPasswordMigration()105     public void testPasswordMigration() throws RemoteException {
106         final byte[] password = "testPasswordMigration-password".getBytes();
107 
108         disableSyntheticPassword();
109         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
110                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
111         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
112         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
113         enableSyntheticPassword();
114         // Performs migration
115         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
116                 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
117                     .getResponseCode());
118         assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
119         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
120 
121         // SP-based verification
122         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
123                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
124                         .getResponseCode());
125         assertArrayNotEquals(primaryStorageKey,
126                 mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
127     }
128 
initializeCredentialUnderSP(byte[] password, int userId)129     protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
130         enableSyntheticPassword();
131         int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
132                 : PASSWORD_QUALITY_UNSPECIFIED;
133         int type = password != null ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
134                 : LockPatternUtils.CREDENTIAL_TYPE_NONE;
135         mService.setLockCredential(password, type, null, quality, userId, false);
136     }
137 
testSyntheticPasswordChangeCredential()138     public void testSyntheticPasswordChangeCredential() throws RemoteException {
139         final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes();
140         final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes();
141 
142         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
143         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
144         mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
145                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
146         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
147                 newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
148                         .getResponseCode());
149         assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
150     }
151 
testSyntheticPasswordVerifyCredential()152     public void testSyntheticPasswordVerifyCredential() throws RemoteException {
153         final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes();
154         final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes();
155 
156         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
157         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
158                 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
159                         .getResponseCode());
160 
161         assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
162                 badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
163                         .getResponseCode());
164     }
165 
testSyntheticPasswordClearCredential()166     public void testSyntheticPasswordClearCredential() throws RemoteException {
167         final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
168         final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
169 
170         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
171         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
172         // clear password
173         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
174                 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
175         assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
176 
177         // set a new password
178         mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
179                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
180         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
181                 badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
182                         .getResponseCode());
183         assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
184     }
185 
testSyntheticPasswordChangeCredentialKeepsAuthSecret()186     public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException {
187         final byte[] password =
188                 "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes();
189         final byte[] badPassword =
190                 "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes();
191 
192         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
193         mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
194                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
195         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
196                 badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
197                         .getResponseCode());
198 
199         // Check the same secret was passed each time
200         ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
201         verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture());
202         assertEquals(1, secret.getAllValues().stream().distinct().count());
203     }
204 
testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret()205     public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
206         final byte[] password =
207                 "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes();
208         final byte[] newPassword =
209                 "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes();
210 
211         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
212         reset(mAuthSecretService);
213         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
214                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
215                         .getResponseCode());
216         verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
217     }
218 
testSecondaryUserDoesNotPassAuthSecret()219     public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException {
220         final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes();
221 
222         initializeCredentialUnderSP(password, SECONDARY_USER_ID);
223         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
224                 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
225                         .getResponseCode());
226         verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
227     }
228 
testNoSyntheticPasswordOrCredentialDoesNotPassAuthSecret()229     public void testNoSyntheticPasswordOrCredentialDoesNotPassAuthSecret() throws RemoteException {
230         // Setting null doesn't create a synthetic password
231         initializeCredentialUnderSP(null, PRIMARY_USER_ID);
232 
233         reset(mAuthSecretService);
234         mService.onUnlockUser(PRIMARY_USER_ID);
235         flushHandlerTasks();
236         verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
237     }
238 
testSyntheticPasswordAndCredentialDoesNotPassAuthSecret()239     public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
240         final byte[] password = "passwordForASyntheticPassword".getBytes();
241         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
242 
243         reset(mAuthSecretService);
244         mService.onUnlockUser(PRIMARY_USER_ID);
245         flushHandlerTasks();
246         verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
247     }
248 
testSyntheticPasswordButNoCredentialPassesAuthSecret()249     public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
250         final byte[] password = "getASyntheticPassword".getBytes();
251         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
252         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
253                 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
254 
255         reset(mAuthSecretService);
256         mService.onUnlockUser(PRIMARY_USER_ID);
257         flushHandlerTasks();
258         verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
259     }
260 
testManagedProfileUnifiedChallengeMigration()261     public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
262         final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
263         disableSyntheticPassword();
264         mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
265                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
266         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
267         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
268         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
269         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
270         final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
271         assertTrue(primarySid != 0);
272         assertTrue(profileSid != 0);
273         assertTrue(profileSid != primarySid);
274 
275         // do migration
276         enableSyntheticPassword();
277         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
278                 UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
279                         .getResponseCode());
280 
281         // verify
282         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
283                 UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
284                         .getResponseCode());
285         assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
286         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
287         assertArrayNotEquals(primaryStorageKey,
288                 mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
289         assertArrayNotEquals(profileStorageKey,
290                 mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
291         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
292         assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
293     }
294 
testManagedProfileSeparateChallengeMigration()295     public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
296         final byte[] primaryPassword =
297                 "testManagedProfileSeparateChallengeMigration-primary".getBytes();
298         final byte[] profilePassword =
299                 "testManagedProfileSeparateChallengeMigration-profile".getBytes();
300         disableSyntheticPassword();
301         mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
302                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
303         mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
304                 PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
305         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
306         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
307         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
308         final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
309         assertTrue(primarySid != 0);
310         assertTrue(profileSid != 0);
311         assertTrue(profileSid != primarySid);
312 
313         // do migration
314         enableSyntheticPassword();
315         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
316                 primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
317                         .getResponseCode());
318         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
319                 profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
320                 0, MANAGED_PROFILE_USER_ID).getResponseCode());
321 
322         // verify
323         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
324                 primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
325                         .getResponseCode());
326         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
327                 profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
328                 0, MANAGED_PROFILE_USER_ID).getResponseCode());
329         assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
330         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
331         assertArrayNotEquals(primaryStorageKey,
332                 mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
333         assertArrayNotEquals(profileStorageKey,
334                 mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
335         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
336         assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
337     }
338 
testTokenBasedResetPassword()339     public void testTokenBasedResetPassword() throws RemoteException {
340         final byte[] password = "password".getBytes();
341         final byte[] pattern = "123654".getBytes();
342         final byte[] token = "some-high-entropy-secure-token".getBytes();
343         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
344         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
345 
346         assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
347         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
348         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
349         assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
350 
351         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
352                 PRIMARY_USER_ID).getResponseCode();
353         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
354         assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
355 
356         mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
357                 handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
358 
359         // Verify DPM gets notified about new device lock
360         flushHandlerTasks();
361         final PasswordMetrics metric = PasswordMetrics.computeForCredential(
362                 LockPatternUtils.CREDENTIAL_TYPE_PATTERN, pattern);
363         verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID);
364 
365         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
366                 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
367                     .getResponseCode());
368         assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
369     }
370 
testTokenBasedClearPassword()371     public void testTokenBasedClearPassword() throws RemoteException {
372         final byte[] password = "password".getBytes();
373         final byte[] pattern = "123654".getBytes();
374         final byte[] token = "some-high-entropy-secure-token".getBytes();
375         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
376         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
377 
378         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
379         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
380 
381         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
382                 0, PRIMARY_USER_ID).getResponseCode();
383         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
384 
385         mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
386                 handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
387         flushHandlerTasks(); // flush the unlockUser() call before changing password again
388         mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
389                 handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
390 
391         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
392                 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
393                         .getResponseCode());
394         assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
395     }
396 
testTokenBasedResetPasswordAfterCredentialChanges()397     public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException {
398         final byte[] password = "password".getBytes();
399         final byte[] pattern = "123654".getBytes();
400         final byte[] newPassword = "password".getBytes();
401         final byte[] token = "some-high-entropy-secure-token".getBytes();
402         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
403         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
404 
405         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
406         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
407 
408         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
409                 0, PRIMARY_USER_ID).getResponseCode();
410         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
411 
412         mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
413                 PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
414 
415         mLocalService.setLockCredentialWithToken(newPassword,
416                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
417                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
418 
419         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
420                 newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
421                     .getResponseCode());
422         assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
423     }
424 
testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration()425     public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration()
426             throws RemoteException {
427         final String token = "some-high-entropy-secure-token";
428         enableSyntheticPassword();
429         long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
430         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
431         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
432         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
433     }
434 
testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration()435     public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration()
436             throws RemoteException {
437         final String token = "some-high-entropy-secure-token";
438         initializeCredentialUnderSP(null, PRIMARY_USER_ID);
439         long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
440         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
441         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
442         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
443     }
444 
testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()445     public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()
446             throws RemoteException {
447         final byte[] token = "some-high-entropy-secure-token".getBytes();
448         final byte[] password = "password".getBytes();
449         // Set up pre-SP user password
450         disableSyntheticPassword();
451         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
452                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
453         enableSyntheticPassword();
454 
455         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
456         // Token not activated immediately since user password exists
457         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
458         // Activate token (password gets migrated to SP at the same time)
459         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
460                 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
461                     .getResponseCode());
462         // Verify token is activated
463         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
464     }
465 
testSetLockCredentialWithTokenFailsWithoutLockScreen()466     public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
467         final byte[] password = "password".getBytes();
468         final byte[] pattern = "123654".getBytes();
469         final byte[] token = "some-high-entropy-secure-token".getBytes();
470 
471         mHasSecureLockScreen = false;
472         enableSyntheticPassword();
473         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
474         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
475 
476         try {
477             mLocalService.setLockCredentialWithToken(password,
478                     LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
479                     PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
480             fail("An exception should have been thrown.");
481         } catch (UnsupportedOperationException e) {
482             // Success - the exception was expected.
483         }
484         assertFalse(mService.havePassword(PRIMARY_USER_ID));
485 
486         try {
487             mLocalService.setLockCredentialWithToken(pattern,
488                     LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token,
489                     PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
490             fail("An exception should have been thrown.");
491         } catch (UnsupportedOperationException e) {
492             // Success - the exception was expected.
493         }
494         assertFalse(mService.havePattern(PRIMARY_USER_ID));
495     }
496 
testgetHashFactorPrimaryUser()497     public void testgetHashFactorPrimaryUser() throws RemoteException {
498         final byte[] password = "password".getBytes();
499         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
500                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
501         final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
502         assertNotNull(hashFactor);
503 
504         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
505                 password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
506         final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
507         assertNotNull(newHashFactor);
508         // Hash factor should never change after password change/removal
509         assertArrayEquals(hashFactor, newHashFactor);
510     }
511 
testgetHashFactorManagedProfileUnifiedChallenge()512     public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
513         final byte[] pattern = "1236".getBytes();
514         mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
515                 null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
516         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
517         assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
518     }
519 
testgetHashFactorManagedProfileSeparateChallenge()520     public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
521         final byte[] primaryPassword = "primary".getBytes();
522         final byte[] profilePassword = "profile".getBytes();
523         mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
524                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
525         mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
526                 PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
527         assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
528     }
529 
testPasswordData_serializeDeserialize()530     public void testPasswordData_serializeDeserialize() {
531         PasswordData data = new PasswordData();
532         data.scryptN = 11;
533         data.scryptR = 22;
534         data.scryptP = 33;
535         data.passwordType = CREDENTIAL_TYPE_PASSWORD;
536         data.salt = PAYLOAD;
537         data.passwordHandle = PAYLOAD2;
538 
539         PasswordData deserialized = PasswordData.fromBytes(data.toBytes());
540 
541         assertEquals(11, deserialized.scryptN);
542         assertEquals(22, deserialized.scryptR);
543         assertEquals(33, deserialized.scryptP);
544         assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.passwordType);
545         assertArrayEquals(PAYLOAD, deserialized.salt);
546         assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
547     }
548 
testPasswordData_deserialize()549     public void testPasswordData_deserialize() {
550         // Test that we can deserialize existing PasswordData and don't inadvertently change the
551         // wire format.
552         byte[] serialized = new byte[] {
553                 0, 0, 0, 2, /* CREDENTIAL_TYPE_PASSWORD */
554                 11, /* scryptN */
555                 22, /* scryptR */
556                 33, /* scryptP */
557                 0, 0, 0, 5, /* salt.length */
558                 1, 2, -1, -2, 55, /* salt */
559                 0, 0, 0, 6, /* passwordHandle.length */
560                 2, 3, -2, -3, 44, 1, /* passwordHandle */
561         };
562         PasswordData deserialized = PasswordData.fromBytes(serialized);
563 
564         assertEquals(11, deserialized.scryptN);
565         assertEquals(22, deserialized.scryptR);
566         assertEquals(33, deserialized.scryptP);
567         assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.passwordType);
568         assertArrayEquals(PAYLOAD, deserialized.salt);
569         assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
570     }
571 
testGsiDisablesAuthSecret()572     public void testGsiDisablesAuthSecret() throws RemoteException {
573         mGsiService.setIsGsiRunning(true);
574 
575         final byte[] password = "testGsiDisablesAuthSecret-password".getBytes();
576 
577         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
578         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
579                 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
580                         .getResponseCode());
581         verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
582     }
583 
584     // b/62213311
585     //TODO: add non-migration work profile case, and unify/un-unify transition.
586     //TODO: test token after user resets password
587     //TODO: test token based reset after unified work challenge
588     //TODO: test clear password after unified work challenge
589 }
590