Handle managed profile with unified challenge in getHashFactor()
Settings passes null into getHashFactor() when a profile user has
unified challenge. In this case getHashFactor() needs to derive the real
profile password before it can calculate the hash factor.
Bug: 80077655
Test: runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests
Change-Id: Ifa1d88818b58f914fd3560bb6ef44012facde87b
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 1078f6e..36b04fc 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2537,6 +2537,7 @@
* Returns a fixed pseudorandom byte string derived from the user's synthetic password.
* This is used to salt the password history hash to protect the hash against offline
* bruteforcing, since rederiving this value requires a successful authentication.
+ * If user is a managed profile with unified challenge, currentCredential is ignored.
*/
@Override
public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
@@ -2544,6 +2545,14 @@
if (TextUtils.isEmpty(currentCredential)) {
currentCredential = null;
}
+ if (isManagedProfileWithUnifiedLock(userId)) {
+ try {
+ currentCredential = getDecryptedPasswordForTiedProfile(userId);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to get work profile credential", e);
+ return null;
+ }
+ }
synchronized (mSpManager) {
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
Slog.w(TAG, "Synthetic password not enabled");
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 142b950..94e02bc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -448,6 +448,39 @@
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
+ public void testgetHashFactorPrimaryUser() throws RemoteException {
+ final String password = "password";
+ mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
+ assertNotNull(hashFactor);
+
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
+ PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
+ assertNotNull(newHashFactor);
+ // Hash factor should never change after password change/removal
+ assertArrayEquals(hashFactor, newHashFactor);
+ }
+
+ public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
+ final String pattern = "1236";
+ mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null,
+ PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
+ }
+
+ public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
+ final String primaryPassword = "primary";
+ final String profilePassword = "profile";
+ mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
+ assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
+ }
+
public void testPasswordData_serializeDeserialize() {
PasswordData data = new PasswordData();
data.scryptN = 11;