Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d991c73 authored by Eric Biggers's avatar Eric Biggers
Browse files

Remove obsolete support for nonempty credential without SP

All users with a nonempty lockscreen credential now have a synthetic
password (SP), due to the migration logic that was enabled in
Android O MR1 (commit 7a0cc0a7 / http://ag/2339115).  For this to
not be the case, a device that launched with Android O or earlier would
have to be upgraded all the way to Android U.  That's unsupported; and
even if it was supported, the migration to SP would have happened if the
user was unlocked even just once with *any* version O MR1 through T.
Therefore, there's no longer any need to support the non-SP case except
when credentialType == CREDENTIAL_TYPE_NONE.

Remove all the relevant code that is no longer needed.

Bug: 146040259
Test: atest com.android.server.locksettings
Test: Upgraded a device that has an LSKF set, then unlocked the device
      and changed the LSKF.
Test: m services FrameworksServicesTests RUN_ERROR_PRONE=true
Change-Id: I08ff4d86379e3289ed8aa02b286a92b3ae431367
parent 442896b4
Loading
Loading
Loading
Loading
+96 −344

File changed.

Preview size limit exceeded, changes collapsed.

+1 −86
Original line number Diff line number Diff line
@@ -85,8 +85,6 @@ class LockSettingsStorage extends WatchableImpl {
    };

    private static final String SYSTEM_DIRECTORY = "/system/";
    private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key";
    private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
    private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";

    private static final String REBOOT_ESCROW_FILE = "reboot.escrow.key";
@@ -248,38 +246,6 @@ class LockSettingsStorage extends WatchableImpl {
            }
            cursor.close();
        }

        // Populate cache by reading the password and pattern files.
        readCredentialHash(userId);
    }

    private CredentialHash readPasswordHashIfExists(int userId) {
        byte[] stored = readFile(getLockPasswordFilename(userId));
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN);
        }
        return null;
    }

    private CredentialHash readPatternHashIfExists(int userId) {
        byte[] stored = readFile(getLockPatternFilename(userId));
        if (!ArrayUtils.isEmpty(stored)) {
            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
        }
        return null;
    }

    public CredentialHash readCredentialHash(int userId) {
        CredentialHash passwordHash = readPasswordHashIfExists(userId);
        if (passwordHash != null) {
            return passwordHash;
        }

        CredentialHash patternHash = readPatternHashIfExists(userId);
        if (patternHash != null) {
            return patternHash;
        }
        return CredentialHash.createEmptyHash();
    }

    public void removeChildProfileLock(int userId) {
@@ -336,14 +302,6 @@ class LockSettingsStorage extends WatchableImpl {
        deleteFile(getRebootEscrowServerBlob());
    }

    public boolean hasPassword(int userId) {
        return hasFile(getLockPasswordFilename(userId));
    }

    public boolean hasPattern(int userId) {
        return hasFile(getLockPatternFilename(userId));
    }

    private boolean hasFile(String name) {
        byte[] contents = readFile(name);
        return contents != null && contents.length > 0;
@@ -429,33 +387,6 @@ class LockSettingsStorage extends WatchableImpl {
        }
    }

    public void writeCredentialHash(CredentialHash hash, int userId) {
        byte[] patternHash = null;
        byte[] passwordHash = null;
        if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN
                || hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
                || hash.type == LockPatternUtils.CREDENTIAL_TYPE_PIN) {
            passwordHash = hash.hash;
        } else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
            patternHash = hash.hash;
        } else {
            Preconditions.checkArgument(hash.type == LockPatternUtils.CREDENTIAL_TYPE_NONE,
                    "Unknown credential type");
        }
        writeFile(getLockPasswordFilename(userId), passwordHash);
        writeFile(getLockPatternFilename(userId), patternHash);
    }

    @VisibleForTesting
    String getLockPatternFilename(int userId) {
        return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE);
    }

    @VisibleForTesting
    String getLockPasswordFilename(int userId) {
        return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE);
    }

    @VisibleForTesting
    String getChildProfileLockFile(int userId) {
        return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE);
@@ -567,12 +498,7 @@ class LockSettingsStorage extends WatchableImpl {

        if (parentInfo == null) {
            // This user owns its lock settings files - safe to delete them
            synchronized (mFileWriteLock) {
                deleteFilesAndRemoveCache(
                        getLockPasswordFilename(userId),
                        getLockPatternFilename(userId),
                        getRebootEscrowFile(userId));
            }
            deleteFile(getRebootEscrowFile(userId));
        } else {
            // Managed profile
            removeChildProfileLock(userId);
@@ -594,17 +520,6 @@ class LockSettingsStorage extends WatchableImpl {
        dispatchChange(this);
    }

    private void deleteFilesAndRemoveCache(String... names) {
        for (String name : names) {
            File file = new File(name);
            if (file.exists()) {
                file.delete();
                mCache.putFile(name, null);
                dispatchChange(this);
            }
        }
    }

    public void setBoolean(String key, boolean value, int userId) {
        setString(key, value ? "1" : "0", userId);
    }
+5 −33
Original line number Diff line number Diff line
@@ -599,47 +599,19 @@ public class SyntheticPasswordManager {
    }

    /**
     * Initializing a new Authentication token, possibly from an existing credential and hash.
     * Initializes a new Authentication token for the given user.
     *
     * The authentication token would bear a randomly-generated synthetic password.
     * The authentication token will bear a randomly-generated synthetic password.
     *
     * This method has the side effect of rebinding the SID of the given user to the
     * newly-generated SP.
     *
     * If the existing credential hash is non-null, the existing SID mill be migrated so
     * the synthetic password in the authentication token will produce the same SID
     * (the corresponding synthetic password handle is persisted by SyntheticPasswordManager
     * in a per-user data storage.)
     *
     * If the existing credential hash is null, it means the given user should have no SID so
     * SyntheticPasswordManager will nuke any SP handle previously persisted. In this case,
     * the supplied credential parameter is also ignored.
     * Any existing SID for the user is cleared.
     *
     * Also saves the escrow information necessary to re-generate the synthetic password under
     * an escrow scheme. This information can be removed with {@link #destroyEscrowData} if
     * password escrow should be disabled completely on the given user.
     *
     */
    public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
            byte[] hash, LockscreenCredential credential, int userId) {
        AuthenticationToken result = AuthenticationToken.create();
        GateKeeperResponse response;
        if (hash != null) {
            try {
                response = gatekeeper.enroll(userId, hash, credential.getCredential(),
                        result.deriveGkPassword());
            } catch (RemoteException e) {
                throw new IllegalStateException("Failed to enroll credential duing SP init", e);
            }
            if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
                Slog.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
                clearSidForUser(userId);
            } else {
                saveSyntheticPasswordHandle(response.getPayload(), userId);
            }
        } else {
    AuthenticationToken newSyntheticPassword(int userId) {
        clearSidForUser(userId);
        }
        AuthenticationToken result = AuthenticationToken.create();
        saveEscrowData(result, userId);
        return result;
    }
+0 −5
Original line number Diff line number Diff line
@@ -135,11 +135,6 @@ public class LockSettingsServiceTestable extends LockSettingsService {
            return mUserManagerInternal;
        }

        @Override
        public boolean hasEnrolledBiometrics(int userId) {
            return false;
        }

        @Override
        public int binderGetCallingUid() {
            return Process.SYSTEM_UID;
+21 −42
Original line number Diff line number Diff line
@@ -42,11 +42,8 @@ import android.service.gatekeeper.GateKeeperResponse;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;

import org.junit.Before;
import org.junit.Test;
@@ -96,17 +93,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {

    @Test
    public void testChangePasswordFailPrimaryUser() throws RemoteException {
        final long sid = 1234;
        initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid);
        initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"));

        assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"),
                    PRIMARY_USER_ID));
        assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid);
        assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"));
    }

    @Test
    public void testClearPasswordPrimaryUser() throws RemoteException {
        initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"));
        assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
                PRIMARY_USER_ID));
        assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID));
@@ -264,10 +260,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
    public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
            throws Exception {
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
        initializeStorageWithCredential(
                MANAGED_PROFILE_USER_ID,
                newPattern("12345"),
                1234);
        initializeStorageWithCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));

        assertTrue(mService.setLockCredential(
                newPassword("newPassword"),
@@ -300,8 +293,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
                    throws Exception {
        final LockscreenCredential oldCredential = newPassword("oldPassword");
        final LockscreenCredential newCredential = newPassword("newPassword");
        initializeStorageWithCredential(
                PRIMARY_USER_ID, oldCredential, 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, oldCredential);
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);

        assertTrue(mService.setLockCredential(
@@ -321,7 +313,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
    public void
            testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
                    throws Exception {
        initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword"), 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword"));
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);

        assertTrue(mService.setLockCredential(
@@ -337,10 +329,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {

    @Test
    public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException {
        initializeStorageWithCredential(
                PRIMARY_USER_ID,
                newPattern("123654"),
                1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, newPattern("123654"));
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);

        mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID);
@@ -358,7 +347,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
            throws Exception {
        final LockscreenCredential parentPassword = newPassword("parentPassword");
        final LockscreenCredential profilePassword = newPassword("profilePassword");
        initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword);
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);

        assertTrue(mService.setLockCredential(
@@ -377,7 +366,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
                    throws Exception {
        final LockscreenCredential parentPassword = newPassword("parentPassword");
        final LockscreenCredential profilePassword = newPattern("12345");
        initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword);
        // Create and verify separate profile credentials.
        testCreateCredential(MANAGED_PROFILE_USER_ID, profilePassword);

@@ -393,7 +382,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
    @Test
    public void testVerifyCredential_forPrimaryUser_sendsCredentials() throws Exception {
        final LockscreenCredential password = newPassword("password");
        initializeStorageWithCredential(PRIMARY_USER_ID, password, 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, password);
        reset(mRecoverableKeyStoreManager);

        mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */);
@@ -424,7 +413,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
    public void verifyCredential_forPrimaryUserWithUnifiedChallengeProfile_sendsCredentialsForBoth()
                    throws Exception {
        final LockscreenCredential pattern = newPattern("12345");
        initializeStorageWithCredential(PRIMARY_USER_ID, pattern, 1234);
        initializeStorageWithCredential(PRIMARY_USER_ID, pattern);
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
        reset(mRecoverableKeyStoreManager);

@@ -464,7 +453,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
    private void testCreateCredential(int userId, LockscreenCredential credential)
            throws RemoteException {
        assertTrue(mService.setLockCredential(credential, nonePassword(), userId));
        assertVerifyCredentials(userId, credential, -1);
        assertVerifyCredentials(userId, credential);
    }

    private void testCreateCredentialFailsWithoutLockScreen(
@@ -483,19 +472,17 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {

    private void testChangeCredentials(int userId, LockscreenCredential newCredential,
            LockscreenCredential oldCredential) throws RemoteException {
        final long sid = 1234;
        initializeStorageWithCredential(userId, oldCredential, sid);
        initializeStorageWithCredential(userId, oldCredential);
        assertTrue(mService.setLockCredential(newCredential, oldCredential, userId));
        assertVerifyCredentials(userId, newCredential, sid);
        assertVerifyCredentials(userId, newCredential);
    }

    private void assertVerifyCredentials(int userId, LockscreenCredential credential, long sid)
    private void assertVerifyCredentials(int userId, LockscreenCredential credential)
            throws RemoteException{
        VerifyCredentialResponse response = mService.verifyCredential(credential, userId,
                0 /* flags */);

        assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
        if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
        if (credential.isPassword()) {
            assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId));
        } else if (credential.isPin()) {
@@ -517,19 +504,11 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
                badCredential, userId, 0 /* flags */).getResponseCode());
    }

    private void initializeStorageWithCredential(int userId, LockscreenCredential credential,
            long sid) throws RemoteException {
        byte[] oldHash = new VerifyHandle(credential.getCredential(), sid).toBytes();
        if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
            mService.initializeSyntheticPasswordLocked(oldHash, credential, userId);
        } else {
            if (credential.isPassword() || credential.isPin()) {
                mStorage.writeCredentialHash(CredentialHash.create(oldHash,
                        LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
            } else {
                mStorage.writeCredentialHash(CredentialHash.create(oldHash,
                        LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
            }
        }
    @SuppressWarnings("GuardedBy") // for initializeSyntheticPasswordLocked
    private void initializeStorageWithCredential(int userId, LockscreenCredential credential)
            throws RemoteException {
        assertEquals(0, mGateKeeperService.getSecureUserId(userId));
        mService.initializeSyntheticPasswordLocked(credential, userId);
        assertNotEquals(0, mGateKeeperService.getSecureUserId(userId));
    }
}
Loading