Loading services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +32 −17 Original line number Diff line number Diff line Loading @@ -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}. * Loading @@ -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) { Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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( Loading Loading @@ -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 Loading @@ -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), Loading @@ -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); } Loading Loading @@ -477,4 +488,8 @@ public class PlatformKeyManager { return keyStore; } private boolean isDeviceSecure(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId); } } services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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 { Loading services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +14 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +32 −17 Original line number Diff line number Diff line Loading @@ -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}. * Loading @@ -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) { Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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( Loading Loading @@ -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 Loading @@ -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), Loading @@ -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); } Loading Loading @@ -477,4 +488,8 @@ public class PlatformKeyManager { return keyStore; } private boolean isDeviceSecure(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId); } }
services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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 { Loading
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +14 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading