Loading services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +9 −11 Original line number Diff line number Diff line Loading @@ -194,6 +194,9 @@ public class PlatformKeyManager { UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { init(userId); try { // Try to see if the decryption key is still accessible before using the encryption key. // The auth-bound decryption will be unrecoverable if the screen lock is disabled. getDecryptKeyInternal(userId); return getEncryptKeyInternal(userId); } catch (UnrecoverableKeyException e) { Log.i(TAG, String.format(Locale.US, Loading @@ -219,7 +222,7 @@ public class PlatformKeyManager { UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { int generationId = getGenerationId(userId); String alias = getEncryptAlias(userId, generationId); if (!mKeyStore.containsAlias(alias)) { if (!isKeyLoaded(userId, generationId)) { throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); } AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( Loading Loading @@ -268,7 +271,7 @@ public class PlatformKeyManager { UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { int generationId = getGenerationId(userId); String alias = getDecryptAlias(userId, generationId); if (!mKeyStore.containsAlias(alias)) { if (!isKeyLoaded(userId, generationId)) { throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); } AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( Loading Loading @@ -300,12 +303,12 @@ public class PlatformKeyManager { return; } if (generationId == -1) { Log.i(TAG, "Generating initial platform ID."); Log.i(TAG, "Generating initial platform key generation ID."); generationId = 1; } else { Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no " + "entry was present in AndroidKeyStore. Generating fresh key.", generationId)); // Had to generate a fresh key, bump the generation id // Have to generate a fresh key, so bump the generation id generationId++; } Loading Loading @@ -374,7 +377,7 @@ public class PlatformKeyManager { String decryptAlias = getDecryptAlias(userId, generationId); SecretKey secretKey = generateAesKey(); // Store Since decryption key first since it is more likely to fail. // Store decryption key first since it is more likely to fail. mKeyStore.setEntry( decryptAlias, new KeyStore.SecretKeyEntry(secretKey), Loading @@ -386,7 +389,6 @@ public class PlatformKeyManager { .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setBoundToSpecificSecureUserId(userId) .build()); mKeyStore.setEntry( encryptAlias, new KeyStore.SecretKeyEntry(secretKey), Loading @@ -397,11 +399,7 @@ public class PlatformKeyManager { setGenerationId(userId, generationId); try { secretKey.destroy(); } catch (DestroyFailedException e) { Log.w(TAG, "Failed to destroy in-memory platform key.", e); } // TODO: Use a reliable way to destroy the temporary secretKey in memory. } /** Loading services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +129 −6 Original line number Diff line number Diff line Loading @@ -255,6 +255,9 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); Loading @@ -263,6 +266,56 @@ public class PlatformKeyManagerTest { any()); } @Test public void getDecryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); // new version is available when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).containsAlias( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), any()); } @Test public void getDecryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).containsAlias( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), any()); } @Test public void getEncryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception { doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( Loading @@ -272,9 +325,15 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); Loading @@ -295,11 +354,16 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed. + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); // new version is available + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); Loading @@ -312,14 +376,70 @@ public class PlatformKeyManagerTest { } @Test public void getEncryptKey_generatesNewKeyIfOldWasRemoved() throws Exception { public void getEncryptKey_generatesNewKeyIfDecryptKeyIsUnrecoverable() throws Exception { doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), any()); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); // new version is available when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(false); // was removed. + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), any()); } @Test public void getEncryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); // new version is available when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).containsAlias( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), any()); } @Test public void getEncryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); Loading @@ -332,10 +452,13 @@ public class PlatformKeyManagerTest { } @Test public void getEncryptKey_getsEndryptKeyWithCorrectAlias() throws Exception { public void getEncryptKey_getsEncryptKeyWithCorrectAlias() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); Loading Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +9 −11 Original line number Diff line number Diff line Loading @@ -194,6 +194,9 @@ public class PlatformKeyManager { UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { init(userId); try { // Try to see if the decryption key is still accessible before using the encryption key. // The auth-bound decryption will be unrecoverable if the screen lock is disabled. getDecryptKeyInternal(userId); return getEncryptKeyInternal(userId); } catch (UnrecoverableKeyException e) { Log.i(TAG, String.format(Locale.US, Loading @@ -219,7 +222,7 @@ public class PlatformKeyManager { UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { int generationId = getGenerationId(userId); String alias = getEncryptAlias(userId, generationId); if (!mKeyStore.containsAlias(alias)) { if (!isKeyLoaded(userId, generationId)) { throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); } AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( Loading Loading @@ -268,7 +271,7 @@ public class PlatformKeyManager { UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { int generationId = getGenerationId(userId); String alias = getDecryptAlias(userId, generationId); if (!mKeyStore.containsAlias(alias)) { if (!isKeyLoaded(userId, generationId)) { throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); } AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( Loading Loading @@ -300,12 +303,12 @@ public class PlatformKeyManager { return; } if (generationId == -1) { Log.i(TAG, "Generating initial platform ID."); Log.i(TAG, "Generating initial platform key generation ID."); generationId = 1; } else { Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no " + "entry was present in AndroidKeyStore. Generating fresh key.", generationId)); // Had to generate a fresh key, bump the generation id // Have to generate a fresh key, so bump the generation id generationId++; } Loading Loading @@ -374,7 +377,7 @@ public class PlatformKeyManager { String decryptAlias = getDecryptAlias(userId, generationId); SecretKey secretKey = generateAesKey(); // Store Since decryption key first since it is more likely to fail. // Store decryption key first since it is more likely to fail. mKeyStore.setEntry( decryptAlias, new KeyStore.SecretKeyEntry(secretKey), Loading @@ -386,7 +389,6 @@ public class PlatformKeyManager { .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setBoundToSpecificSecureUserId(userId) .build()); mKeyStore.setEntry( encryptAlias, new KeyStore.SecretKeyEntry(secretKey), Loading @@ -397,11 +399,7 @@ public class PlatformKeyManager { setGenerationId(userId, generationId); try { secretKey.destroy(); } catch (DestroyFailedException e) { Log.w(TAG, "Failed to destroy in-memory platform key.", e); } // TODO: Use a reliable way to destroy the temporary secretKey in memory. } /** Loading
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +129 −6 Original line number Diff line number Diff line Loading @@ -255,6 +255,9 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); Loading @@ -263,6 +266,56 @@ public class PlatformKeyManagerTest { any()); } @Test public void getDecryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); // new version is available when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).containsAlias( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), any()); } @Test public void getDecryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).containsAlias( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), any()); } @Test public void getEncryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception { doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( Loading @@ -272,9 +325,15 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); Loading @@ -295,11 +354,16 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed. + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); // new version is available + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); Loading @@ -312,14 +376,70 @@ public class PlatformKeyManagerTest { } @Test public void getEncryptKey_generatesNewKeyIfOldWasRemoved() throws Exception { public void getEncryptKey_generatesNewKeyIfDecryptKeyIsUnrecoverable() throws Exception { doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), any()); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); // new version is available when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(false); // was removed. + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), any()); } @Test public void getEncryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); // new version is available when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).containsAlias( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), any()); } @Test public void getEncryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(false); // was removed when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); Loading @@ -332,10 +452,13 @@ public class PlatformKeyManagerTest { } @Test public void getEncryptKey_getsEndryptKeyWithCorrectAlias() throws Exception { public void getEncryptKey_getsEncryptKeyWithCorrectAlias() throws Exception { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); Loading