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