Loading core/java/android/os/storage/IStorageManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -193,4 +193,5 @@ interface IStorageManager { void startCheckpoint(int numTries) = 85; void startCheckpoint(int numTries) = 85; boolean needsCheckpoint() = 86; boolean needsCheckpoint() = 86; void abortChanges(in String message, boolean retry) = 87; void abortChanges(in String message, boolean retry) = 87; void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88; } } services/core/java/com/android/server/StorageManagerService.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -2787,6 +2787,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 * Delete all disk encryption token/secret pairs except the most recently added one */ */ Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +15 −20 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,6 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.USER_FRP; import static com.android.internal.widget.LockPatternUtils.USER_FRP; Loading Loading @@ -1511,7 +1510,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (credential != null) { if (credential != null) { Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); } } clearUserKeyProtection(userId); clearUserKeyProtection(userId, null); getGateKeeperService().clearSecureUserId(userId); getGateKeeperService().clearSecureUserId(userId); mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); setKeystorePassword(null, userId); setKeystorePassword(null, userId); Loading Loading @@ -1688,9 +1687,17 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, token, secretFromCredential(credential)); addUserKeyAuth(userId, token, secretFromCredential(credential)); } } private void clearUserKeyProtection(int userId) throws RemoteException { private void clearUserKeyProtection(int userId, byte[] secret) { if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId); 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(byte[] credential) throws RemoteException { private static byte[] secretFromCredential(byte[] credential) throws RemoteException { Loading Loading @@ -2512,7 +2519,7 @@ public class LockSettingsService extends ILockSettings.Stub { setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); setKeystorePassword(auth.deriveKeyStorePassword(), userId); setKeystorePassword(auth.deriveKeyStorePassword(), userId); } else { } else { clearUserKeyProtection(userId); clearUserKeyProtection(userId, null); setKeystorePassword(null, userId); setKeystorePassword(null, userId); getGateKeeperService().clearSecureUserId(userId); getGateKeeperService().clearSecureUserId(userId); } } Loading @@ -2532,23 +2539,12 @@ public class LockSettingsService extends ILockSettings.Stub { return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER; return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER; } } long handle = getSyntheticPasswordHandleLocked(userId); long handle = getSyntheticPasswordHandleLocked(userId); // This is a global setting return handle != SyntheticPasswordManager.DEFAULT_HANDLE; long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM); return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE; } } @VisibleForTesting @VisibleForTesting protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { long handle = getSyntheticPasswordHandleLocked(userId); return true; // This is a global setting long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM); return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE; } private void enableSyntheticPasswordLocked() { setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); } } private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, Loading Loading @@ -2698,7 +2694,7 @@ public class LockSettingsService extends ILockSettings.Stub { // during boot. Vold storage needs to be unlocked before manipulation of the keys can // during boot. Vold storage needs to be unlocked before manipulation of the keys can // succeed. // succeed. unlockUserKey(userId, null, auth.deriveDiskEncryptionKey()); unlockUserKey(userId, null, auth.deriveDiskEncryptionKey()); clearUserKeyProtection(userId); clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); fixateNewestUserKeyAuth(userId); fixateNewestUserKeyAuth(userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); setKeystorePassword(null, userId); setKeystorePassword(null, userId); Loading Loading @@ -2829,7 +2825,6 @@ public class LockSettingsService extends ILockSettings.Stub { throws RemoteException { throws RemoteException { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { synchronized (mSpManager) { enableSyntheticPasswordLocked(); // Migrate to synthetic password based credentials if the user has no password, // Migrate to synthetic password based credentials if the user has no password, // the token can then be activated immediately. // the token can then be activated immediately. AuthenticationToken auth = null; AuthenticationToken auth = null; Loading services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +12 −0 Original line number Original line Diff line number Diff line Loading @@ -215,6 +215,18 @@ public abstract class BaseLockSettingsServiceTests { } } }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any()); }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any()); doAnswer(new Answer<Void>() { @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( doAnswer( new Answer<Void>() { new Answer<Void>() { @Override @Override Loading services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java +9 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,15 @@ public class FakeStorageManager { getUserAuth(userId).add(new Pair<>(token, secret)); getUserAuth(userId).add(new Pair<>(token, secret)); } } public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) { ArrayList<Pair<byte[], byte[]>> 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) { public void fixateNewestUserKeyAuth(int userId) { ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId); ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId); Pair<byte[], byte[]> latest = auths.get(auths.size() - 1); Pair<byte[], byte[]> latest = auths.get(auths.size() - 1); Loading Loading
core/java/android/os/storage/IStorageManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -193,4 +193,5 @@ interface IStorageManager { void startCheckpoint(int numTries) = 85; void startCheckpoint(int numTries) = 85; boolean needsCheckpoint() = 86; boolean needsCheckpoint() = 86; void abortChanges(in String message, boolean retry) = 87; void abortChanges(in String message, boolean retry) = 87; void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88; } }
services/core/java/com/android/server/StorageManagerService.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -2787,6 +2787,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 * Delete all disk encryption token/secret pairs except the most recently added one */ */ Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +15 −20 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,6 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.USER_FRP; import static com.android.internal.widget.LockPatternUtils.USER_FRP; Loading Loading @@ -1511,7 +1510,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (credential != null) { if (credential != null) { Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); } } clearUserKeyProtection(userId); clearUserKeyProtection(userId, null); getGateKeeperService().clearSecureUserId(userId); getGateKeeperService().clearSecureUserId(userId); mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); setKeystorePassword(null, userId); setKeystorePassword(null, userId); Loading Loading @@ -1688,9 +1687,17 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, token, secretFromCredential(credential)); addUserKeyAuth(userId, token, secretFromCredential(credential)); } } private void clearUserKeyProtection(int userId) throws RemoteException { private void clearUserKeyProtection(int userId, byte[] secret) { if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId); 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(byte[] credential) throws RemoteException { private static byte[] secretFromCredential(byte[] credential) throws RemoteException { Loading Loading @@ -2512,7 +2519,7 @@ public class LockSettingsService extends ILockSettings.Stub { setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); setKeystorePassword(auth.deriveKeyStorePassword(), userId); setKeystorePassword(auth.deriveKeyStorePassword(), userId); } else { } else { clearUserKeyProtection(userId); clearUserKeyProtection(userId, null); setKeystorePassword(null, userId); setKeystorePassword(null, userId); getGateKeeperService().clearSecureUserId(userId); getGateKeeperService().clearSecureUserId(userId); } } Loading @@ -2532,23 +2539,12 @@ public class LockSettingsService extends ILockSettings.Stub { return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER; return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER; } } long handle = getSyntheticPasswordHandleLocked(userId); long handle = getSyntheticPasswordHandleLocked(userId); // This is a global setting return handle != SyntheticPasswordManager.DEFAULT_HANDLE; long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM); return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE; } } @VisibleForTesting @VisibleForTesting protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { long handle = getSyntheticPasswordHandleLocked(userId); return true; // This is a global setting long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM); return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE; } private void enableSyntheticPasswordLocked() { setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); } } private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, Loading Loading @@ -2698,7 +2694,7 @@ public class LockSettingsService extends ILockSettings.Stub { // during boot. Vold storage needs to be unlocked before manipulation of the keys can // during boot. Vold storage needs to be unlocked before manipulation of the keys can // succeed. // succeed. unlockUserKey(userId, null, auth.deriveDiskEncryptionKey()); unlockUserKey(userId, null, auth.deriveDiskEncryptionKey()); clearUserKeyProtection(userId); clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); fixateNewestUserKeyAuth(userId); fixateNewestUserKeyAuth(userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); setKeystorePassword(null, userId); setKeystorePassword(null, userId); Loading Loading @@ -2829,7 +2825,6 @@ public class LockSettingsService extends ILockSettings.Stub { throws RemoteException { throws RemoteException { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { synchronized (mSpManager) { enableSyntheticPasswordLocked(); // Migrate to synthetic password based credentials if the user has no password, // Migrate to synthetic password based credentials if the user has no password, // the token can then be activated immediately. // the token can then be activated immediately. AuthenticationToken auth = null; AuthenticationToken auth = null; Loading
services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +12 −0 Original line number Original line Diff line number Diff line Loading @@ -215,6 +215,18 @@ public abstract class BaseLockSettingsServiceTests { } } }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any()); }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any()); doAnswer(new Answer<Void>() { @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( doAnswer( new Answer<Void>() { new Answer<Void>() { @Override @Override Loading
services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java +9 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,15 @@ public class FakeStorageManager { getUserAuth(userId).add(new Pair<>(token, secret)); getUserAuth(userId).add(new Pair<>(token, secret)); } } public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) { ArrayList<Pair<byte[], byte[]>> 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) { public void fixateNewestUserKeyAuth(int userId) { ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId); ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId); Pair<byte[], byte[]> latest = auths.get(auths.size() - 1); Pair<byte[], byte[]> latest = auths.get(auths.size() - 1); Loading