Loading services/core/java/com/android/server/LockSettingsService.java +9 −5 Original line number Diff line number Diff line Loading @@ -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); } } } Loading Loading @@ -2071,10 +2072,12 @@ public class LockSettingsService extends ILockSettings.Stub { pwdHandle, null, userId).authToken; } } 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) { mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId); Loading @@ -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)); Loading services/core/java/com/android/server/SyntheticPasswordManager.java +15 −3 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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, Loading Loading @@ -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)); } Loading services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java +20 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
services/core/java/com/android/server/LockSettingsService.java +9 −5 Original line number Diff line number Diff line Loading @@ -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); } } } Loading Loading @@ -2071,10 +2072,12 @@ public class LockSettingsService extends ILockSettings.Stub { pwdHandle, null, userId).authToken; } } 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) { mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId); Loading @@ -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)); Loading
services/core/java/com/android/server/SyntheticPasswordManager.java +15 −3 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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, Loading Loading @@ -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)); } Loading
services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java +20 −0 Original line number Diff line number Diff line Loading @@ -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 Loading