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

Commit 9025f5a1 authored by Dmitry Dementyev's avatar Dmitry Dementyev Committed by Automerger Merge Worker
Browse files

Throw InsecureUserException when LSKF is not set in recoverablekeystore. am: de7bc53d

parents 3e50c9ea de7bc53d
Loading
Loading
Loading
Loading
+32 −17
Original line number Diff line number Diff line
@@ -166,6 +166,7 @@ public class PlatformKeyManager {
     * @param userId The ID of the user to whose lock screen the platform key must be bound.
     * @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
     * @throws KeyStoreException if there is an error in AndroidKeyStore.
     * @throws InsecureUserException if the user does not have a lock screen set.
     * @throws IOException if there was an issue with local database update.
     * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
     *
@@ -174,7 +175,7 @@ public class PlatformKeyManager {
    @VisibleForTesting
    void regenerate(int userId)
            throws NoSuchAlgorithmException, KeyStoreException, IOException,
                    RemoteException {
                    RemoteException, InsecureUserException {
        int generationId = getGenerationId(userId);
        int nextId;
        if (generationId == -1) {
@@ -195,13 +196,14 @@ public class PlatformKeyManager {
     * @throws UnrecoverableKeyException if the key could not be recovered.
     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
     * @throws IOException if there was an issue with local database update.
     * @throws InsecureUserException if the user does not have a lock screen set.
     * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
     *
     * @hide
     */
    public PlatformEncryptionKey getEncryptKey(int userId)
            throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
                    IOException, RemoteException {
                    IOException, RemoteException, InsecureUserException {
        init(userId);
        try {
            // Try to see if the decryption key is still accessible before using the encryption key.
@@ -254,7 +256,7 @@ public class PlatformKeyManager {
     */
    public PlatformDecryptionKey getDecryptKey(int userId)
            throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
                    IOException, RemoteException {
                    IOException, InsecureUserException, RemoteException {
        init(userId);
        try {
            PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId);
@@ -328,7 +330,7 @@ public class PlatformKeyManager {
     */
    void init(int userId)
            throws KeyStoreException, NoSuchAlgorithmException, IOException,
                    RemoteException {
                    RemoteException, InsecureUserException {
        int generationId = getGenerationId(userId);
        if (isKeyLoaded(userId, generationId)) {
            Log.i(TAG, String.format(
@@ -414,7 +416,8 @@ public class PlatformKeyManager {
     * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
     */
    private void generateAndLoadKey(int userId, int generationId)
            throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException {
            throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException,
                InsecureUserException {
        String encryptAlias = getEncryptAlias(userId, generationId);
        String decryptAlias = getDecryptAlias(userId, generationId);
        // SecretKey implementation doesn't provide reliable way to destroy the secret
@@ -427,11 +430,13 @@ public class PlatformKeyManager {
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
        // Skip UserAuthenticationRequired for main user
        if (userId ==  UserHandle.USER_SYSTEM) {
            // attempt to store key will fail if screenlock is not set.
            decryptionKeyProtection.setUnlockedDeviceRequired(true);
        } else {
            // Don't set protection params to prevent losing key.
        }
        // Store decryption key first since it is more likely to fail.
        try {
            mKeyStore.setEntry(
                    decryptAlias,
                    new KeyStore.SecretKeyEntry(secretKey),
@@ -443,7 +448,13 @@ public class PlatformKeyManager {
                        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                        .build());

        } catch (KeyStoreException e) {
            if (!isDeviceSecure(userId)) {
                throw new InsecureUserException("Screenlock is not set");
            } else {
                throw e;
            }
        }
        setGenerationId(userId, generationId);
    }

@@ -477,4 +488,8 @@ public class PlatformKeyManager {
        return keyStore;
    }

    private boolean isDeviceSecure(int userId) {
        return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId);
    }

}
+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.locksettings.recoverablekeystore;
import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT;
import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED;
import static android.security.keystore.recovery.RecoveryController.ERROR_DOWNGRADE_CERTIFICATE;
import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER;
import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
@@ -750,6 +751,8 @@ public class RecoverableKeyStoreManager {
            throw new RuntimeException(e);
        } catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
        } catch (InsecureUserException e) {
            throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
        }

        try {
@@ -817,6 +820,8 @@ public class RecoverableKeyStoreManager {
            throw new RuntimeException(e);
        } catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
        } catch (InsecureUserException e) {
            throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
        }

        try {
+14 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;

import android.app.KeyguardManager;
import android.content.Context;
@@ -54,6 +55,7 @@ import org.mockito.MockitoAnnotations;

import java.io.File;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import java.util.List;

@@ -392,6 +394,18 @@ public class PlatformKeyManagerTest {
                any());
    }

    @Test
    public void getEncryptKey_noScreenlock() throws Exception {
        when(mKeyguardManager.isDeviceSecure(USER_ID_FIXTURE)).thenReturn(false);
        doThrow(new KeyStoreException()).when(mKeyStoreProxy).setEntry(
                anyString(),
                any(),
                any());

        assertThrows(InsecureUserException.class,
                () -> mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE));
    }

    @Test
    public void getDecryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
        doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(