Loading core/java/com/android/internal/widget/LockPatternUtils.java +2 −1 Original line number Diff line number Diff line Loading @@ -1936,7 +1936,8 @@ public class LockPatternUtils { * If the user is not secured, ie doesn't have an LSKF, then decrypt the user's synthetic * password and use it to unlock various cryptographic keys associated with the user. This * primarily includes unlocking the user's credential-encrypted (CE) storage. It also includes * deriving or decrypting the vendor auth secret and sending it to the AuthSecret HAL. * unlocking the user's Keystore super keys, and deriving or decrypting the vendor auth secret * and sending it to the AuthSecret HAL in order to unlock Secure Element firmware updates. * <p> * These tasks would normally be done when the LSKF is verified. This method is where these * tasks are done when the user doesn't have an LSKF. It's called when the user is started. Loading keystore/java/android/security/AndroidKeyStoreMaintenance.java +47 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public class AndroidKeyStoreMaintenance { * @return 0 if successful or a {@code ResponseCode} * @hide */ public static int onUserAdded(@NonNull int userId) { public static int onUserAdded(int userId) { StrictMode.noteDiskWrite(); try { getService().onUserAdded(userId); Loading @@ -65,6 +65,30 @@ public class AndroidKeyStoreMaintenance { } } /** * Tells Keystore to create a user's super keys and store them encrypted by the given secret. * * @param userId - Android user id of the user * @param password - a secret derived from the user's synthetic password * @param allowExisting - true if the keys already existing should not be considered an error * @return 0 if successful or a {@code ResponseCode} * @hide */ public static int initUserSuperKeys(int userId, @NonNull byte[] password, boolean allowExisting) { StrictMode.noteDiskWrite(); try { getService().initUserSuperKeys(userId, password, allowExisting); return 0; } catch (ServiceSpecificException e) { Log.e(TAG, "initUserSuperKeys failed", e); return e.errorCode; } catch (Exception e) { Log.e(TAG, "Can not connect to keystore", e); return SYSTEM_ERROR; } } /** * Informs Keystore 2.0 about removing a user * Loading Loading @@ -109,6 +133,28 @@ public class AndroidKeyStoreMaintenance { } } /** * Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to * Swipe or None. Keystore uses this notification to delete the user's auth-bound keys. * * @param userId - Android user id of the user * @return 0 if successful or a {@code ResponseCode} * @hide */ public static int onUserLskfRemoved(int userId) { StrictMode.noteDiskWrite(); try { getService().onUserLskfRemoved(userId); return 0; } catch (ServiceSpecificException e) { Log.e(TAG, "onUserLskfRemoved failed", e); return e.errorCode; } catch (Exception e) { Log.e(TAG, "Can not connect to keystore", e); return SYSTEM_ERROR; } } /** * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to * be cleared. Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +127 −26 Original line number Diff line number Diff line Loading @@ -243,6 +243,10 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String MIGRATED_FRP2 = "migrated_frp2"; private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace"; private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce"; private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys"; private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS = android.security.Flags.fixUnlockedDeviceRequiredKeys(); // Duration that LockSettingsService will store the gatekeeper password for. This allows // multiple biometric enrollments without prompting the user to enter their password via Loading Loading @@ -853,9 +857,11 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { // Notify keystore that a new user was added. final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); AndroidKeyStoreMaintenance.onUserAdded(userHandle); } } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); mStorage.prefetchUser(userHandle); Loading Loading @@ -1019,16 +1025,38 @@ public class LockSettingsService extends ILockSettings.Stub { } mEarlyCreatedUsers = null; // no longer needed // Also do a one-time migration of all users to SP-based credentials with the CE key // encrypted by the SP. This is needed for the system user on the first boot of a // device, as the system user is special and never goes through the user creation flow // that other users do. It is also needed for existing users on a device upgraded from // Android 13 or earlier, where users with no LSKF didn't necessarily have an SP, and if // they did have an SP then their CE key wasn't encrypted by it. // Do a one-time migration for any unsecured users: create the user's synthetic password // if not already done, encrypt the user's CE key with the synthetic password if not // already done, and create the user's Keystore super keys if not already done. // // This is needed for the following cases: // // - Finalizing the creation of the system user on the first boot of a device, as the // system user is special and doesn't go through the normal user creation flow. // // If this gets interrupted (e.g. by the device powering off), there shouldn't be a // problem since this will run again on the next boot, and setCeStorageProtection() is // okay with the CE key being already protected by the given secret. // - Upgrading from Android 13 or earlier, where unsecured users didn't necessarily have // a synthetic password, and if they did have a synthetic password their CE key wasn't // encrypted by it. Also, unsecured users didn't have Keystore super keys. // // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys. // // The end result is that all users, regardless of whether they are secured or not, have // a synthetic password with all keys initialized and protected by it. // // Note: if this migration gets interrupted (e.g. by the device powering off), there // shouldn't be a problem since this will run again on the next boot, and // setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent. if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { if (!getBoolean(MIGRATED_SP_FULL, false, 0)) { for (UserInfo user : mUserManager.getAliveUsers()) { removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); synchronized (mSpManager) { migrateUserToSpWithBoundKeysLocked(user.id); } } setBoolean(MIGRATED_SP_FULL, true, 0); } } else { if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { for (UserInfo user : mUserManager.getAliveUsers()) { removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); Loading @@ -1039,6 +1067,13 @@ public class LockSettingsService extends ILockSettings.Stub { setString(MIGRATED_SP_CE_ONLY, "true", 0); } if (getBoolean(MIGRATED_SP_FULL, false, 0)) { // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled. // Ensure the full migration runs again the next time the flag is enabled... setBoolean(MIGRATED_SP_FULL, false, 0); } } mThirdPartyAppsStarted = true; } } Loading Loading @@ -1067,6 +1102,37 @@ public class LockSettingsService extends ILockSettings.Stub { } } @GuardedBy("mSpManager") private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) { if (isUserSecure(userId)) { Slogf.d(TAG, "User %d is secured; no migration needed", userId); return; } long protectorId = getCurrentLskfBasedProtectorId(userId); if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) { Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId); initializeSyntheticPassword(userId); return; } Slogf.i(TAG, "Existing unsecured user %d has a synthetic password", userId); AuthenticationResult result = mSpManager.unlockLskfBasedProtector( getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId, null); SyntheticPassword sp = result.syntheticPassword; if (sp == null) { Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId); return; } // While setCeStorageProtection() is idempotent, it does log some error messages when called // again. Skip it if we know it was already handled by an earlier upgrade to Android 14. if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId); setCeStorageProtection(userId, sp); } Slogf.i(TAG, "Initializing Keystore super keys for user %d", userId); initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true); } /** * Returns the lowest password quality that still presents the same UI for entering it. * Loading Loading @@ -1348,6 +1414,20 @@ public class LockSettingsService extends ILockSettings.Stub { AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password); } @VisibleForTesting /** Note: this method is overridden in unit tests */ void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) { final byte[] password = sp.deriveKeyStorePassword(); try { int res = AndroidKeyStoreMaintenance.initUserSuperKeys(userId, password, allowExisting); if (res != 0) { throw new IllegalStateException("Failed to initialize Keystore super keys for user " + userId); } } finally { Arrays.fill(password, (byte) 0); } } private void unlockKeystore(int userId, SyntheticPassword sp) { Authorization.onLockScreenEvent(false, userId, sp.deriveKeyStorePassword(), null); } Loading Loading @@ -2071,6 +2151,9 @@ public class LockSettingsService extends ILockSettings.Stub { return; } onSyntheticPasswordUnlocked(userId, result.syntheticPassword); if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { unlockKeystore(userId, result.syntheticPassword); } unlockCeStorage(userId, result.syntheticPassword); } } Loading Loading @@ -2350,6 +2433,16 @@ public class LockSettingsService extends ILockSettings.Stub { } private void createNewUser(@UserIdInt int userId, int userSerialNumber) { // Delete all Keystore keys for userId, just in case any were left around from a removed // user with the same userId. This should be unnecessary, but we've been doing this for a // long time, so for now we keep doing it just in case it's ever important. Don't wait // until initKeystoreSuperKeys() to do this; that can be delayed if the user is being // created during early boot, and maybe something will use Keystore before then. if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { AndroidKeyStoreMaintenance.onUserAdded(userId); } synchronized (mUserCreationAndRemovalLock) { // During early boot, don't actually create the synthetic password yet, but rather // automatically delay it to later. We do this because protecting the synthetic Loading Loading @@ -2756,7 +2849,7 @@ public class LockSettingsService extends ILockSettings.Stub { /** * Creates the synthetic password (SP) for the given user, protects it with an empty LSKF, and * protects the user's CE key with a key derived from the SP. * protects the user's CE storage key and Keystore super keys with keys derived from the SP. * * <p>This is called just once in the lifetime of the user: at user creation time (possibly * delayed until the time when Weaver is guaranteed to be available), or when upgrading from Loading @@ -2775,6 +2868,9 @@ public class LockSettingsService extends ILockSettings.Stub { LockscreenCredential.createNone(), sp, userId); setCurrentLskfBasedProtectorId(protectorId, userId); setCeStorageProtection(userId, sp); if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false); } onSyntheticPasswordCreated(userId, sp); Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId); return sp; Loading Loading @@ -2867,11 +2963,10 @@ public class LockSettingsService extends ILockSettings.Stub { /** * Changes the user's LSKF by creating an LSKF-based protector that uses the new LSKF (which may * be empty) and replacing the old LSKF-based protector with it. The SP itself is not changed. * * Also maintains the invariants described in {@link SyntheticPasswordManager} by * setting/clearing the protection (by the SP) on the user's auth-bound Keystore keys when the * LSKF is added/removed, respectively. If an LSKF is being added, then the Gatekeeper auth * token is also refreshed. * <p> * Also maintains the invariants described in {@link SyntheticPasswordManager} by enrolling / * deleting the synthetic password into Gatekeeper as the LSKF is set / cleared, and asking * Keystore to delete the user's auth-bound keys when the LSKF is cleared. */ @GuardedBy("mSpManager") private long setLockCredentialWithSpLocked(LockscreenCredential credential, Loading @@ -2890,8 +2985,10 @@ public class LockSettingsService extends ILockSettings.Stub { if (!mSpManager.hasSidForUser(userId)) { mSpManager.newSidForUser(getGateKeeperService(), sp, userId); mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId); if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { setKeystorePassword(sp.deriveKeyStorePassword(), userId); } } } else { // Cache all profile password if they use unified work challenge. This will later be // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles() Loading @@ -2901,7 +2998,11 @@ public class LockSettingsService extends ILockSettings.Stub { gateKeeperClearSecureUserId(userId); unlockCeStorage(userId, sp); unlockKeystore(userId, sp); if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { AndroidKeyStoreMaintenance.onUserLskfRemoved(userId); } else { setKeystorePassword(null, userId); } removeBiometricsForUser(userId); } setCurrentLskfBasedProtectorId(newProtectorId, userId); Loading services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +9 −4 Original line number Diff line number Diff line Loading @@ -90,10 +90,15 @@ import java.util.Set; * * - The user's credential-encrypted storage is always protected by the SP. * * - The user's auth-bound Keystore keys are protected by the SP, but only while an LSKF is set. * This works by setting the user's Keystore and Gatekeeper passwords to SP-derived secrets, but * only while an LSKF is set. When the LSKF is removed, these passwords are cleared, * invalidating the user's auth-bound keys. * - The user's Keystore superencryption keys are always protected by the SP. These in turn * protect the Keystore keys that require user authentication, an unlocked device, or both. * * - A secret derived from the synthetic password is enrolled in Gatekeeper for the user, but only * while the user has a (nonempty) LSKF. This enrollment has an associated ID called the Secure * user ID or SID. This use of Gatekeeper, which is separate from the use of GateKeeper that may * be used in the LSKF-based protector, makes it so that unlocking the synthetic password * generates a HardwareAuthToken (but only when the user has LSKF). That HardwareAuthToken can * be provided to KeyMint to authorize the use of the user's authentication-bound Keystore keys. * * Files stored on disk for each user: * For the SP itself, stored under NULL_PROTECTOR_ID: Loading services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +5 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.service.gatekeeper.IGateKeeperService; import com.android.internal.widget.LockscreenCredential; import com.android.server.ServiceThread; import com.android.server.locksettings.SyntheticPasswordManager.SyntheticPassword; import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager; import com.android.server.pm.UserManagerInternal; Loading Loading @@ -202,6 +203,10 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) { } @Override protected boolean isCredentialSharableWithParent(int userId) { UserInfo userInfo = mUserManager.getUserInfo(userId); Loading Loading
core/java/com/android/internal/widget/LockPatternUtils.java +2 −1 Original line number Diff line number Diff line Loading @@ -1936,7 +1936,8 @@ public class LockPatternUtils { * If the user is not secured, ie doesn't have an LSKF, then decrypt the user's synthetic * password and use it to unlock various cryptographic keys associated with the user. This * primarily includes unlocking the user's credential-encrypted (CE) storage. It also includes * deriving or decrypting the vendor auth secret and sending it to the AuthSecret HAL. * unlocking the user's Keystore super keys, and deriving or decrypting the vendor auth secret * and sending it to the AuthSecret HAL in order to unlock Secure Element firmware updates. * <p> * These tasks would normally be done when the LSKF is verified. This method is where these * tasks are done when the user doesn't have an LSKF. It's called when the user is started. Loading
keystore/java/android/security/AndroidKeyStoreMaintenance.java +47 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public class AndroidKeyStoreMaintenance { * @return 0 if successful or a {@code ResponseCode} * @hide */ public static int onUserAdded(@NonNull int userId) { public static int onUserAdded(int userId) { StrictMode.noteDiskWrite(); try { getService().onUserAdded(userId); Loading @@ -65,6 +65,30 @@ public class AndroidKeyStoreMaintenance { } } /** * Tells Keystore to create a user's super keys and store them encrypted by the given secret. * * @param userId - Android user id of the user * @param password - a secret derived from the user's synthetic password * @param allowExisting - true if the keys already existing should not be considered an error * @return 0 if successful or a {@code ResponseCode} * @hide */ public static int initUserSuperKeys(int userId, @NonNull byte[] password, boolean allowExisting) { StrictMode.noteDiskWrite(); try { getService().initUserSuperKeys(userId, password, allowExisting); return 0; } catch (ServiceSpecificException e) { Log.e(TAG, "initUserSuperKeys failed", e); return e.errorCode; } catch (Exception e) { Log.e(TAG, "Can not connect to keystore", e); return SYSTEM_ERROR; } } /** * Informs Keystore 2.0 about removing a user * Loading Loading @@ -109,6 +133,28 @@ public class AndroidKeyStoreMaintenance { } } /** * Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to * Swipe or None. Keystore uses this notification to delete the user's auth-bound keys. * * @param userId - Android user id of the user * @return 0 if successful or a {@code ResponseCode} * @hide */ public static int onUserLskfRemoved(int userId) { StrictMode.noteDiskWrite(); try { getService().onUserLskfRemoved(userId); return 0; } catch (ServiceSpecificException e) { Log.e(TAG, "onUserLskfRemoved failed", e); return e.errorCode; } catch (Exception e) { Log.e(TAG, "Can not connect to keystore", e); return SYSTEM_ERROR; } } /** * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to * be cleared. Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +127 −26 Original line number Diff line number Diff line Loading @@ -243,6 +243,10 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String MIGRATED_FRP2 = "migrated_frp2"; private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace"; private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce"; private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys"; private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS = android.security.Flags.fixUnlockedDeviceRequiredKeys(); // Duration that LockSettingsService will store the gatekeeper password for. This allows // multiple biometric enrollments without prompting the user to enter their password via Loading Loading @@ -853,9 +857,11 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { // Notify keystore that a new user was added. final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); AndroidKeyStoreMaintenance.onUserAdded(userHandle); } } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); mStorage.prefetchUser(userHandle); Loading Loading @@ -1019,16 +1025,38 @@ public class LockSettingsService extends ILockSettings.Stub { } mEarlyCreatedUsers = null; // no longer needed // Also do a one-time migration of all users to SP-based credentials with the CE key // encrypted by the SP. This is needed for the system user on the first boot of a // device, as the system user is special and never goes through the user creation flow // that other users do. It is also needed for existing users on a device upgraded from // Android 13 or earlier, where users with no LSKF didn't necessarily have an SP, and if // they did have an SP then their CE key wasn't encrypted by it. // Do a one-time migration for any unsecured users: create the user's synthetic password // if not already done, encrypt the user's CE key with the synthetic password if not // already done, and create the user's Keystore super keys if not already done. // // This is needed for the following cases: // // - Finalizing the creation of the system user on the first boot of a device, as the // system user is special and doesn't go through the normal user creation flow. // // If this gets interrupted (e.g. by the device powering off), there shouldn't be a // problem since this will run again on the next boot, and setCeStorageProtection() is // okay with the CE key being already protected by the given secret. // - Upgrading from Android 13 or earlier, where unsecured users didn't necessarily have // a synthetic password, and if they did have a synthetic password their CE key wasn't // encrypted by it. Also, unsecured users didn't have Keystore super keys. // // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys. // // The end result is that all users, regardless of whether they are secured or not, have // a synthetic password with all keys initialized and protected by it. // // Note: if this migration gets interrupted (e.g. by the device powering off), there // shouldn't be a problem since this will run again on the next boot, and // setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent. if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { if (!getBoolean(MIGRATED_SP_FULL, false, 0)) { for (UserInfo user : mUserManager.getAliveUsers()) { removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); synchronized (mSpManager) { migrateUserToSpWithBoundKeysLocked(user.id); } } setBoolean(MIGRATED_SP_FULL, true, 0); } } else { if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { for (UserInfo user : mUserManager.getAliveUsers()) { removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); Loading @@ -1039,6 +1067,13 @@ public class LockSettingsService extends ILockSettings.Stub { setString(MIGRATED_SP_CE_ONLY, "true", 0); } if (getBoolean(MIGRATED_SP_FULL, false, 0)) { // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled. // Ensure the full migration runs again the next time the flag is enabled... setBoolean(MIGRATED_SP_FULL, false, 0); } } mThirdPartyAppsStarted = true; } } Loading Loading @@ -1067,6 +1102,37 @@ public class LockSettingsService extends ILockSettings.Stub { } } @GuardedBy("mSpManager") private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) { if (isUserSecure(userId)) { Slogf.d(TAG, "User %d is secured; no migration needed", userId); return; } long protectorId = getCurrentLskfBasedProtectorId(userId); if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) { Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId); initializeSyntheticPassword(userId); return; } Slogf.i(TAG, "Existing unsecured user %d has a synthetic password", userId); AuthenticationResult result = mSpManager.unlockLskfBasedProtector( getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId, null); SyntheticPassword sp = result.syntheticPassword; if (sp == null) { Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId); return; } // While setCeStorageProtection() is idempotent, it does log some error messages when called // again. Skip it if we know it was already handled by an earlier upgrade to Android 14. if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId); setCeStorageProtection(userId, sp); } Slogf.i(TAG, "Initializing Keystore super keys for user %d", userId); initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true); } /** * Returns the lowest password quality that still presents the same UI for entering it. * Loading Loading @@ -1348,6 +1414,20 @@ public class LockSettingsService extends ILockSettings.Stub { AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password); } @VisibleForTesting /** Note: this method is overridden in unit tests */ void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) { final byte[] password = sp.deriveKeyStorePassword(); try { int res = AndroidKeyStoreMaintenance.initUserSuperKeys(userId, password, allowExisting); if (res != 0) { throw new IllegalStateException("Failed to initialize Keystore super keys for user " + userId); } } finally { Arrays.fill(password, (byte) 0); } } private void unlockKeystore(int userId, SyntheticPassword sp) { Authorization.onLockScreenEvent(false, userId, sp.deriveKeyStorePassword(), null); } Loading Loading @@ -2071,6 +2151,9 @@ public class LockSettingsService extends ILockSettings.Stub { return; } onSyntheticPasswordUnlocked(userId, result.syntheticPassword); if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { unlockKeystore(userId, result.syntheticPassword); } unlockCeStorage(userId, result.syntheticPassword); } } Loading Loading @@ -2350,6 +2433,16 @@ public class LockSettingsService extends ILockSettings.Stub { } private void createNewUser(@UserIdInt int userId, int userSerialNumber) { // Delete all Keystore keys for userId, just in case any were left around from a removed // user with the same userId. This should be unnecessary, but we've been doing this for a // long time, so for now we keep doing it just in case it's ever important. Don't wait // until initKeystoreSuperKeys() to do this; that can be delayed if the user is being // created during early boot, and maybe something will use Keystore before then. if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { AndroidKeyStoreMaintenance.onUserAdded(userId); } synchronized (mUserCreationAndRemovalLock) { // During early boot, don't actually create the synthetic password yet, but rather // automatically delay it to later. We do this because protecting the synthetic Loading Loading @@ -2756,7 +2849,7 @@ public class LockSettingsService extends ILockSettings.Stub { /** * Creates the synthetic password (SP) for the given user, protects it with an empty LSKF, and * protects the user's CE key with a key derived from the SP. * protects the user's CE storage key and Keystore super keys with keys derived from the SP. * * <p>This is called just once in the lifetime of the user: at user creation time (possibly * delayed until the time when Weaver is guaranteed to be available), or when upgrading from Loading @@ -2775,6 +2868,9 @@ public class LockSettingsService extends ILockSettings.Stub { LockscreenCredential.createNone(), sp, userId); setCurrentLskfBasedProtectorId(protectorId, userId); setCeStorageProtection(userId, sp); if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false); } onSyntheticPasswordCreated(userId, sp); Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId); return sp; Loading Loading @@ -2867,11 +2963,10 @@ public class LockSettingsService extends ILockSettings.Stub { /** * Changes the user's LSKF by creating an LSKF-based protector that uses the new LSKF (which may * be empty) and replacing the old LSKF-based protector with it. The SP itself is not changed. * * Also maintains the invariants described in {@link SyntheticPasswordManager} by * setting/clearing the protection (by the SP) on the user's auth-bound Keystore keys when the * LSKF is added/removed, respectively. If an LSKF is being added, then the Gatekeeper auth * token is also refreshed. * <p> * Also maintains the invariants described in {@link SyntheticPasswordManager} by enrolling / * deleting the synthetic password into Gatekeeper as the LSKF is set / cleared, and asking * Keystore to delete the user's auth-bound keys when the LSKF is cleared. */ @GuardedBy("mSpManager") private long setLockCredentialWithSpLocked(LockscreenCredential credential, Loading @@ -2890,8 +2985,10 @@ public class LockSettingsService extends ILockSettings.Stub { if (!mSpManager.hasSidForUser(userId)) { mSpManager.newSidForUser(getGateKeeperService(), sp, userId); mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId); if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { setKeystorePassword(sp.deriveKeyStorePassword(), userId); } } } else { // Cache all profile password if they use unified work challenge. This will later be // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles() Loading @@ -2901,7 +2998,11 @@ public class LockSettingsService extends ILockSettings.Stub { gateKeeperClearSecureUserId(userId); unlockCeStorage(userId, sp); unlockKeystore(userId, sp); if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { AndroidKeyStoreMaintenance.onUserLskfRemoved(userId); } else { setKeystorePassword(null, userId); } removeBiometricsForUser(userId); } setCurrentLskfBasedProtectorId(newProtectorId, userId); Loading
services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +9 −4 Original line number Diff line number Diff line Loading @@ -90,10 +90,15 @@ import java.util.Set; * * - The user's credential-encrypted storage is always protected by the SP. * * - The user's auth-bound Keystore keys are protected by the SP, but only while an LSKF is set. * This works by setting the user's Keystore and Gatekeeper passwords to SP-derived secrets, but * only while an LSKF is set. When the LSKF is removed, these passwords are cleared, * invalidating the user's auth-bound keys. * - The user's Keystore superencryption keys are always protected by the SP. These in turn * protect the Keystore keys that require user authentication, an unlocked device, or both. * * - A secret derived from the synthetic password is enrolled in Gatekeeper for the user, but only * while the user has a (nonempty) LSKF. This enrollment has an associated ID called the Secure * user ID or SID. This use of Gatekeeper, which is separate from the use of GateKeeper that may * be used in the LSKF-based protector, makes it so that unlocking the synthetic password * generates a HardwareAuthToken (but only when the user has LSKF). That HardwareAuthToken can * be provided to KeyMint to authorize the use of the user's authentication-bound Keystore keys. * * Files stored on disk for each user: * For the SP itself, stored under NULL_PROTECTOR_ID: Loading
services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +5 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.service.gatekeeper.IGateKeeperService; import com.android.internal.widget.LockscreenCredential; import com.android.server.ServiceThread; import com.android.server.locksettings.SyntheticPasswordManager.SyntheticPassword; import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager; import com.android.server.pm.UserManagerInternal; Loading Loading @@ -202,6 +203,10 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) { } @Override protected boolean isCredentialSharableWithParent(int userId) { UserInfo userInfo = mUserManager.getUserInfo(userId); Loading