• Home
  • History
  • Annotate
  • 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