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