Loading services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +17 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_L import android.content.Context; import android.os.RemoteException; import android.os.UserHandle; import android.security.Scrypt; import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; Loading Loading @@ -163,16 +164,28 @@ public class KeySyncTask implements Runnable { } private void syncKeys() throws RemoteException { int generation = mPlatformKeyManager.getGenerationId(mUserId); 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); if (generation < PlatformKeyManager.MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED || mUserId != UserHandle.USER_SYSTEM) { // Only invalidate keys with legacy protection param. mPlatformKeyManager.invalidatePlatformKey(mUserId, generation); } return; } if (isCustomLockScreen()) { Log.w(TAG, "Unsupported credential type " + mCredentialType + " for user " + mUserId); // Keys will be synced when user starts using non custom screen lock. if (generation < PlatformKeyManager.MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED || mUserId != UserHandle.USER_SYSTEM) { mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(mUserId); } return; } if (mPlatformKeyManager.isDeviceLocked(mUserId) && mUserId == UserHandle.USER_SYSTEM) { Log.w(TAG, "Can't sync keys for locked user " + mUserId); return; } Loading services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +21 −29 Original line number Diff line number Diff line Loading @@ -67,8 +67,9 @@ import javax.crypto.spec.GCMParameterSpec; * @hide */ public class PlatformKeyManager { private static final String TAG = "PlatformKeyManager"; static final int MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED = 1000000; private static final String TAG = "PlatformKeyManager"; private static final String KEY_ALGORITHM = "AES"; private static final int KEY_SIZE_BITS = 256; private static final String KEY_ALIAS_PREFIX = Loading Loading @@ -131,14 +132,14 @@ public class PlatformKeyManager { /** * Returns {@code true} if the platform key is available. A platform key won't be available if * the user has not set up a lock screen. * device is locked. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * * @hide */ public boolean isAvailable(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId); public boolean isDeviceLocked(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceLocked(userId); } /** Loading Loading @@ -169,7 +170,6 @@ 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 @@ -177,13 +177,8 @@ public class PlatformKeyManager { */ @VisibleForTesting void regenerate(int userId) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException, throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(userId); int nextId; if (generationId == -1) { Loading @@ -192,6 +187,7 @@ public class PlatformKeyManager { invalidatePlatformKey(userId, generationId); nextId = generationId + 1; } generationId = Math.max(generationId, MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED); generateAndLoadKey(userId, nextId); } Loading @@ -203,7 +199,6 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @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 @@ -211,7 +206,7 @@ public class PlatformKeyManager { */ public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException, RemoteException { IOException, RemoteException { init(userId); try { // Try to see if the decryption key is still accessible before using the encryption key. Loading @@ -234,12 +229,11 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(userId); String alias = getEncryptAlias(userId, generationId); if (!isKeyLoaded(userId, generationId)) { Loading @@ -258,7 +252,6 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @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 @@ -266,7 +259,7 @@ public class PlatformKeyManager { */ public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException, RemoteException { IOException, RemoteException { init(userId); try { PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId); Loading @@ -288,12 +281,11 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(userId); String alias = getDecryptAlias(userId, generationId); if (!isKeyLoaded(userId, generationId)) { Loading Loading @@ -340,13 +332,8 @@ public class PlatformKeyManager { * @hide */ void init(int userId) throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException, throws KeyStoreException, NoSuchAlgorithmException, IOException, RemoteException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(userId); if (isKeyLoaded(userId, generationId)) { Log.i(TAG, String.format( Loading @@ -363,6 +350,7 @@ public class PlatformKeyManager { generationId++; } generationId = Math.max(generationId, MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED); generateAndLoadKey(userId, generationId); } Loading Loading @@ -440,12 +428,16 @@ public class PlatformKeyManager { KeyProtection.Builder decryptionKeyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds( USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE); if (userId != UserHandle.USER_SYSTEM) { // Skip UserAuthenticationRequired for main user if (userId == UserHandle.USER_SYSTEM) { decryptionKeyProtection.setUnlockedDeviceRequired(true); } else { // With setUnlockedDeviceRequired, KeyStore thinks that device is locked . decryptionKeyProtection.setUserAuthenticationRequired(true); decryptionKeyProtection.setUserAuthenticationValidityDurationSeconds( USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS); // Bind decryption key to secondary profile lock screen secret. long secureUserId = getGateKeeperService().getSecureUserId(userId); // TODO(b/124095438): Propagate this failure instead of silently failing. Loading services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +16 −14 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ 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 @@ -46,7 +45,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.Preconditions; import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException; import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils; import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException; Loading Loading @@ -76,8 +74,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.crypto.AEADBadTagException; Loading @@ -89,13 +88,14 @@ import javax.crypto.AEADBadTagException; */ public class RecoverableKeyStoreManager { private static final String TAG = "RecoverableKeyStoreMgr"; private static final long SYNC_DELAY_MILLIS = 2000; private static RecoverableKeyStoreManager mInstance; private final Context mContext; private final RecoverableKeyStoreDb mDatabase; private final RecoverySessionStorage mRecoverySessionStorage; private final ExecutorService mExecutorService; private final ScheduledExecutorService mExecutorService; private final RecoverySnapshotListenersStorage mListenersStorage; private final RecoverableKeyGenerator mRecoverableKeyGenerator; private final RecoverySnapshotStorage mSnapshotStorage; Loading Loading @@ -136,7 +136,7 @@ public class RecoverableKeyStoreManager { context.getApplicationContext(), db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), Executors.newScheduledThreadPool(1), snapshotStorage, new RecoverySnapshotListenersStorage(), platformKeyManager, Loading @@ -152,7 +152,7 @@ public class RecoverableKeyStoreManager { Context context, RecoverableKeyStoreDb recoverableKeyStoreDb, RecoverySessionStorage recoverySessionStorage, ExecutorService executorService, ScheduledExecutorService executorService, RecoverySnapshotStorage snapshotStorage, RecoverySnapshotListenersStorage listenersStorage, PlatformKeyManager platformKeyManager, Loading Loading @@ -724,8 +724,6 @@ 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 @@ -793,8 +791,6 @@ 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 @@ -915,7 +911,7 @@ public class RecoverableKeyStoreManager { int storedHashType, @NonNull byte[] credential, int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { mExecutorService.execute(KeySyncTask.newInstance( mExecutorService.schedule(KeySyncTask.newInstance( mContext, mDatabase, mSnapshotStorage, Loading @@ -923,7 +919,10 @@ public class RecoverableKeyStoreManager { userId, storedHashType, credential, /*credentialUpdated=*/ false)); /*credentialUpdated=*/ false), SYNC_DELAY_MILLIS, TimeUnit.MILLISECONDS ); } catch (NoSuchAlgorithmException e) { Log.wtf(TAG, "Should never happen - algorithm unavailable for KeySync", e); } catch (KeyStoreException e) { Loading @@ -947,7 +946,7 @@ public class RecoverableKeyStoreManager { int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { mExecutorService.execute(KeySyncTask.newInstance( mExecutorService.schedule(KeySyncTask.newInstance( mContext, mDatabase, mSnapshotStorage, Loading @@ -955,7 +954,10 @@ public class RecoverableKeyStoreManager { userId, storedHashType, credential, /*credentialUpdated=*/ true)); /*credentialUpdated=*/ true), SYNC_DELAY_MILLIS, TimeUnit.MILLISECONDS ); } catch (NoSuchAlgorithmException e) { Log.wtf(TAG, "Should never happen - algorithm unavailable for KeySync", e); } catch (KeyStoreException e) { Loading services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +114 −114 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +5 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; Loading Loading @@ -84,7 +85,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Map; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; Loading Loading @@ -157,7 +158,7 @@ public class RecoverableKeyStoreManagerTest { @Mock private PlatformKeyManager mPlatformKeyManager; @Mock private ApplicationKeyStorage mApplicationKeyStorage; @Mock private CleanupManager mCleanupManager; @Mock private ExecutorService mExecutorService; @Mock private ScheduledExecutorService mExecutorService; @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper; private RecoverableKeyStoreDb mRecoverableKeyStoreDb; Loading Loading @@ -1253,7 +1254,7 @@ public class RecoverableKeyStoreManagerTest { mRecoverableKeyStoreManager.lockScreenSecretAvailable( LockPatternUtils.CREDENTIAL_TYPE_PATTERN, "password".getBytes(), 11); verify(mExecutorService).execute(any()); verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any()); } @Test Loading @@ -1263,7 +1264,7 @@ public class RecoverableKeyStoreManagerTest { "password".getBytes(), 11); verify(mExecutorService).execute(any()); verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any()); } private static byte[] encryptedApplicationKey( Loading Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +17 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_L import android.content.Context; import android.os.RemoteException; import android.os.UserHandle; import android.security.Scrypt; import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; Loading Loading @@ -163,16 +164,28 @@ public class KeySyncTask implements Runnable { } private void syncKeys() throws RemoteException { int generation = mPlatformKeyManager.getGenerationId(mUserId); 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); if (generation < PlatformKeyManager.MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED || mUserId != UserHandle.USER_SYSTEM) { // Only invalidate keys with legacy protection param. mPlatformKeyManager.invalidatePlatformKey(mUserId, generation); } return; } if (isCustomLockScreen()) { Log.w(TAG, "Unsupported credential type " + mCredentialType + " for user " + mUserId); // Keys will be synced when user starts using non custom screen lock. if (generation < PlatformKeyManager.MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED || mUserId != UserHandle.USER_SYSTEM) { mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(mUserId); } return; } if (mPlatformKeyManager.isDeviceLocked(mUserId) && mUserId == UserHandle.USER_SYSTEM) { Log.w(TAG, "Can't sync keys for locked user " + mUserId); return; } Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +21 −29 Original line number Diff line number Diff line Loading @@ -67,8 +67,9 @@ import javax.crypto.spec.GCMParameterSpec; * @hide */ public class PlatformKeyManager { private static final String TAG = "PlatformKeyManager"; static final int MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED = 1000000; private static final String TAG = "PlatformKeyManager"; private static final String KEY_ALGORITHM = "AES"; private static final int KEY_SIZE_BITS = 256; private static final String KEY_ALIAS_PREFIX = Loading Loading @@ -131,14 +132,14 @@ public class PlatformKeyManager { /** * Returns {@code true} if the platform key is available. A platform key won't be available if * the user has not set up a lock screen. * device is locked. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * * @hide */ public boolean isAvailable(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId); public boolean isDeviceLocked(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceLocked(userId); } /** Loading Loading @@ -169,7 +170,6 @@ 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 @@ -177,13 +177,8 @@ public class PlatformKeyManager { */ @VisibleForTesting void regenerate(int userId) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException, throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(userId); int nextId; if (generationId == -1) { Loading @@ -192,6 +187,7 @@ public class PlatformKeyManager { invalidatePlatformKey(userId, generationId); nextId = generationId + 1; } generationId = Math.max(generationId, MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED); generateAndLoadKey(userId, nextId); } Loading @@ -203,7 +199,6 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @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 @@ -211,7 +206,7 @@ public class PlatformKeyManager { */ public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException, RemoteException { IOException, RemoteException { init(userId); try { // Try to see if the decryption key is still accessible before using the encryption key. Loading @@ -234,12 +229,11 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(userId); String alias = getEncryptAlias(userId, generationId); if (!isKeyLoaded(userId, generationId)) { Loading @@ -258,7 +252,6 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @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 @@ -266,7 +259,7 @@ public class PlatformKeyManager { */ public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException, RemoteException { IOException, RemoteException { init(userId); try { PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId); Loading @@ -288,12 +281,11 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(userId); String alias = getDecryptAlias(userId, generationId); if (!isKeyLoaded(userId, generationId)) { Loading Loading @@ -340,13 +332,8 @@ public class PlatformKeyManager { * @hide */ void init(int userId) throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException, throws KeyStoreException, NoSuchAlgorithmException, IOException, RemoteException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(userId); if (isKeyLoaded(userId, generationId)) { Log.i(TAG, String.format( Loading @@ -363,6 +350,7 @@ public class PlatformKeyManager { generationId++; } generationId = Math.max(generationId, MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED); generateAndLoadKey(userId, generationId); } Loading Loading @@ -440,12 +428,16 @@ public class PlatformKeyManager { KeyProtection.Builder decryptionKeyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds( USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE); if (userId != UserHandle.USER_SYSTEM) { // Skip UserAuthenticationRequired for main user if (userId == UserHandle.USER_SYSTEM) { decryptionKeyProtection.setUnlockedDeviceRequired(true); } else { // With setUnlockedDeviceRequired, KeyStore thinks that device is locked . decryptionKeyProtection.setUserAuthenticationRequired(true); decryptionKeyProtection.setUserAuthenticationValidityDurationSeconds( USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS); // Bind decryption key to secondary profile lock screen secret. long secureUserId = getGateKeeperService().getSecureUserId(userId); // TODO(b/124095438): Propagate this failure instead of silently failing. Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +16 −14 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ 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 @@ -46,7 +45,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.Preconditions; import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException; import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils; import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException; Loading Loading @@ -76,8 +74,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.crypto.AEADBadTagException; Loading @@ -89,13 +88,14 @@ import javax.crypto.AEADBadTagException; */ public class RecoverableKeyStoreManager { private static final String TAG = "RecoverableKeyStoreMgr"; private static final long SYNC_DELAY_MILLIS = 2000; private static RecoverableKeyStoreManager mInstance; private final Context mContext; private final RecoverableKeyStoreDb mDatabase; private final RecoverySessionStorage mRecoverySessionStorage; private final ExecutorService mExecutorService; private final ScheduledExecutorService mExecutorService; private final RecoverySnapshotListenersStorage mListenersStorage; private final RecoverableKeyGenerator mRecoverableKeyGenerator; private final RecoverySnapshotStorage mSnapshotStorage; Loading Loading @@ -136,7 +136,7 @@ public class RecoverableKeyStoreManager { context.getApplicationContext(), db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), Executors.newScheduledThreadPool(1), snapshotStorage, new RecoverySnapshotListenersStorage(), platformKeyManager, Loading @@ -152,7 +152,7 @@ public class RecoverableKeyStoreManager { Context context, RecoverableKeyStoreDb recoverableKeyStoreDb, RecoverySessionStorage recoverySessionStorage, ExecutorService executorService, ScheduledExecutorService executorService, RecoverySnapshotStorage snapshotStorage, RecoverySnapshotListenersStorage listenersStorage, PlatformKeyManager platformKeyManager, Loading Loading @@ -724,8 +724,6 @@ 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 @@ -793,8 +791,6 @@ 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 @@ -915,7 +911,7 @@ public class RecoverableKeyStoreManager { int storedHashType, @NonNull byte[] credential, int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { mExecutorService.execute(KeySyncTask.newInstance( mExecutorService.schedule(KeySyncTask.newInstance( mContext, mDatabase, mSnapshotStorage, Loading @@ -923,7 +919,10 @@ public class RecoverableKeyStoreManager { userId, storedHashType, credential, /*credentialUpdated=*/ false)); /*credentialUpdated=*/ false), SYNC_DELAY_MILLIS, TimeUnit.MILLISECONDS ); } catch (NoSuchAlgorithmException e) { Log.wtf(TAG, "Should never happen - algorithm unavailable for KeySync", e); } catch (KeyStoreException e) { Loading @@ -947,7 +946,7 @@ public class RecoverableKeyStoreManager { int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { mExecutorService.execute(KeySyncTask.newInstance( mExecutorService.schedule(KeySyncTask.newInstance( mContext, mDatabase, mSnapshotStorage, Loading @@ -955,7 +954,10 @@ public class RecoverableKeyStoreManager { userId, storedHashType, credential, /*credentialUpdated=*/ true)); /*credentialUpdated=*/ true), SYNC_DELAY_MILLIS, TimeUnit.MILLISECONDS ); } catch (NoSuchAlgorithmException e) { Log.wtf(TAG, "Should never happen - algorithm unavailable for KeySync", e); } catch (KeyStoreException e) { Loading
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +114 −114 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +5 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; Loading Loading @@ -84,7 +85,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Map; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; Loading Loading @@ -157,7 +158,7 @@ public class RecoverableKeyStoreManagerTest { @Mock private PlatformKeyManager mPlatformKeyManager; @Mock private ApplicationKeyStorage mApplicationKeyStorage; @Mock private CleanupManager mCleanupManager; @Mock private ExecutorService mExecutorService; @Mock private ScheduledExecutorService mExecutorService; @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper; private RecoverableKeyStoreDb mRecoverableKeyStoreDb; Loading Loading @@ -1253,7 +1254,7 @@ public class RecoverableKeyStoreManagerTest { mRecoverableKeyStoreManager.lockScreenSecretAvailable( LockPatternUtils.CREDENTIAL_TYPE_PATTERN, "password".getBytes(), 11); verify(mExecutorService).execute(any()); verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any()); } @Test Loading @@ -1263,7 +1264,7 @@ public class RecoverableKeyStoreManagerTest { "password".getBytes(), 11); verify(mExecutorService).execute(any()); verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any()); } private static byte[] encryptedApplicationKey( Loading