Merge changes from topic "remove_ce_caching"
* changes: Provide secret to vold to remove credential Force all devices to migrate to synthetic password
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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_PATTERN;
|
||||
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.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
|
||||
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
|
||||
@@ -1511,7 +1510,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
if (credential != null) {
|
||||
Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
|
||||
}
|
||||
clearUserKeyProtection(userId);
|
||||
clearUserKeyProtection(userId, null);
|
||||
getGateKeeperService().clearSecureUserId(userId);
|
||||
mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
|
||||
setKeystorePassword(null, userId);
|
||||
@@ -1688,9 +1687,17 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
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);
|
||||
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 {
|
||||
@@ -2512,7 +2519,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
setKeystorePassword(auth.deriveKeyStorePassword(), userId);
|
||||
} else {
|
||||
clearUserKeyProtection(userId);
|
||||
clearUserKeyProtection(userId, null);
|
||||
setKeystorePassword(null, userId);
|
||||
getGateKeeperService().clearSecureUserId(userId);
|
||||
}
|
||||
@@ -2532,23 +2539,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
|
||||
}
|
||||
long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
// 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;
|
||||
return handle != SyntheticPasswordManager.DEFAULT_HANDLE;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
|
||||
long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
// 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);
|
||||
return true;
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
|
||||
@@ -2698,7 +2694,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);
|
||||
@@ -2829,7 +2825,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
throws RemoteException {
|
||||
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
|
||||
synchronized (mSpManager) {
|
||||
enableSyntheticPasswordLocked();
|
||||
// Migrate to synthetic password based credentials if the user has no password,
|
||||
// the token can then be activated immediately.
|
||||
AuthenticationToken auth = null;
|
||||
|
||||
@@ -215,6 +215,18 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
}
|
||||
}).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(
|
||||
new Answer<Void>() {
|
||||
@Override
|
||||
|
||||
@@ -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<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) {
|
||||
ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
|
||||
Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
|
||||
|
||||
@@ -103,31 +103,6 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPasswordMigration() throws RemoteException {
|
||||
final byte[] password = "testPasswordMigration-password".getBytes();
|
||||
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
enableSyntheticPassword();
|
||||
// Performs migration
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
|
||||
|
||||
// SP-based verification
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertArrayNotEquals(primaryStorageKey,
|
||||
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
|
||||
enableSyntheticPassword();
|
||||
int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
|
||||
@@ -269,86 +244,6 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
|
||||
final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
|
||||
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
|
||||
assertTrue(primarySid != 0);
|
||||
assertTrue(profileSid != 0);
|
||||
assertTrue(profileSid != primarySid);
|
||||
|
||||
// do migration
|
||||
enableSyntheticPassword();
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
|
||||
// verify
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
assertArrayNotEquals(primaryStorageKey,
|
||||
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
assertArrayNotEquals(profileStorageKey,
|
||||
mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
|
||||
final byte[] primaryPassword =
|
||||
"testManagedProfileSeparateChallengeMigration-primary".getBytes();
|
||||
final byte[] profilePassword =
|
||||
"testManagedProfileSeparateChallengeMigration-profile".getBytes();
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
|
||||
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
|
||||
assertTrue(primarySid != 0);
|
||||
assertTrue(profileSid != 0);
|
||||
assertTrue(profileSid != primarySid);
|
||||
|
||||
// do migration
|
||||
enableSyntheticPassword();
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
0, MANAGED_PROFILE_USER_ID).getResponseCode());
|
||||
|
||||
// verify
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
0, MANAGED_PROFILE_USER_ID).getResponseCode());
|
||||
assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
assertArrayNotEquals(primaryStorageKey,
|
||||
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
|
||||
assertArrayNotEquals(profileStorageKey,
|
||||
mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
|
||||
assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenBasedResetPassword() throws RemoteException {
|
||||
final byte[] password = "password".getBytes();
|
||||
|
||||
Reference in New Issue
Block a user