diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 1de3e37a78c1c..ee8a23c08b4a6 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -73,7 +73,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; import android.hardware.authsecret.V1_0.IAuthSecret; -import android.hardware.biometrics.BiometricManager; import android.hardware.face.Face; import android.hardware.face.FaceManager; import android.hardware.fingerprint.Fingerprint; @@ -89,7 +88,6 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; -import android.os.StrictMode; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; @@ -110,7 +108,6 @@ import android.security.keystore.recovery.RecoveryCertPath; import android.security.keystore.recovery.WrappedApplicationKey; import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import android.security.keystore2.AndroidKeyStoreProvider; -import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; import android.system.keystore2.Domain; import android.text.TextUtils; @@ -141,7 +138,6 @@ import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; -import com.android.server.locksettings.LockSettingsStorage.CredentialHash; import com.android.server.locksettings.LockSettingsStorage.PersistentData; import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken; @@ -163,7 +159,6 @@ import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyStoreException; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; @@ -517,11 +512,6 @@ public class LockSettingsService extends ILockSettings.Stub { return new RebootEscrowManager(mContext, callbacks, storage); } - public boolean hasEnrolledBiometrics(int userId) { - BiometricManager bm = mContext.getSystemService(BiometricManager.class); - return bm.hasEnrolledBiometrics(userId); - } - public int binderGetCallingUid() { return Binder.getCallingUid(); } @@ -1285,11 +1275,8 @@ public class LockSettingsService extends ILockSettings.Stub { return mStorage.getString(key, defaultValue, userId); } - private void setKeyguardStoredQuality(int quality, int userId) { - if (DEBUG) Slog.d(TAG, "setKeyguardStoredQuality: user=" + userId + " quality=" + quality); - mStorage.setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId); - } - + // Not relevant for new devices, but some legacy devices still have PASSWORD_TYPE_KEY around to + // distinguish between credential types. private int getKeyguardStoredQuality(int userId) { return (int) mStorage.getLong(LockPatternUtils.PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId); @@ -1326,18 +1313,6 @@ public class LockSettingsService extends ILockSettings.Stub { return pinOrPasswordQualityToCredentialType(getKeyguardStoredQuality(userId)); } } - // Intentional duplication of the getKeyguardStoredQuality() call above since this is a - // unlikely code path (device with pre-synthetic password credential). We want to skip - // calling getKeyguardStoredQuality whenever possible. - final int savedQuality = getKeyguardStoredQuality(userId); - if (savedQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - && mStorage.hasPattern(userId)) { - return CREDENTIAL_TYPE_PATTERN; - } - if (savedQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC - && mStorage.hasPassword(userId)) { - return pinOrPasswordQualityToCredentialType(savedQuality); - } return CREDENTIAL_TYPE_NONE; } @@ -1742,33 +1717,15 @@ public class LockSettingsService extends ILockSettings.Stub { LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { Objects.requireNonNull(credential); Objects.requireNonNull(savedCredential); + if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId); synchronized (mSpManager) { - if (isSyntheticPasswordBasedCredentialLocked(userId)) { - return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId, - isLockTiedToParent); - } - } - - if (credential.isNone()) { - clearUserKeyProtection(userId, null); - gateKeeperClearSecureUserId(userId); - mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); - // Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path, - // since it forms part of the state that determines the credential type - // @see getCredentialTypeInternal - setKeyguardStoredQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId); - setKeystorePassword(null, userId); - fixateNewestUserKeyAuth(userId); - synchronizeUnifiedWorkChallengeForProfiles(userId, null); - setUserPasswordMetrics(LockscreenCredential.createNone(), userId); - sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent); - return true; - } - - CredentialHash currentHandle = mStorage.readCredentialHash(userId); - if (isProfileWithUnifiedLock(userId)) { - // get credential from keystore when managed/clone profile has unified lock - if (savedCredential.isNone()) { + if (!isSyntheticPasswordBasedCredentialLocked(userId)) { + if (!savedCredential.isNone()) { + throw new IllegalStateException("Saved credential given, but user has no SP"); + } + initializeSyntheticPasswordLocked(savedCredential, userId); + } else if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) { + // get credential from keystore when profile has unified lock try { //TODO: remove as part of b/80170828 savedCredential = getDecryptedPasswordForTiedProfile(userId); @@ -1781,19 +1738,31 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.e(TAG, "Failed to decrypt child profile key", e); } } - } else { - if (currentHandle.hash == null) { - if (!savedCredential.isNone()) { - Slog.w(TAG, "Saved credential provided, but none stored"); + final long origHandle = getSyntheticPasswordHandleLocked(userId); + AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( + getGateKeeperService(), origHandle, savedCredential, userId, null); + VerifyCredentialResponse response = authResult.gkResponse; + AuthenticationToken auth = authResult.authToken; + + if (auth == null) { + if (response == null + || response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) { + Slog.w(TAG, "Failed to enroll: incorrect credential."); + return false; } - savedCredential.close(); - savedCredential = LockscreenCredential.createNone(); + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + Slog.w(TAG, "Failed to enroll: rate limit exceeded."); + return false; + } + // Should not be reachable, but just in case. + throw new IllegalStateException("password change failed"); } - } - synchronized (mSpManager) { - initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId); - return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId, - isLockTiedToParent); + + onAuthTokenKnownForUser(userId, auth); + setLockCredentialWithAuthTokenLocked(credential, auth, userId); + mSpManager.destroyPasswordBasedSyntheticPassword(origHandle, userId); + sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent); + return true; } } @@ -1912,10 +1881,6 @@ public class LockSettingsService extends ILockSettings.Stub { return getUserManagerFromCache(userId).isCredentialSharableWithParent(); } - private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) { - return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse); - } - private void setCredentialRequiredToDecrypt(boolean required) { if (isDeviceEncryptionEnabled()) { Settings.Global.putInt(mContext.getContentResolver(), @@ -2089,21 +2054,6 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private static byte[] secretFromCredential(LockscreenCredential credential) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-512"); - // Personalize the hash - byte[] personalization = "Android FBE credential hash".getBytes(); - // Pad it to the block size of the hash function - personalization = Arrays.copyOf(personalization, 128); - digest.update(personalization); - digest.update(credential.getCredential()); - return digest.digest(); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("NoSuchAlgorithmException for SHA-512"); - } - } - private boolean isUserKeyUnlocked(int userId) { try { return mStorageManager.isUserKeyUnlocked(userId); @@ -2262,9 +2212,8 @@ public class LockSettingsService extends ILockSettings.Stub { } } - /* - * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero - * format. + /** + * Verify user credential and unlock the user. * @param credential User's lockscreen credential * @param userId User to verify the credential for * @param progressCallback Receive progress callbacks @@ -2282,36 +2231,59 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.e(TAG, "FRP credential can only be verified prior to provisioning."); return VerifyCredentialResponse.ERROR; } + Slog.d(TAG, "doVerifyCredential: user=" + userId); - VerifyCredentialResponse response = spBasedDoVerifyCredential(credential, userId, - progressCallback, flags); + final AuthenticationResult authResult; + VerifyCredentialResponse response; - // The user employs synthetic password based credential. - if (response != null) { - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - sendCredentialsOnUnlockIfRequired(credential, userId); + synchronized (mSpManager) { + if (!isSyntheticPasswordBasedCredentialLocked(userId)) { + Slog.wtf(TAG, "Unexpected credential type, should be SP based."); + return VerifyCredentialResponse.ERROR; + } + if (userId == USER_FRP) { + return mSpManager.verifyFrpCredential(getGateKeeperService(), credential, + progressCallback); + } + + long handle = getSyntheticPasswordHandleLocked(userId); + authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( + getGateKeeperService(), handle, credential, userId, progressCallback); + response = authResult.gkResponse; + + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + // credential has matched + mBiometricDeferredQueue.addPendingLockoutResetForUser(userId, + authResult.authToken.deriveGkPassword()); + + // perform verifyChallenge with synthetic password which generates the real GK auth + // token and response for the current user + response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken, + 0L /* challenge */, userId); + if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { + // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't + // match the recorded GK password handle. + Slog.wtf(TAG, "verifyChallenge with SP failed."); + return VerifyCredentialResponse.ERROR; + } } - return response; } - - if (userId == USER_FRP) { - Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based."); - return VerifyCredentialResponse.ERROR; - } - - final CredentialHash storedHash = mStorage.readCredentialHash(userId); - if (!credential.checkAgainstStoredType(storedHash.type)) { - Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??" - + " stored: " + storedHash.type + " passed in: " + credential.getType()); - return VerifyCredentialResponse.ERROR; - } - - response = verifyCredential(userId, storedHash, credential, progressCallback); - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); + onCredentialVerified(authResult.authToken, + PasswordMetrics.computeForCredential(credential), userId); + if ((flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0) { + final long gkHandle = storeGatekeeperPasswordTemporarily( + authResult.authToken.deriveGkPassword()); + response = new VerifyCredentialResponse.Builder() + .setGatekeeperPasswordHandle(gkHandle) + .build(); + } + sendCredentialsOnUnlockIfRequired(credential, userId); + } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + if (response.getTimeout() > 0) { + requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId); + } } - return response; } @@ -2350,83 +2322,6 @@ public class LockSettingsService extends ILockSettings.Stub { } } - /** - * Lowest-level credential verification routine that talks to GateKeeper. If verification - * passes, unlock the corresponding user and keystore. Also handles the migration from legacy - * hash to GK. - */ - private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, - LockscreenCredential credential, ICheckCredentialProgressCallback progressCallback) { - if ((storedHash == null || storedHash.hash.length == 0) && credential.isNone()) { - // don't need to pass empty credentials to GateKeeper - return VerifyCredentialResponse.OK; - } - - if (storedHash == null || storedHash.hash.length == 0 || credential.isNone()) { - return VerifyCredentialResponse.ERROR; - } - - // We're potentially going to be doing a bunch of disk I/O below as part - // of unlocking the user, so yell if calling from the main thread. - StrictMode.noteDiskRead(); - - GateKeeperResponse gateKeeperResponse; - try { - gateKeeperResponse = getGateKeeperService().verifyChallenge( - userId, 0L /* challenge */, storedHash.hash, credential.getCredential()); - } catch (RemoteException e) { - Slog.e(TAG, "gatekeeper verify failed", e); - gateKeeperResponse = GateKeeperResponse.ERROR; - } - VerifyCredentialResponse response = convertResponse(gateKeeperResponse); - boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); - - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - - // credential has matched - - if (progressCallback != null) { - try { - progressCallback.onCredentialVerified(); - } catch (RemoteException e) { - Slog.w(TAG, "progressCallback throws exception", e); - } - } - setUserPasswordMetrics(credential, userId); - unlockKeystore(credential.getCredential(), userId); - - Slog.i(TAG, "Unlocking user " + userId); - unlockUser(userId, secretFromCredential(credential)); - - if (isProfileWithSeparatedLock(userId)) { - setDeviceUnlockedForUser(userId); - } - if (shouldReEnroll) { - setLockCredentialInternal(credential, credential, - userId, /* isLockTiedToParent= */ false); - } else { - // Now that we've cleared of all required GK migration, let's do the final - // migration to synthetic password. - synchronized (mSpManager) { - if (shouldMigrateToSyntheticPasswordLocked(userId)) { - AuthenticationToken auth = initializeSyntheticPasswordLocked( - storedHash.hash, credential, userId); - activateEscrowTokens(auth, userId); - } - } - } - // Use credentials to create recoverable keystore snapshot. - sendCredentialsOnUnlockIfRequired(credential, userId); - - } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { - if (response.getTimeout() > 0) { - requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId); - } - } - - return response; - } - /** * Keep track of the given user's latest password metric. This should be called * when the user is authenticating or when a new password is being set. In comparison, @@ -2779,7 +2674,9 @@ public class LockSettingsService extends ILockSettings.Stub { * Precondition: vold and keystore unlocked. * * Create new synthetic password, set up synthetic password blob protected by the supplied - * user credential, and make the newly-created SP blob active. + * user credential, and make the newly-created SP blob active. This is called just once in the + * lifetime of the user: the first time that a user credential is set (!credential.isNone()), or + * when an escrow token is activated on an unsecured device (credential.isNone()). * * The invariant under a synthetic password is: * 1. If user credential exists, then both vold and keystore and protected with keys derived @@ -2793,47 +2690,21 @@ public class LockSettingsService extends ILockSettings.Stub { * protected by a default PIN. * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user * clears/re-creates their lockscreen PIN. - * - * - * Different cases of calling this method: - * 1. credentialHash != null - * This implies credential != null, a new SP blob will be provisioned, and existing SID - * migrated to associate with the new SP. - * This happens during a normal migration case when the user currently has password. - * - * 2. credentialhash == null and credential == null - * A new SP blob and will be created, while the user has no credentials. - * This can happens when we are activating an escrow token on a unsecured device, during - * which we want to create the SP structure with an empty user credential. - * This could also happen during an untrusted reset to clear password. - * - * 3. credentialhash == null and credential != null - * The user sets a new lockscreen password FOR THE FIRST TIME on a SP-enabled device. - * New credential and new SID will be created */ @GuardedBy("mSpManager") @VisibleForTesting - protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, - LockscreenCredential credential, int userId) { + AuthenticationToken initializeSyntheticPasswordLocked(LockscreenCredential credential, + int userId) { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); Preconditions.checkState( getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE, "Cannot reinitialize SP"); - final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid( - getGateKeeperService(), credentialHash, credential, userId); - if (auth == null) { - Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token"); - return null; - } + final AuthenticationToken auth = mSpManager.newSyntheticPassword(userId); long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(), credential, auth, userId); if (!credential.isNone()) { - if (credentialHash == null) { - // Since when initializing SP, we didn't provide an existing password handle - // for it to migrate SID, we need to create a new SID for the user. - mSpManager.newSidForUser(getGateKeeperService(), auth, userId); - } + mSpManager.newSidForUser(getGateKeeperService(), auth, userId); mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId); setUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); setKeystorePassword(auth.deriveKeyStorePassword(), userId); @@ -2878,73 +2749,6 @@ public class LockSettingsService extends ILockSettings.Stub { return handle != SyntheticPasswordManager.DEFAULT_HANDLE; } - @VisibleForTesting - protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { - return getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE; - } - - private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential, - int userId, ICheckCredentialProgressCallback progressCallback, - @LockPatternUtils.VerifyFlag int flags) { - final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); - - Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId - + " hasEnrolledBiometrics=" + hasEnrolledBiometrics); - - final AuthenticationResult authResult; - VerifyCredentialResponse response; - final boolean requestGkPw = (flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0; - - synchronized (mSpManager) { - if (!isSyntheticPasswordBasedCredentialLocked(userId)) { - return null; - } - if (userId == USER_FRP) { - return mSpManager.verifyFrpCredential(getGateKeeperService(), - userCredential, progressCallback); - } - - long handle = getSyntheticPasswordHandleLocked(userId); - authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( - getGateKeeperService(), handle, userCredential, userId, progressCallback); - response = authResult.gkResponse; - - // credential has matched - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - mBiometricDeferredQueue.addPendingLockoutResetForUser(userId, - authResult.authToken.deriveGkPassword()); - - // perform verifyChallenge with synthetic password which generates the real GK auth - // token and response for the current user - response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken, - 0L /* challenge */, userId); - if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { - // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't - // match the recorded GK password handle. - Slog.wtf(TAG, "verifyChallenge with SP failed."); - return VerifyCredentialResponse.ERROR; - } - } - } - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - onCredentialVerified(authResult.authToken, - PasswordMetrics.computeForCredential(userCredential), userId); - } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { - if (response.getTimeout() > 0) { - requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId); - } - } - - if (response.isMatched() && requestGkPw) { - final long handle = storeGatekeeperPasswordTemporarily( - authResult.authToken.deriveGkPassword()); - return new VerifyCredentialResponse.Builder().setGatekeeperPasswordHandle(handle) - .build(); - } else { - return response; - } - } - /** * Stores the gatekeeper password temporarily. * @param gatekeeperPassword unlocked upon successful Synthetic Password @@ -3148,56 +2952,6 @@ public class LockSettingsService extends ILockSettings.Stub { }; } - /** - * @param savedCredential if the user is a profile with unified challenge and - * savedCredential is empty, LSS will try to re-derive the profile password internally. - * TODO (b/80170828): Fix this so profile password is always passed in. - */ - @GuardedBy("mSpManager") - private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { - if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); - if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) { - // get credential from keystore when profile has unified lock - try { - //TODO: remove as part of b/80170828 - savedCredential = getDecryptedPasswordForTiedProfile(userId); - } catch (FileNotFoundException e) { - Slog.i(TAG, "Child profile key not found"); - } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException - | NoSuchAlgorithmException | NoSuchPaddingException - | InvalidAlgorithmParameterException | IllegalBlockSizeException - | BadPaddingException | CertificateException | IOException e) { - Slog.e(TAG, "Failed to decrypt child profile key", e); - } - } - long handle = getSyntheticPasswordHandleLocked(userId); - AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( - getGateKeeperService(), handle, savedCredential, userId, null); - VerifyCredentialResponse response = authResult.gkResponse; - AuthenticationToken auth = authResult.authToken; - - if (auth == null) { - if (response == null - || response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) { - Slog.w(TAG, "Failed to enroll: incorrect credential."); - return false; - } - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { - Slog.w(TAG, "Failed to enroll: rate limit exceeded."); - return false; - } - // Should not be reachable, but just in case. - throw new IllegalStateException("password change failed"); - } - - onAuthTokenKnownForUser(userId, auth); - setLockCredentialWithAuthTokenLocked(credential, auth, userId); - mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); - sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent); - return true; - } - /** * 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 @@ -3244,20 +2998,18 @@ public class LockSettingsService extends ILockSettings.Stub { // the token can then be activated immediately. AuthenticationToken auth = null; if (!isUserSecure(userId)) { - if (shouldMigrateToSyntheticPasswordLocked(userId)) { - auth = initializeSyntheticPasswordLocked( - /* credentialHash */ null, LockscreenCredential.createNone(), userId); - } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ { - long pwdHandle = getSyntheticPasswordHandleLocked(userId); + long handle = getSyntheticPasswordHandleLocked(userId); + if (handle == SyntheticPasswordManager.DEFAULT_HANDLE) { + auth = initializeSyntheticPasswordLocked(LockscreenCredential.createNone(), + userId); + } else { auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(), - pwdHandle, LockscreenCredential.createNone(), userId, null).authToken; + handle, LockscreenCredential.createNone(), userId, null).authToken; } } - if (isSyntheticPasswordBasedCredentialLocked(userId)) { - disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); - if (!mSpManager.hasEscrowData(userId)) { - throw new SecurityException("Escrow token is disabled on the current user"); - } + disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); + if (!mSpManager.hasEscrowData(userId)) { + throw new SecurityException("Escrow token is disabled on the current user"); } long handle = mSpManager.createTokenBasedSyntheticPassword(token, type, userId, callback); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index f9db5cf998bb4..9ddf1efbaef21 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -85,8 +85,6 @@ class LockSettingsStorage extends WatchableImpl { }; private static final String SYSTEM_DIRECTORY = "/system/"; - private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key"; - private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key"; private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key"; private static final String REBOOT_ESCROW_FILE = "reboot.escrow.key"; @@ -248,38 +246,6 @@ class LockSettingsStorage extends WatchableImpl { } cursor.close(); } - - // Populate cache by reading the password and pattern files. - readCredentialHash(userId); - } - - private CredentialHash readPasswordHashIfExists(int userId) { - byte[] stored = readFile(getLockPasswordFilename(userId)); - if (!ArrayUtils.isEmpty(stored)) { - return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN); - } - return null; - } - - private CredentialHash readPatternHashIfExists(int userId) { - byte[] stored = readFile(getLockPatternFilename(userId)); - if (!ArrayUtils.isEmpty(stored)) { - return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN); - } - return null; - } - - public CredentialHash readCredentialHash(int userId) { - CredentialHash passwordHash = readPasswordHashIfExists(userId); - if (passwordHash != null) { - return passwordHash; - } - - CredentialHash patternHash = readPatternHashIfExists(userId); - if (patternHash != null) { - return patternHash; - } - return CredentialHash.createEmptyHash(); } public void removeChildProfileLock(int userId) { @@ -336,14 +302,6 @@ class LockSettingsStorage extends WatchableImpl { deleteFile(getRebootEscrowServerBlob()); } - public boolean hasPassword(int userId) { - return hasFile(getLockPasswordFilename(userId)); - } - - public boolean hasPattern(int userId) { - return hasFile(getLockPatternFilename(userId)); - } - private boolean hasFile(String name) { byte[] contents = readFile(name); return contents != null && contents.length > 0; @@ -429,33 +387,6 @@ class LockSettingsStorage extends WatchableImpl { } } - public void writeCredentialHash(CredentialHash hash, int userId) { - byte[] patternHash = null; - byte[] passwordHash = null; - if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN - || hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD - || hash.type == LockPatternUtils.CREDENTIAL_TYPE_PIN) { - passwordHash = hash.hash; - } else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { - patternHash = hash.hash; - } else { - Preconditions.checkArgument(hash.type == LockPatternUtils.CREDENTIAL_TYPE_NONE, - "Unknown credential type"); - } - writeFile(getLockPasswordFilename(userId), passwordHash); - writeFile(getLockPatternFilename(userId), patternHash); - } - - @VisibleForTesting - String getLockPatternFilename(int userId) { - return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE); - } - - @VisibleForTesting - String getLockPasswordFilename(int userId) { - return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE); - } - @VisibleForTesting String getChildProfileLockFile(int userId) { return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE); @@ -567,12 +498,7 @@ class LockSettingsStorage extends WatchableImpl { if (parentInfo == null) { // This user owns its lock settings files - safe to delete them - synchronized (mFileWriteLock) { - deleteFilesAndRemoveCache( - getLockPasswordFilename(userId), - getLockPatternFilename(userId), - getRebootEscrowFile(userId)); - } + deleteFile(getRebootEscrowFile(userId)); } else { // Managed profile removeChildProfileLock(userId); @@ -594,17 +520,6 @@ class LockSettingsStorage extends WatchableImpl { dispatchChange(this); } - private void deleteFilesAndRemoveCache(String... names) { - for (String name : names) { - File file = new File(name); - if (file.exists()) { - file.delete(); - mCache.putFile(name, null); - dispatchChange(this); - } - } - } - public void setBoolean(String key, boolean value, int userId) { setString(key, value ? "1" : "0", userId); } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 3edbfe038ce6d..f5ee9068a623f 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -599,47 +599,19 @@ public class SyntheticPasswordManager { } /** - * Initializing a new Authentication token, possibly from an existing credential and hash. + * Initializes a new Authentication token for the given user. * - * The authentication token would bear a randomly-generated synthetic password. + * The authentication token will bear a randomly-generated synthetic password. * - * This method has the side effect of rebinding the SID of the given user to the - * newly-generated SP. - * - * 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.) - * - * 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, - * the supplied credential parameter is also ignored. + * Any existing SID for the user is cleared. * * Also saves the escrow information necessary to re-generate the synthetic password under * an escrow scheme. This information can be removed with {@link #destroyEscrowData} if * password escrow should be disabled completely on the given user. - * */ - public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper, - byte[] hash, LockscreenCredential credential, int userId) { + AuthenticationToken newSyntheticPassword(int userId) { + clearSidForUser(userId); AuthenticationToken result = AuthenticationToken.create(); - GateKeeperResponse response; - if (hash != null) { - try { - response = gatekeeper.enroll(userId, hash, credential.getCredential(), - result.deriveGkPassword()); - } catch (RemoteException e) { - throw new IllegalStateException("Failed to enroll credential duing SP init", e); - } - if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { - Slog.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId); - clearSidForUser(userId); - } else { - saveSyntheticPasswordHandle(response.getPayload(), userId); - } - } else { - clearSidForUser(userId); - } saveEscrowData(result, userId); return result; } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 1d10b8aa3f5a6..85db23c6b7171 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -135,11 +135,6 @@ public class LockSettingsServiceTestable extends LockSettingsService { return mUserManagerInternal; } - @Override - public boolean hasEnrolledBiometrics(int userId) { - return false; - } - @Override public int binderGetCallingUid() { return Process.SYSTEM_UID; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index e7f4d3dccae76..20cc42cd9c769 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -42,11 +42,8 @@ import android.service.gatekeeper.GateKeeperResponse; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.VerifyCredentialResponse; -import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle; -import com.android.server.locksettings.LockSettingsStorage.CredentialHash; import org.junit.Before; import org.junit.Test; @@ -96,17 +93,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { @Test public void testChangePasswordFailPrimaryUser() throws RemoteException { - final long sid = 1234; - initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid); + initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password")); assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"), PRIMARY_USER_ID)); - assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid); + assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password")); } @Test public void testClearPasswordPrimaryUser() throws RemoteException { - initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password")); assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), PRIMARY_USER_ID)); assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID)); @@ -264,10 +260,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials() throws Exception { mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null); - initializeStorageWithCredential( - MANAGED_PROFILE_USER_ID, - newPattern("12345"), - 1234); + initializeStorageWithCredential(MANAGED_PROFILE_USER_ID, newPattern("12345")); assertTrue(mService.setLockCredential( newPassword("newPassword"), @@ -300,8 +293,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { throws Exception { final LockscreenCredential oldCredential = newPassword("oldPassword"); final LockscreenCredential newCredential = newPassword("newPassword"); - initializeStorageWithCredential( - PRIMARY_USER_ID, oldCredential, 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, oldCredential); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertTrue(mService.setLockCredential( @@ -321,7 +313,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials() throws Exception { - initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword"), 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword")); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertTrue(mService.setLockCredential( @@ -337,10 +329,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { @Test public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException { - initializeStorageWithCredential( - PRIMARY_USER_ID, - newPattern("123654"), - 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, newPattern("123654")); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID); @@ -358,7 +347,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { throws Exception { final LockscreenCredential parentPassword = newPassword("parentPassword"); final LockscreenCredential profilePassword = newPassword("profilePassword"); - initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertTrue(mService.setLockCredential( @@ -377,7 +366,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { throws Exception { final LockscreenCredential parentPassword = newPassword("parentPassword"); final LockscreenCredential profilePassword = newPattern("12345"); - initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword); // Create and verify separate profile credentials. testCreateCredential(MANAGED_PROFILE_USER_ID, profilePassword); @@ -393,7 +382,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { @Test public void testVerifyCredential_forPrimaryUser_sendsCredentials() throws Exception { final LockscreenCredential password = newPassword("password"); - initializeStorageWithCredential(PRIMARY_USER_ID, password, 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, password); reset(mRecoverableKeyStoreManager); mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */); @@ -424,7 +413,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void verifyCredential_forPrimaryUserWithUnifiedChallengeProfile_sendsCredentialsForBoth() throws Exception { final LockscreenCredential pattern = newPattern("12345"); - initializeStorageWithCredential(PRIMARY_USER_ID, pattern, 1234); + initializeStorageWithCredential(PRIMARY_USER_ID, pattern); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); reset(mRecoverableKeyStoreManager); @@ -464,7 +453,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { private void testCreateCredential(int userId, LockscreenCredential credential) throws RemoteException { assertTrue(mService.setLockCredential(credential, nonePassword(), userId)); - assertVerifyCredentials(userId, credential, -1); + assertVerifyCredentials(userId, credential); } private void testCreateCredentialFailsWithoutLockScreen( @@ -483,19 +472,17 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { private void testChangeCredentials(int userId, LockscreenCredential newCredential, LockscreenCredential oldCredential) throws RemoteException { - final long sid = 1234; - initializeStorageWithCredential(userId, oldCredential, sid); + initializeStorageWithCredential(userId, oldCredential); assertTrue(mService.setLockCredential(newCredential, oldCredential, userId)); - assertVerifyCredentials(userId, newCredential, sid); + assertVerifyCredentials(userId, newCredential); } - private void assertVerifyCredentials(int userId, LockscreenCredential credential, long sid) + private void assertVerifyCredentials(int userId, LockscreenCredential credential) throws RemoteException{ VerifyCredentialResponse response = mService.verifyCredential(credential, userId, 0 /* flags */); assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode()); - if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId)); if (credential.isPassword()) { assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId)); } else if (credential.isPin()) { @@ -517,19 +504,11 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { badCredential, userId, 0 /* flags */).getResponseCode()); } - private void initializeStorageWithCredential(int userId, LockscreenCredential credential, - long sid) throws RemoteException { - byte[] oldHash = new VerifyHandle(credential.getCredential(), sid).toBytes(); - if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) { - mService.initializeSyntheticPasswordLocked(oldHash, credential, userId); - } else { - if (credential.isPassword() || credential.isPin()) { - mStorage.writeCredentialHash(CredentialHash.create(oldHash, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId); - } else { - mStorage.writeCredentialHash(CredentialHash.create(oldHash, - LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId); - } - } + @SuppressWarnings("GuardedBy") // for initializeSyntheticPasswordLocked + private void initializeStorageWithCredential(int userId, LockscreenCredential credential) + throws RemoteException { + assertEquals(0, mGateKeeperService.getSecureUserId(userId)); + mService.initializeSyntheticPasswordLocked(credential, userId); + assertNotEquals(0, mGateKeeperService.getSecureUserId(userId)); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java index f2bb1d662ed9e..c30af4cae59dc 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java @@ -63,18 +63,6 @@ public class LockSettingsStorageTestable extends LockSettingsStorage { }).when(mPersistentDataBlockManager).getFrpCredentialHandle(); } - @Override - String getLockPatternFilename(int userId) { - return makeDirs(mStorageDir, - super.getLockPatternFilename(userId)).getAbsolutePath(); - } - - @Override - String getLockPasswordFilename(int userId) { - return makeDirs(mStorageDir, - super.getLockPasswordFilename(userId)).getAbsolutePath(); - } - @Override String getChildProfileLockFile(int userId) { return makeDirs(mStorageDir, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java index 5f38a3509a20c..609c05c040c29 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java @@ -48,9 +48,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.widget.LockPatternUtils; import com.android.server.PersistentDataBlockManagerInternal; -import com.android.server.locksettings.LockSettingsStorage.CredentialHash; import com.android.server.locksettings.LockSettingsStorage.PersistentData; import org.junit.After; @@ -72,10 +70,7 @@ import java.util.concurrent.CountDownLatch; @RunWith(AndroidJUnit4.class) public class LockSettingsStorageTests { private static final int SOME_USER_ID = 1034; - private final byte[] PASSWORD_0 = "thepassword0".getBytes(); - private final byte[] PASSWORD_1 = "password1".getBytes(); - private final byte[] PATTERN_0 = "123654".getBytes(); - private final byte[] PATTERN_1 = "147852369".getBytes(); + private final byte[] PASSWORD = "thepassword".getBytes(); public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 33}; @@ -216,161 +211,64 @@ public class LockSettingsStorageTests { @Test public void testRemoveUser() { mStorage.writeKeyValue("key", "value", 0); - writePasswordBytes(PASSWORD_0, 0); - writePatternBytes(PATTERN_0, 0); - mStorage.writeKeyValue("key", "value", 1); - writePasswordBytes(PASSWORD_1, 1); - writePatternBytes(PATTERN_1, 1); mStorage.removeUser(0); assertEquals("value", mStorage.readKeyValue("key", "default", 1)); assertEquals("default", mStorage.readKeyValue("key", "default", 0)); - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type); - assertPatternBytes(PATTERN_1, 1); - } - - @Test - public void testCredential_Default() { - assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE); - } - - @Test - public void testPassword_Write() { - writePasswordBytes(PASSWORD_0, 0); - - assertPasswordBytes(PASSWORD_0, 0); - mStorage.clearCache(); - assertPasswordBytes(PASSWORD_0, 0); - } - - @Test - public void testPassword_WriteProfileWritesParent() { - writePasswordBytes(PASSWORD_0, 1); - writePasswordBytes(PASSWORD_1, 2); - - assertPasswordBytes(PASSWORD_0, 1); - assertPasswordBytes(PASSWORD_1, 2); - mStorage.clearCache(); - assertPasswordBytes(PASSWORD_0, 1); - assertPasswordBytes(PASSWORD_1, 2); - } - - @Test - public void testLockType_WriteProfileWritesParent() { - writePasswordBytes(PASSWORD_0, 10); - writePatternBytes(PATTERN_0, 20); - - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN, - mStorage.readCredentialHash(10).type); - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - mStorage.readCredentialHash(20).type); - mStorage.clearCache(); - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN, - mStorage.readCredentialHash(10).type); - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - mStorage.readCredentialHash(20).type); - } - - @Test - public void testPassword_WriteParentWritesProfile() { - writePasswordBytes(PASSWORD_0, 2); - writePasswordBytes(PASSWORD_1, 1); - - assertPasswordBytes(PASSWORD_1, 1); - assertPasswordBytes(PASSWORD_0, 2); - mStorage.clearCache(); - assertPasswordBytes(PASSWORD_1, 1); - assertPasswordBytes(PASSWORD_0, 2); } @Test public void testProfileLock_ReadWriteChildProfileLock() { assertFalse(mStorage.hasChildProfileLock(20)); - mStorage.writeChildProfileLock(20, PASSWORD_0); - assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20)); + mStorage.writeChildProfileLock(20, PASSWORD); + assertArrayEquals(PASSWORD, mStorage.readChildProfileLock(20)); assertTrue(mStorage.hasChildProfileLock(20)); mStorage.clearCache(); - assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20)); + assertArrayEquals(PASSWORD, mStorage.readChildProfileLock(20)); assertTrue(mStorage.hasChildProfileLock(20)); } - @Test - public void testPattern_Write() { - writePatternBytes(PATTERN_0, 0); - - assertPatternBytes(PATTERN_0, 0); - mStorage.clearCache(); - assertPatternBytes(PATTERN_0, 0); - } - - @Test - public void testPattern_WriteProfileWritesParent() { - writePatternBytes(PATTERN_0, 1); - writePatternBytes(PATTERN_1, 2); - - assertPatternBytes(PATTERN_0, 1); - assertPatternBytes(PATTERN_1, 2); - mStorage.clearCache(); - assertPatternBytes(PATTERN_0, 1); - assertPatternBytes(PATTERN_1, 2); - } - - @Test - public void testPattern_WriteParentWritesProfile() { - writePatternBytes(PATTERN_1, 2); - writePatternBytes(PATTERN_0, 1); - - assertPatternBytes(PATTERN_0, 1); - assertPatternBytes(PATTERN_1, 2); - mStorage.clearCache(); - assertPatternBytes(PATTERN_0, 1); - assertPatternBytes(PATTERN_1, 2); - } - @Test public void testPrefetch() { mStorage.writeKeyValue("key", "toBeFetched", 0); - writePatternBytes(PATTERN_0, 0); mStorage.clearCache(); mStorage.prefetchUser(0); assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0)); - assertPatternBytes(PATTERN_0, 0); } @Test public void testFileLocation_Owner() { LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext()); - assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0)); - assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0)); + assertEquals("/data/system/gatekeeper.profile.key", storage.getChildProfileLockFile(0)); } @Test public void testFileLocation_SecondaryUser() { LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext()); - assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1)); - assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1)); + assertEquals("/data/system/users/1/gatekeeper.profile.key", + storage.getChildProfileLockFile(1)); } @Test public void testFileLocation_ProfileToSecondary() { LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext()); - assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2)); - assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2)); + assertEquals("/data/system/users/2/gatekeeper.profile.key", + storage.getChildProfileLockFile(2)); } @Test public void testFileLocation_ProfileToOwner() { LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext()); - assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3)); - assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3)); + assertEquals("/data/system/users/3/gatekeeper.profile.key", + storage.getChildProfileLockFile(3)); } @Test @@ -483,28 +381,6 @@ public class LockSettingsStorageTests { } } - private void writePasswordBytes(byte[] password, int userId) { - mStorage.writeCredentialHash(CredentialHash.create( - password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId); - } - - private void writePatternBytes(byte[] pattern, int userId) { - mStorage.writeCredentialHash(CredentialHash.create( - pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId); - } - - private void assertPasswordBytes(byte[] password, int userId) { - CredentialHash cred = mStorage.readCredentialHash(userId); - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN, cred.type); - assertArrayEquals(password, cred.hash); - } - - private void assertPatternBytes(byte[] pattern, int userId) { - CredentialHash cred = mStorage.readCredentialHash(userId); - assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type); - assertArrayEquals(pattern, cred.hash); - } - /** * Suppresses reporting of the WTF to system_server, so we don't pollute the dropbox with * intentionally caused WTFs. 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 09aa345bef221..6d1df2c2f2bf8 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -19,7 +19,6 @@ package com.android.server.locksettings; 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_PASSWORD_OR_PIN; -import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static org.junit.Assert.assertEquals; @@ -38,7 +37,6 @@ import static org.mockito.Mockito.when; import android.app.admin.PasswordMetrics; import android.app.PropertyInvalidatedCache; import android.os.RemoteException; -import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -82,8 +80,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { final LockscreenCredential badPassword = newPassword("bad-password"); MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager, mPasswordSlotManager); - AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null, - null, USER_ID); + AuthenticationToken authToken = manager.newSyntheticPassword(USER_ID); long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, password, authToken, USER_ID); @@ -97,32 +94,23 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertNull(result.authToken); } - private void disableSyntheticPassword() throws RemoteException { - mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM); - } - - private void enableSyntheticPassword() throws RemoteException { - mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); - } - private boolean hasSyntheticPassword(int userId) throws RemoteException { return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0; } - protected void initializeCredentialUnderSP(LockscreenCredential password, int userId) + private void initializeCredential(LockscreenCredential password, int userId) throws RemoteException { - enableSyntheticPassword(); assertTrue(mService.setLockCredential(password, nonePassword(), userId)); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId)); assertTrue(mService.isSyntheticPasswordBasedCredential(userId)); } @Test - public void testSyntheticPasswordChangeCredential() throws RemoteException { + public void testChangeCredential() throws RemoteException { final LockscreenCredential password = newPassword("password"); final LockscreenCredential newPassword = newPassword("newpassword"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); mService.setLockCredential(newPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( @@ -131,11 +119,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testSyntheticPasswordVerifyCredential() throws RemoteException { + public void testVerifyCredential() throws RemoteException { LockscreenCredential password = newPassword("password"); LockscreenCredential badPassword = newPassword("badpassword"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); @@ -144,11 +132,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testSyntheticPasswordClearCredential() throws RemoteException { + public void testClearCredential() throws RemoteException { LockscreenCredential password = newPassword("password"); LockscreenCredential badPassword = newPassword("newpassword"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); @@ -162,11 +150,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException { + public void testChangeCredentialKeepsAuthSecret() throws RemoteException { LockscreenCredential password = newPassword("password"); LockscreenCredential badPassword = newPassword("new"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); mService.setLockCredential(badPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( badPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); @@ -178,11 +166,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException { + public void testVerifyPassesPrimaryUserAuthSecret() throws RemoteException { LockscreenCredential password = newPassword("password"); - LockscreenCredential newPassword = newPassword("new"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); reset(mAuthSecretService); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); @@ -193,7 +180,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException { LockscreenCredential password = newPassword("password"); - initializeCredentialUnderSP(password, SECONDARY_USER_ID); + initializeCredential(password, SECONDARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( password, SECONDARY_USER_ID, 0 /* flags */).getResponseCode()); verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); @@ -207,9 +194,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException { - LockscreenCredential password = newPassword("passwordForASyntheticPassword"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + public void testCredentialDoesNotPassAuthSecret() throws RemoteException { + LockscreenCredential password = newPassword("password"); + initializeCredential(password, PRIMARY_USER_ID); reset(mAuthSecretService); mService.onUnlockUser(PRIMARY_USER_ID); @@ -219,8 +206,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException { - LockscreenCredential password = newPassword("getASyntheticPassword"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + LockscreenCredential password = newPassword("password"); + initializeCredential(password, PRIMARY_USER_ID); mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); reset(mAuthSecretService); @@ -234,7 +221,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); LockscreenCredential pattern = newPattern("123654"); byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); // Disregard any reportPasswordChanged() invocations as part of credential setup. flushHandlerTasks(); reset(mDevicePolicyManager); @@ -269,7 +256,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); LockscreenCredential pattern = newPattern("123654"); byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); @@ -295,7 +282,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential pattern = newPattern("123654"); LockscreenCredential newPassword = newPassword("password"); byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); @@ -318,7 +305,6 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration() throws RemoteException { final byte[] token = "some-high-entropy-secure-token".getBytes(); - enableSyntheticPassword(); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); @@ -331,7 +317,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { final byte[] token = "some-high-entropy-secure-token".getBytes(); // By first setting a password and then clearing it, we enter the state where SP is // initialized but the user currently has no password - initializeCredentialUnderSP(newPassword("password"), PRIMARY_USER_ID); + initializeCredential(newPassword("password"), PRIMARY_USER_ID); assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), PRIMARY_USER_ID)); assertTrue(mService.isSyntheticPasswordBasedCredential(PRIMARY_USER_ID)); @@ -343,19 +329,15 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @Test - public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration() - throws RemoteException { + public void testEscrowTokenActivatedLaterWithUserPassword() throws RemoteException { byte[] token = "some-high-entropy-secure-token".getBytes(); LockscreenCredential password = newPassword("password"); - // Set up pre-SP user password - disableSyntheticPassword(); mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID); - enableSyntheticPassword(); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); // Token not activated immediately since user password exists assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - // Activate token (password gets migrated to SP at the same time) + // Activate token assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); // Verify token is activated @@ -383,7 +365,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); LockscreenCredential pattern = newPattern("123654"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); long handle0 = mLocalService.addEscrowToken(token0, PRIMARY_USER_ID, null); long handle1 = mLocalService.addEscrowToken(token1, PRIMARY_USER_ID, null); @@ -412,7 +394,6 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { byte[] token = "some-high-entropy-secure-token".getBytes(); mService.mHasSecureLockScreen = false; - enableSyntheticPassword(); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); @@ -515,7 +496,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("testGsiDisablesAuthSecret-password"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); @@ -525,7 +506,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testUnlockUserWithToken() throws Exception { LockscreenCredential password = newPassword("password"); byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); // Disregard any reportPasswordChanged() invocations as part of credential setup. flushHandlerTasks(); reset(mDevicePolicyManager); @@ -546,7 +527,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testPasswordChange_NoOrphanedFilesLeft() throws Exception { LockscreenCredential password = newPassword("password"); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredential(password, PRIMARY_USER_ID); assertTrue(mService.setLockCredential(password, password, PRIMARY_USER_ID)); assertNoOrphanedFilesLeft(PRIMARY_USER_ID); }