Home | History | Annotate | Download | only in locksettings
      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 import static org.mockito.Mockito.verify;
     27 
     28 import android.app.admin.PasswordMetrics;
     29 import android.os.RemoteException;
     30 import android.os.UserHandle;
     31 
     32 import com.android.internal.widget.LockPatternUtils;
     33 import com.android.internal.widget.VerifyCredentialResponse;
     34 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
     35 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
     36 import com.android.server.locksettings.SyntheticPasswordManager.PasswordData;
     37 
     38 
     39 /**
     40  * runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests
     41  */
     42 public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
     43 
     44     public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 55};
     45     public static final byte[] PAYLOAD2 = new byte[] {2, 3, -2, -3, 44, 1};
     46 
     47     @Override
     48     protected void setUp() throws Exception {
     49         super.setUp();
     50     }
     51 
     52     @Override
     53     protected void tearDown() throws Exception {
     54         super.tearDown();
     55     }
     56 
     57     public void testPasswordBasedSyntheticPassword() throws RemoteException {
     58         final int USER_ID = 10;
     59         final String PASSWORD = "user-password";
     60         final String BADPASSWORD = "bad-password";
     61         MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
     62                 mGateKeeperService, mUserManager);
     63         AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
     64                 null, USER_ID);
     65         long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, PASSWORD,
     66                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, PASSWORD_QUALITY_ALPHABETIC,
     67                 USER_ID);
     68 
     69         AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle, PASSWORD, USER_ID);
     70         assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword());
     71 
     72         result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle, BADPASSWORD, USER_ID);
     73         assertNull(result.authToken);
     74     }
     75 
     76     private void disableSyntheticPassword() throws RemoteException {
     77         mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
     78     }
     79 
     80     private void enableSyntheticPassword() throws RemoteException {
     81         mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
     82     }
     83 
     84     private boolean hasSyntheticPassword(int userId) throws RemoteException {
     85         return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0;
     86     }
     87 
     88     public void testPasswordMigration() throws RemoteException {
     89         final String PASSWORD = "testPasswordMigration-password";
     90 
     91         disableSyntheticPassword();
     92         mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
     93                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
     94         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
     95         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
     96         enableSyntheticPassword();
     97         // Performs migration
     98         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
     99                 mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    100         assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    101         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
    102 
    103         // SP-based verification
    104         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    105                 mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    106         assertArrayNotSame(primaryStorageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
    107     }
    108 
    109     private void initializeCredentialUnderSP(String password, int userId) throws RemoteException {
    110         enableSyntheticPassword();
    111         int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
    112                 : PASSWORD_QUALITY_UNSPECIFIED;
    113         int type = password != null ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
    114                 : LockPatternUtils.CREDENTIAL_TYPE_NONE;
    115         mService.setLockCredential(password, type, null, quality, userId);
    116     }
    117 
    118     public void testSyntheticPasswordChangeCredential() throws RemoteException {
    119         final String PASSWORD = "testSyntheticPasswordChangeCredential-password";
    120         final String NEWPASSWORD = "testSyntheticPasswordChangeCredential-newpassword";
    121 
    122         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    123         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
    124         mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
    125                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    126         mGateKeeperService.clearSecureUserId(PRIMARY_USER_ID);
    127         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    128                 mService.verifyCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    129         assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    130     }
    131 
    132     public void testSyntheticPasswordVerifyCredential() throws RemoteException {
    133         final String PASSWORD = "testSyntheticPasswordVerifyCredential-password";
    134         final String BADPASSWORD = "testSyntheticPasswordVerifyCredential-badpassword";
    135 
    136         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    137         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    138                 mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    139 
    140         assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
    141                 mService.verifyCredential(BADPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    142     }
    143 
    144     public void testSyntheticPasswordClearCredential() throws RemoteException {
    145         final String PASSWORD = "testSyntheticPasswordClearCredential-password";
    146         final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
    147 
    148         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    149         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
    150         // clear password
    151         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
    152                 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
    153         assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    154 
    155         // set a new password
    156         mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    157                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    158         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    159                 mService.verifyCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    160         assertNotSame(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    161     }
    162 
    163     public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
    164         final String PASSWORD = "testSyntheticPasswordClearCredential-password";
    165         final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
    166 
    167         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    168         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
    169         // clear password
    170         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
    171                 PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
    172         assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    173 
    174         // set a new password
    175         mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    176                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    177         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    178                 mService.verifyCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    179         assertNotSame(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    180     }
    181 
    182     public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
    183         final String PASSWORD = "testSyntheticPasswordClearCredential-password";
    184         final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
    185 
    186         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    187         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
    188         // Untrusted change password
    189         mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    190                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    191         assertNotSame(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    192         assertNotSame(sid ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    193 
    194         // Verify the password
    195         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    196                 mService.verifyCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    197     }
    198 
    199 
    200     public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
    201         final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd";
    202         disableSyntheticPassword();
    203         mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    204                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    205         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
    206         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
    207         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
    208         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
    209         final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
    210         assertTrue(primarySid != 0);
    211         assertTrue(profileSid != 0);
    212         assertTrue(profileSid != primarySid);
    213 
    214         // do migration
    215         enableSyntheticPassword();
    216         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    217                 mService.verifyCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    218 
    219         // verify
    220         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    221                 mService.verifyCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    222         assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    223         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
    224         assertArrayNotSame(primaryStorageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
    225         assertArrayNotSame(profileStorageKey, mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
    226         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
    227         assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
    228     }
    229 
    230     public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
    231         final String primaryPassword = "testManagedProfileSeparateChallengeMigration-primary";
    232         final String profilePassword = "testManagedProfileSeparateChallengeMigration-profile";
    233         disableSyntheticPassword();
    234         mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    235                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    236         mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    237                 PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
    238         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
    239         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
    240         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
    241         final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
    242         assertTrue(primarySid != 0);
    243         assertTrue(profileSid != 0);
    244         assertTrue(profileSid != primarySid);
    245 
    246         // do migration
    247         enableSyntheticPassword();
    248         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    249                 mService.verifyCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    250         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    251                 mService.verifyCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, MANAGED_PROFILE_USER_ID).getResponseCode());
    252 
    253         // verify
    254         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    255                 mService.verifyCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    256         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    257                 mService.verifyCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, MANAGED_PROFILE_USER_ID).getResponseCode());
    258         assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    259         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
    260         assertArrayNotSame(primaryStorageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
    261         assertArrayNotSame(profileStorageKey, mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
    262         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
    263         assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
    264     }
    265 
    266     public void testTokenBasedResetPassword() throws RemoteException {
    267         final String PASSWORD = "password";
    268         final String PATTERN = "123654";
    269         final String TOKEN = "some-high-entropy-secure-token";
    270         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    271         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
    272 
    273         long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
    274         assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    275 
    276         mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
    277                 PRIMARY_USER_ID).getResponseCode();
    278         assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    279 
    280         mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
    281                 handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
    282 
    283         // Verify DPM gets notified about new device lock
    284         mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
    285         PasswordMetrics metric = PasswordMetrics.computeForPassword(PATTERN);
    286         metric.quality = PASSWORD_QUALITY_SOMETHING;
    287         verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID);
    288 
    289         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    290                 mService.verifyCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0,
    291                         PRIMARY_USER_ID).getResponseCode());
    292         assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
    293     }
    294 
    295     public void testTokenBasedClearPassword() throws RemoteException {
    296         final String PASSWORD = "password";
    297         final String PATTERN = "123654";
    298         final String TOKEN = "some-high-entropy-secure-token";
    299         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    300         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
    301 
    302         long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
    303         assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    304 
    305         mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode();
    306         assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    307 
    308         mService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, handle,
    309                 TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
    310         mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
    311                 handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
    312 
    313         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    314                 mService.verifyCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID).getResponseCode());
    315         assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
    316     }
    317 
    318     public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException {
    319         final String PASSWORD = "password";
    320         final String PATTERN = "123654";
    321         final String NEWPASSWORD = "password";
    322         final String TOKEN = "some-high-entropy-secure-token";
    323         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
    324         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
    325 
    326         long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
    327         assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    328 
    329         mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode();
    330         assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    331 
    332         mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
    333                 PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
    334 
    335         mService.setLockCredentialWithToken(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
    336                 handle, TOKEN.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    337 
    338         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    339                 mService.verifyCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
    340         assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
    341     }
    342 
    343     public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration() throws RemoteException {
    344         final String TOKEN = "some-high-entropy-secure-token";
    345         enableSyntheticPassword();
    346         long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
    347         assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    348         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    349         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
    350     }
    351 
    352     public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration() throws RemoteException {
    353         final String TOKEN = "some-high-entropy-secure-token";
    354         initializeCredentialUnderSP(null, PRIMARY_USER_ID);
    355         long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
    356         assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    357         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
    358         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
    359     }
    360 
    361     public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration() throws RemoteException {
    362         final String TOKEN = "some-high-entropy-secure-token";
    363         final String PASSWORD = "password";
    364         // Set up pre-SP user password
    365         disableSyntheticPassword();
    366         mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
    367                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
    368         enableSyntheticPassword();
    369 
    370         long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
    371         // Token not activated immediately since user password exists
    372         assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    373         // Activate token (password gets migrated to SP at the same time)
    374         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
    375                 mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
    376                         PRIMARY_USER_ID).getResponseCode());
    377         // Verify token is activated
    378         assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
    379     }
    380 
    381     public void testPasswordData_serializeDeserialize() {
    382         PasswordData data = new PasswordData();
    383         data.scryptN = 11;
    384         data.scryptR = 22;
    385         data.scryptP = 33;
    386         data.passwordType = CREDENTIAL_TYPE_PASSWORD;
    387         data.salt = PAYLOAD;
    388         data.passwordHandle = PAYLOAD2;
    389 
    390         PasswordData deserialized = PasswordData.fromBytes(data.toBytes());
    391 
    392         assertEquals(11, deserialized.scryptN);
    393         assertEquals(22, deserialized.scryptR);
    394         assertEquals(33, deserialized.scryptP);
    395         assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.passwordType);
    396         assertArrayEquals(PAYLOAD, deserialized.salt);
    397         assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
    398     }
    399 
    400     public void testPasswordData_deserialize() {
    401         // Test that we can deserialize existing PasswordData and don't inadvertently change the
    402         // wire format.
    403         byte[] serialized = new byte[] {
    404                 0, 0, 0, 2, /* CREDENTIAL_TYPE_PASSWORD */
    405                 11, /* scryptN */
    406                 22, /* scryptR */
    407                 33, /* scryptP */
    408                 0, 0, 0, 5, /* salt.length */
    409                 1, 2, -1, -2, 55, /* salt */
    410                 0, 0, 0, 6, /* passwordHandle.length */
    411                 2, 3, -2, -3, 44, 1, /* passwordHandle */
    412         };
    413         PasswordData deserialized = PasswordData.fromBytes(serialized);
    414 
    415         assertEquals(11, deserialized.scryptN);
    416         assertEquals(22, deserialized.scryptR);
    417         assertEquals(33, deserialized.scryptP);
    418         assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.passwordType);
    419         assertArrayEquals(PAYLOAD, deserialized.salt);
    420         assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
    421     }
    422 
    423     // b/34600579
    424     //TODO: add non-migration work profile case, and unify/un-unify transition.
    425     //TODO: test token after user resets password
    426     //TODO: test token based reset after unified work challenge
    427     //TODO: test clear password after unified work challenge
    428 }
    429