diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 92fecaddff223..bbc936d76e1cc 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -193,4 +193,5 @@ interface IStorageManager { void startCheckpoint(int numTries) = 85; boolean needsCheckpoint() = 86; void abortChanges(in String message, boolean retry) = 87; + void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88; } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index bcc3bdb0a232c..c95d3e87f2b03 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2988,6 +2988,24 @@ class StorageManagerService extends IStorageManager.Stub } } + /* + * Clear disk encryption key bound to the associated token / secret pair. Removing the user + * binding of the Disk encryption key is done in two phases: first, this call will retrieve + * the disk encryption key using the provided token / secret pair and store it by + * encrypting it with a keymaster key not bound to the user, then fixateNewestUserKeyAuth + * is called to delete all other bindings of the disk encryption key. + */ + @Override + public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) { + enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); + + try { + mVold.clearUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret)); + } catch (Exception e) { + Slog.wtf(TAG, e); + } + } + /* * Delete all disk encryption token/secret pairs except the most recently added one */ diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 7233f3465d5b8..baae4ea502d53 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1622,7 +1622,7 @@ public class LockSettingsService extends ILockSettings.Stub { } if (credential.isNone()) { - clearUserKeyProtection(userId); + clearUserKeyProtection(userId, null); gateKeeperClearSecureUserId(userId); mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); // Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path, @@ -1813,9 +1813,17 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, token, secretFromCredential(credential)); } - private void clearUserKeyProtection(int userId) { + private void clearUserKeyProtection(int userId, byte[] secret) { if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId); - addUserKeyAuth(userId, null, null); + final UserInfo userInfo = mUserManager.getUserInfo(userId); + final long callingId = Binder.clearCallingIdentity(); + try { + mStorageManager.clearUserKeyAuth(userId, userInfo.serialNumber, null, secret); + } catch (RemoteException e) { + throw new IllegalStateException("clearUserKeyAuth failed user=" + userId); + } finally { + Binder.restoreCallingIdentity(callingId); + } } private static byte[] secretFromCredential(LockscreenCredential credential) { @@ -2571,7 +2579,7 @@ public class LockSettingsService extends ILockSettings.Stub { setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); setKeystorePassword(auth.deriveKeyStorePassword(), userId); } else { - clearUserKeyProtection(userId); + clearUserKeyProtection(userId, null); setKeystorePassword(null, userId); gateKeeperClearSecureUserId(userId); } @@ -2765,7 +2773,7 @@ public class LockSettingsService extends ILockSettings.Stub { // during boot. Vold storage needs to be unlocked before manipulation of the keys can // succeed. unlockUserKey(userId, null, auth.deriveDiskEncryptionKey()); - clearUserKeyProtection(userId); + clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); fixateNewestUserKeyAuth(userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); setKeystorePassword(null, userId); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index a3d15dd7de3b0..1b5c56a4b4c93 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -230,6 +230,18 @@ public abstract class BaseLockSettingsServiceTests { } }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any()); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + mStorageManager.clearUserKeyAuth((int) args[0] /* userId */, + (int) args[1] /* serialNumber */, + (byte[]) args[2] /* token */, + (byte[]) args[3] /* secret */); + return null; + } + }).when(sm).clearUserKeyAuth(anyInt(), anyInt(), any(), any()); + doAnswer( new Answer() { @Override diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java index 1ae1fa65ddf2c..102bac111adac 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java @@ -36,6 +36,15 @@ public class FakeStorageManager { getUserAuth(userId).add(new Pair<>(token, secret)); } + public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) { + ArrayList> auths = getUserAuth(userId); + if (token == null && secret == null) { + return; + } + auths.remove(new Pair<>(token, secret)); + auths.add(new Pair<>(null, null)); + } + public void fixateNewestUserKeyAuth(int userId) { ArrayList> auths = mAuth.get(userId); Pair latest = auths.get(auths.size() - 1);