diff options
3 files changed, 44 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index e26630bc4aee..3a24091ec1c6 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -1562,8 +1562,9 @@ public class LockSettingsService extends ILockSettings.Stub { // migration to synthetic password. synchronized (mSpManager) { if (shouldMigrateToSyntheticPasswordLocked(userId)) { - initializeSyntheticPasswordLocked(storedHash.hash, credential, - storedHash.type, userId); + AuthenticationToken auth = initializeSyntheticPasswordLocked( + storedHash.hash, credential, storedHash.type, userId); + activateEscrowTokens(auth, userId); } } } @@ -2071,9 +2072,11 @@ public class LockSettingsService extends ILockSettings.Stub { pwdHandle, null, userId).authToken; } } - disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); - if (!mSpManager.hasEscrowData(userId)) { - throw new SecurityException("Escrow token is disabled on the current user"); + if (isSyntheticPasswordBasedCredentialLocked(userId)) { + disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); + if (!mSpManager.hasEscrowData(userId)) { + throw new SecurityException("Escrow token is disabled on the current user"); + } } long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId); if (auth != null) { @@ -2085,6 +2088,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId); + disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); synchronized (mSpManager) { for (long handle : mSpManager.getPendingTokensForUser(userId)) { Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId)); diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java index 2517613c03e0..d23584fab372 100644 --- a/services/core/java/com/android/server/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/SyntheticPasswordManager.java @@ -48,6 +48,20 @@ import java.util.Set; * The SP has an associated password handle, which binds to the SID for that user. The password * handle is persisted by SyntheticPasswordManager internally. * If the user credential is null, it's treated as if the credential is DEFAULT_PASSWORD + * + * Information persisted on disk: + * for each user (stored under DEFAULT_HANDLE): + * SP_HANDLE_NAME: GateKeeper password handle of synthetic password. Only available if user + * credential exists, cleared when user clears their credential. + * SP_E0_NAME, SP_P1_NAME: Secret to derive synthetic password when combined with escrow + * tokens. Destroyed when escrow support is turned off for the given user. + * + * for each SP blob under the user (stored under the corresponding handle): + * SP_BLOB_NAME: The encrypted synthetic password. Always exists. + * PASSWORD_DATA_NAME: Metadata about user credential. Only exists for password based SP. + * SECDISCARDABLE_NAME: Part of the necessary ingredient to decrypt SP_BLOB_NAME for the + * purpose of secure deletion. + * */ public class SyntheticPasswordManager { private static final String SP_BLOB_NAME = "spblob"; @@ -221,7 +235,7 @@ public class SyntheticPasswordManager { * If the existing credential hash is non-null, the existing SID mill be migrated so * the synthetic password in the authentication token will produce the same SID * (the corresponding synthetic password handle is persisted by SyntheticPasswordManager - * in a per-user data storage. + * in a per-user data storage.) * * If the existing credential hash is null, it means the given user should have no SID so * SyntheticPasswordManager will nuke any SP handle previously persisted. In this case, @@ -578,8 +592,6 @@ public class SyntheticPasswordManager { private void destroySyntheticPassword(long handle, int userId) { destroyState(SP_BLOB_NAME, true, handle, userId); - destroyState(SP_E0_NAME, true, handle, userId); - destroyState(SP_P1_NAME, true, handle, userId); destroySPBlobKey(getHandleName(handle)); } diff --git a/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java index 6e5ade12ce2c..3ec71e431155 100644 --- a/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java @@ -320,6 +320,26 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); } + public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration() throws RemoteException { + final String TOKEN = "some-high-entropy-secure-token"; + final String PASSWORD = "password"; + // Set up pre-SP user password + disableSyntheticPassword(PRIMARY_USER_ID); + mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + PRIMARY_USER_ID); + enableSyntheticPassword(PRIMARY_USER_ID); + + long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + // Token not activated immediately since user password exists + assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + // Activate token (password gets migrated to SP at the same time) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, + mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + PRIMARY_USER_ID).getResponseCode()); + // Verify token is activated + assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + } + // b/34600579 //TODO: add non-migration work profile case, and unify/un-unify transition. //TODO: test token after user resets password |