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