Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +16 −2 Original line number Diff line number Diff line Loading @@ -1931,7 +1931,8 @@ public class LockSettingsService extends ILockSettings.Stub { * This is the untrusted credential reset, OR the user sets a new lockscreen password * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created */ private AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, @VisibleForTesting protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, String credential, int credentialType, int requestedQuality, int userId) throws RemoteException { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); Loading Loading @@ -1982,7 +1983,8 @@ public class LockSettingsService extends ILockSettings.Stub { return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE; } private boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException { @VisibleForTesting protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException { long handle = getSyntheticPasswordHandleLocked(userId); // This is a global setting long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, Loading Loading @@ -2017,6 +2019,10 @@ public class LockSettingsService extends ILockSettings.Stub { authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( getGateKeeperService(), handle, userCredential, userId); if (authResult.credentialType != credentialType) { Slog.e(TAG, "Credential type mismatch."); return VerifyCredentialResponse.ERROR; } response = authResult.gkResponse; // credential has matched if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { Loading Loading @@ -2136,6 +2142,14 @@ public class LockSettingsService extends ILockSettings.Stub { getGateKeeperService(), handle, savedCredential, userId); VerifyCredentialResponse response = authResult.gkResponse; AuthenticationToken auth = authResult.authToken; // If existing credential is provided, then it must match. if (savedCredential != null && auth == null) { throw new RemoteException("Failed to enroll " + (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern")); } if (auth != null) { // We are performing a trusted credential change i.e. a correct existing credential // is provided Loading services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +4 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ public class SyntheticPasswordManager { static class AuthenticationResult { public AuthenticationToken authToken; public VerifyCredentialResponse gkResponse; public int credentialType; } static class AuthenticationToken { Loading Loading @@ -754,6 +755,8 @@ public class SyntheticPasswordManager { * Decrypt a synthetic password by supplying the user credential and corresponding password * blob handle generated previously. If the decryption is successful, initiate a GateKeeper * verification to referesh the SID & Auth token maintained by the system. * Note: the credential type is not validated here since there are call sites where the type is * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType */ public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, long handle, String credential, int userId) throws RemoteException { Loading @@ -762,6 +765,7 @@ public class SyntheticPasswordManager { } AuthenticationResult result = new AuthenticationResult(); PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, userId)); result.credentialType = pwd.passwordType; byte[] pwdToken = computePasswordToken(credential, pwd); final byte[] applicationId; Loading services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +11 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.content.ComponentName; import android.content.pm.UserInfo; import android.os.FileUtils; Loading @@ -38,6 +39,7 @@ import android.os.storage.IStorageManager; import android.security.KeyStore; import android.test.AndroidTestCase; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; import org.mockito.invocation.InvocationOnMock; Loading Loading @@ -67,7 +69,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { LockSettingsStorageTestable mStorage; LockPatternUtils mLockPatternUtils; MockGateKeeperService mGateKeeperService; FakeGateKeeperService mGateKeeperService; NotificationManager mNotificationManager; UserManager mUserManager; FakeStorageManager mStorageManager; Loading @@ -80,8 +82,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); mLockPatternUtils = mock(LockPatternUtils.class); mGateKeeperService = new MockGateKeeperService(); mGateKeeperService = new FakeGateKeeperService(); mNotificationManager = mock(NotificationManager.class); mUserManager = mock(UserManager.class); mStorageManager = new FakeStorageManager(); Loading @@ -89,7 +90,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { mDevicePolicyManager = mock(DevicePolicyManager.class); mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager, mDevicePolicyManager, mock(StorageManager.class)); mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class)); mStorage = new LockSettingsStorageTestable(mContext, new File(getContext().getFilesDir(), "locksettings")); File storageDir = mStorage.mStorageDir; Loading @@ -99,6 +100,12 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { storageDir.mkdirs(); } mLockPatternUtils = new LockPatternUtils(mContext) { @Override public ILockSettings getLockSettings() { return mService; } }; mSpManager = new MockSyntheticPasswordManager(mStorage, mGateKeeperService, mUserManager); mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage, mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager, Loading @@ -122,8 +129,6 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { } }); when(mLockPatternUtils.getLockSettings()).thenReturn(mService); // Adding a fake Device Owner app which will enable escrow token support in LSS. when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( new ComponentName("com.dummy.package", ".FakeDeviceOwner")); Loading services/tests/servicestests/src/com/android/server/locksettings/MockGateKeeperService.java→services/tests/servicestests/src/com/android/server/locksettings/FakeGateKeeperService.java +10 −10 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; public class MockGateKeeperService implements IGateKeeperService { public class FakeGateKeeperService implements IGateKeeperService { static class VerifyHandle { public byte[] password; public long sid; Loading Loading @@ -92,7 +92,6 @@ public class MockGateKeeperService implements IGateKeeperService { @Override public GateKeeperResponse enroll(int uid, byte[] currentPasswordHandle, byte[] currentPassword, byte[] desiredPassword) throws android.os.RemoteException { if (currentPasswordHandle != null) { VerifyHandle handle = new VerifyHandle(currentPasswordHandle); if (Arrays.equals(currentPassword, handle.password)) { Loading @@ -101,18 +100,19 @@ public class MockGateKeeperService implements IGateKeeperService { refreshSid(uid, handle.sid, false); handleMap.put(uid, newHandle.toBytes()); return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false); } else { } else if (currentPassword != null) { // current password is provided but does not match handle, this is an error case. return null; } } else { // Untrusted enroll // Fall through: password handle is provided, but no password } // Untrusted/new enrollment: generate a new SID long newSid = new Random().nextLong(); VerifyHandle newHandle = new VerifyHandle(desiredPassword, newSid); refreshSid(uid, newSid, true); handleMap.put(uid, newHandle.toBytes()); return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false); } } @Override public GateKeeperResponse verify(int uid, byte[] enrolledPasswordHandle, Loading services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +2 −3 Original line number Diff line number Diff line Loading @@ -103,12 +103,10 @@ public class LockSettingsServiceTestable extends LockSettingsService { public int binderGetCallingUid() { return Process.SYSTEM_UID; } } protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils, LockSettingsStorage storage, MockGateKeeperService gatekeeper, KeyStore keystore, LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore, IStorageManager storageManager, IActivityManager mActivityManager, SyntheticPasswordManager spManager) { super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils, Loading Loading @@ -137,4 +135,5 @@ public class LockSettingsServiceTestable extends LockSettingsService { } return new String(storedData); } } Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +16 −2 Original line number Diff line number Diff line Loading @@ -1931,7 +1931,8 @@ public class LockSettingsService extends ILockSettings.Stub { * This is the untrusted credential reset, OR the user sets a new lockscreen password * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created */ private AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, @VisibleForTesting protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, String credential, int credentialType, int requestedQuality, int userId) throws RemoteException { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); Loading Loading @@ -1982,7 +1983,8 @@ public class LockSettingsService extends ILockSettings.Stub { return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE; } private boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException { @VisibleForTesting protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException { long handle = getSyntheticPasswordHandleLocked(userId); // This is a global setting long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, Loading Loading @@ -2017,6 +2019,10 @@ public class LockSettingsService extends ILockSettings.Stub { authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( getGateKeeperService(), handle, userCredential, userId); if (authResult.credentialType != credentialType) { Slog.e(TAG, "Credential type mismatch."); return VerifyCredentialResponse.ERROR; } response = authResult.gkResponse; // credential has matched if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { Loading Loading @@ -2136,6 +2142,14 @@ public class LockSettingsService extends ILockSettings.Stub { getGateKeeperService(), handle, savedCredential, userId); VerifyCredentialResponse response = authResult.gkResponse; AuthenticationToken auth = authResult.authToken; // If existing credential is provided, then it must match. if (savedCredential != null && auth == null) { throw new RemoteException("Failed to enroll " + (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern")); } if (auth != null) { // We are performing a trusted credential change i.e. a correct existing credential // is provided Loading
services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +4 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ public class SyntheticPasswordManager { static class AuthenticationResult { public AuthenticationToken authToken; public VerifyCredentialResponse gkResponse; public int credentialType; } static class AuthenticationToken { Loading Loading @@ -754,6 +755,8 @@ public class SyntheticPasswordManager { * Decrypt a synthetic password by supplying the user credential and corresponding password * blob handle generated previously. If the decryption is successful, initiate a GateKeeper * verification to referesh the SID & Auth token maintained by the system. * Note: the credential type is not validated here since there are call sites where the type is * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType */ public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, long handle, String credential, int userId) throws RemoteException { Loading @@ -762,6 +765,7 @@ public class SyntheticPasswordManager { } AuthenticationResult result = new AuthenticationResult(); PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, userId)); result.credentialType = pwd.passwordType; byte[] pwdToken = computePasswordToken(credential, pwd); final byte[] applicationId; Loading
services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +11 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.content.ComponentName; import android.content.pm.UserInfo; import android.os.FileUtils; Loading @@ -38,6 +39,7 @@ import android.os.storage.IStorageManager; import android.security.KeyStore; import android.test.AndroidTestCase; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; import org.mockito.invocation.InvocationOnMock; Loading Loading @@ -67,7 +69,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { LockSettingsStorageTestable mStorage; LockPatternUtils mLockPatternUtils; MockGateKeeperService mGateKeeperService; FakeGateKeeperService mGateKeeperService; NotificationManager mNotificationManager; UserManager mUserManager; FakeStorageManager mStorageManager; Loading @@ -80,8 +82,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); mLockPatternUtils = mock(LockPatternUtils.class); mGateKeeperService = new MockGateKeeperService(); mGateKeeperService = new FakeGateKeeperService(); mNotificationManager = mock(NotificationManager.class); mUserManager = mock(UserManager.class); mStorageManager = new FakeStorageManager(); Loading @@ -89,7 +90,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { mDevicePolicyManager = mock(DevicePolicyManager.class); mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager, mDevicePolicyManager, mock(StorageManager.class)); mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class)); mStorage = new LockSettingsStorageTestable(mContext, new File(getContext().getFilesDir(), "locksettings")); File storageDir = mStorage.mStorageDir; Loading @@ -99,6 +100,12 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { storageDir.mkdirs(); } mLockPatternUtils = new LockPatternUtils(mContext) { @Override public ILockSettings getLockSettings() { return mService; } }; mSpManager = new MockSyntheticPasswordManager(mStorage, mGateKeeperService, mUserManager); mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage, mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager, Loading @@ -122,8 +129,6 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { } }); when(mLockPatternUtils.getLockSettings()).thenReturn(mService); // Adding a fake Device Owner app which will enable escrow token support in LSS. when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( new ComponentName("com.dummy.package", ".FakeDeviceOwner")); Loading
services/tests/servicestests/src/com/android/server/locksettings/MockGateKeeperService.java→services/tests/servicestests/src/com/android/server/locksettings/FakeGateKeeperService.java +10 −10 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; public class MockGateKeeperService implements IGateKeeperService { public class FakeGateKeeperService implements IGateKeeperService { static class VerifyHandle { public byte[] password; public long sid; Loading Loading @@ -92,7 +92,6 @@ public class MockGateKeeperService implements IGateKeeperService { @Override public GateKeeperResponse enroll(int uid, byte[] currentPasswordHandle, byte[] currentPassword, byte[] desiredPassword) throws android.os.RemoteException { if (currentPasswordHandle != null) { VerifyHandle handle = new VerifyHandle(currentPasswordHandle); if (Arrays.equals(currentPassword, handle.password)) { Loading @@ -101,18 +100,19 @@ public class MockGateKeeperService implements IGateKeeperService { refreshSid(uid, handle.sid, false); handleMap.put(uid, newHandle.toBytes()); return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false); } else { } else if (currentPassword != null) { // current password is provided but does not match handle, this is an error case. return null; } } else { // Untrusted enroll // Fall through: password handle is provided, but no password } // Untrusted/new enrollment: generate a new SID long newSid = new Random().nextLong(); VerifyHandle newHandle = new VerifyHandle(desiredPassword, newSid); refreshSid(uid, newSid, true); handleMap.put(uid, newHandle.toBytes()); return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false); } } @Override public GateKeeperResponse verify(int uid, byte[] enrolledPasswordHandle, Loading
services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +2 −3 Original line number Diff line number Diff line Loading @@ -103,12 +103,10 @@ public class LockSettingsServiceTestable extends LockSettingsService { public int binderGetCallingUid() { return Process.SYSTEM_UID; } } protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils, LockSettingsStorage storage, MockGateKeeperService gatekeeper, KeyStore keystore, LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore, IStorageManager storageManager, IActivityManager mActivityManager, SyntheticPasswordManager spManager) { super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils, Loading Loading @@ -137,4 +135,5 @@ public class LockSettingsServiceTestable extends LockSettingsService { } return new String(storedData); } }