diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 6b93d8336b95c..05b839df9fa47 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -28,6 +28,7 @@ interface ILockSettings { long getLong(in String key, in long defaultValue, in int userId); String getString(in String key, in String defaultValue, in int userId); void setLockPattern(in String pattern, in String savedPattern, int userId); + void resetKeyStore(int userId); VerifyCredentialResponse checkPattern(in String pattern, int userId); VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId); void setLockPassword(in String password, in String savedPassword, int userId); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 70941b6c300bd..1beea8c11386d 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -534,6 +534,18 @@ public class LockPatternUtils { return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } + /** + * Use it to reset keystore without wiping work profile + */ + public void resetKeyStore(int userId) { + try { + getLockSettings().resetKeyStore(userId); + } catch (RemoteException e) { + // It should not happen + Log.e(TAG, "Couldn't reset keystore " + e); + } + } + /** * Clear any lock pattern or password. */ diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index bc5401215b03f..fbbdccc6bec1a 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -47,6 +47,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; import android.os.Parcel; +import android.os.Process; import android.os.RemoteException; import android.os.storage.IMountService; import android.os.ServiceManager; @@ -128,6 +129,14 @@ public class LockSettingsService extends ILockSettings.Stub { private NotificationManager mNotificationManager; private UserManager mUserManager; + private final KeyStore mKeyStore = KeyStore.getInstance(); + + /** + * The UIDs that are used for system credential storage in keystore. + */ + private static final int[] SYSTEM_CREDENTIAL_UIDS = {Process.WIFI_UID, Process.VPN_UID, + Process.ROOT_UID, Process.SYSTEM_UID}; + static { // Just launch the home screen, which happens anyway ACTION_NULL = new Intent(Intent.ACTION_MAIN); @@ -715,7 +724,7 @@ public class LockSettingsService extends ILockSettings.Stub { NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, CertificateException, IOException { - if (DEBUG) Slog.v(TAG, "Unlock keystore for child profile"); + if (DEBUG) Slog.v(TAG, "Get child profile decrytped key"); byte[] storedData = mStorage.readChildProfileLock(userId); if (storedData == null) { throw new FileNotFoundException("Child profile lock file not found"); @@ -1134,6 +1143,49 @@ public class LockSettingsService extends ILockSettings.Stub { getMountService().fixateNewestUserKeyAuth(userId); } + @Override + public void resetKeyStore(int userId) throws RemoteException { + if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); + int managedUserId = -1; + String managedUserDecryptedPassword = null; + final List profiles = mUserManager.getProfiles(userId); + for (UserInfo pi : profiles) { + // Unlock managed profile with unified lock + if (pi.isManagedProfile() + && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id) + && mStorage.hasChildProfileLock(pi.id)) { + try { + if (managedUserId == -1) { + managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id); + managedUserId = pi.id; + } else { + // Should not happen + Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId + + ", uid2:" + pi.id); + } + } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException + | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException + | BadPaddingException | CertificateException | IOException e) { + Slog.e(TAG, "Failed to decrypt child profile key", e); + } + } + } + try { + // Clear all the users credentials could have been installed in for this user. + for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) { + for (int uid : SYSTEM_CREDENTIAL_UIDS) { + mKeyStore.clearUid(UserHandle.getUid(profileId, uid)); + } + } + } finally { + if (managedUserId != -1 && managedUserDecryptedPassword != null) { + if (DEBUG) Slog.v(TAG, "Restore tied profile lock"); + tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); + } + } + } + @Override public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException { return doVerifyPattern(pattern, false, 0, userId);