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

Commit 6e16724f authored by Dmitry Dementyev's avatar Dmitry Dementyev
Browse files

Remove platform key when user disables lock screen protection

Correctly sync keys on LSKF update.

Bug: 72443379
Test: adb shell am instrument -w -e package
com.android.server.locksettings.recoverablekeystore
com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner

Change-Id: I2569310388a6f852c86d560663024d8c8dadb761
parent 761a89df
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -1348,11 +1348,11 @@ public class LockSettingsService extends ILockSettings.Stub {
                    .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
            setUserKeyProtection(userId, credential, convertResponse(gkResponse));
            fixateNewestUserKeyAuth(userId);
            mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential,
                userId);
            // Refresh the auth token
            doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
            mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential,
                userId);
        } else {
            throw new RemoteException("Failed to enroll " +
                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
@@ -2494,6 +2494,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                    (response != null ? "rate limit exceeded" : "failed"));
            return;
        }
        mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
    }

    @Override
+8 −9
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ public class KeySyncTask implements Runnable {
    private final int mCredentialType;
    private final String mCredential;
    private final boolean mCredentialUpdated;
    private final PlatformKeyManager.Factory mPlatformKeyManagerFactory;
    private final PlatformKeyManager mPlatformKeyManager;
    private final RecoverySnapshotStorage mRecoverySnapshotStorage;
    private final RecoverySnapshotListenersStorage mSnapshotListenersStorage;

@@ -94,7 +94,7 @@ public class KeySyncTask implements Runnable {
                credentialType,
                credential,
                credentialUpdated,
                () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb));
                PlatformKeyManager.getInstance(context, recoverableKeyStoreDb));
    }

    /**
@@ -105,9 +105,7 @@ public class KeySyncTask implements Runnable {
     * @param credentialType The type of credential as defined in {@code LockPatternUtils}
     * @param credential The credential, encoded as a {@link String}.
     * @param credentialUpdated signals weather credentials were updated.
     * @param platformKeyManagerFactory Instantiates a {@link PlatformKeyManager} for the user.
     *     This is a factory to enable unit testing, as otherwise it would be impossible to test
     *     without a screen unlock occurring!
     * @param platformKeyManager platform key manager
     */
    @VisibleForTesting
    KeySyncTask(
@@ -118,14 +116,14 @@ public class KeySyncTask implements Runnable {
            int credentialType,
            String credential,
            boolean credentialUpdated,
            PlatformKeyManager.Factory platformKeyManagerFactory) {
            PlatformKeyManager platformKeyManager) {
        mSnapshotListenersStorage = recoverySnapshotListenersStorage;
        mRecoverableKeyStoreDb = recoverableKeyStoreDb;
        mUserId = userId;
        mCredentialType = credentialType;
        mCredential = credential;
        mCredentialUpdated = credentialUpdated;
        mPlatformKeyManagerFactory = platformKeyManagerFactory;
        mPlatformKeyManager = platformKeyManager;
        mRecoverySnapshotStorage = snapshotStorage;
    }

@@ -145,6 +143,8 @@ public class KeySyncTask implements Runnable {
        if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
            // Application keys for the user will not be available for sync.
            Log.w(TAG, "Credentials are not set for user " + mUserId);
            int generation = mPlatformKeyManager.getGenerationId(mUserId);
            mPlatformKeyManager.invalidatePlatformKey(mUserId, generation);
            return;
        }

@@ -304,8 +304,7 @@ public class KeySyncTask implements Runnable {
            throws InsecureUserException, KeyStoreException, UnrecoverableKeyException,
            NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
            InvalidKeyException, InvalidAlgorithmParameterException {
        PlatformKeyManager platformKeyManager = mPlatformKeyManagerFactory.newInstance();
        PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId);;
        PlatformDecryptionKey decryptKey = mPlatformKeyManager.getDecryptKey(mUserId);;
        Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys(
                mUserId, recoveryAgentUid, decryptKey.getGenerationId());
        return WrappedKey.unwrapKeys(decryptKey, wrappedKeys);
+31 −14
Original line number Diff line number Diff line
@@ -128,6 +128,26 @@ public class PlatformKeyManager {
        return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId);
    }

    /**
     * Removes the platform key from Android KeyStore.
     * It is triggered when user disables lock screen.
     *
     * @param userId The ID of the user to whose lock screen the platform key must be bound.
     * @param generationId Generation id.
     *
     * @hide
     */
    public void invalidatePlatformKey(int userId, int generationId) {
        if (generationId != -1) {
            try {
                mKeyStore.deleteEntry(getEncryptAlias(userId, generationId));
                mKeyStore.deleteEntry(getDecryptAlias(userId, generationId));
            } catch (KeyStoreException e) {
                // Ignore failed attempt to delete key.
            }
        }
    }

    /**
     * Generates a new key and increments the generation ID. Should be invoked if the platform key
     * is corrupted and needs to be rotated.
@@ -152,6 +172,7 @@ public class PlatformKeyManager {
        if (generationId == -1) {
            nextId = 1;
        } else {
            invalidatePlatformKey(userId, generationId);
            nextId = generationId + 1;
        }
        generateAndLoadKey(userId, nextId);
@@ -197,8 +218,12 @@ public class PlatformKeyManager {
    private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException,
           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
        int generationId = getGenerationId(userId);
        String alias = getEncryptAlias(userId, generationId);
        if (!mKeyStore.containsAlias(alias)) {
            throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
        }
        AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
                getEncryptAlias(userId, generationId), /*password=*/ null);
                alias, /*password=*/ null);
        return new PlatformEncryptionKey(generationId, key);
    }

@@ -242,8 +267,12 @@ public class PlatformKeyManager {
    private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException,
           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
        int generationId = getGenerationId(userId);
        String alias = getDecryptAlias(userId, generationId);
        if (!mKeyStore.containsAlias(alias)) {
            throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
        }
        AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
                getDecryptAlias(userId, generationId), /*password=*/ null);
                alias, /*password=*/ null);
        return new PlatformDecryptionKey(generationId, key);
    }

@@ -405,16 +434,4 @@ public class PlatformKeyManager {
        return keyStore;
    }

    /**
     * @hide
     */
    public interface Factory {
        /**
         * New PlatformKeyManager instance.
         *
         * @hide
         */
        PlatformKeyManager newInstance()
                throws NoSuchAlgorithmException, InsecureUserException, KeyStoreException;
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -579,6 +579,7 @@ public class RecoverableKeyStoreManager {

    /**
     * This function can only be used inside LockSettingsService.
     *
     * @param storedHashType from {@code CredentialHash}
     * @param credential - unencrypted String
     * @param userId for the user whose lock screen credentials were changed.
@@ -604,7 +605,7 @@ public class RecoverableKeyStoreManager {
        } catch (KeyStoreException e) {
            Log.e(TAG, "Key store error encountered during recoverable key sync", e);
        } catch (InsecureUserException e) {
            Log.wtf(TAG, "Impossible - insecure user, but user just entered lock screen", e);
            Log.e(TAG, "InsecureUserException during lock screen secret update", e);
        }
    }

+4 −4
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ public class KeySyncTaskTest {
                TEST_CREDENTIAL_TYPE,
                TEST_CREDENTIAL,
                /*credentialUpdated=*/ false,
                () -> mPlatformKeyManager);
                mPlatformKeyManager);

        mWrappingKey = generateAndroidKeyStoreKey();
        mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey);
@@ -352,7 +352,7 @@ public class KeySyncTaskTest {
                CREDENTIAL_TYPE_PASSWORD,
                "password",
                /*credentialUpdated=*/ false,
                () -> mPlatformKeyManager);
                mPlatformKeyManager);

        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
@@ -378,7 +378,7 @@ public class KeySyncTaskTest {
                CREDENTIAL_TYPE_PASSWORD,
                /*credential=*/ "1234",
                /*credentialUpdated=*/ false,
                () -> mPlatformKeyManager);
                mPlatformKeyManager);

        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
@@ -405,7 +405,7 @@ public class KeySyncTaskTest {
                CREDENTIAL_TYPE_PATTERN,
                "12345",
                /*credentialUpdated=*/ false,
                () -> mPlatformKeyManager);
                mPlatformKeyManager);

        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
Loading