Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 801dfc47 authored by Irina Dumitrescu's avatar Irina Dumitrescu Committed by Android (Google) Code Review
Browse files

Merge "Change existing LockPatternUtil APIs to fail untrusted password updates."

parents 971f1fdf c90674dc
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -1680,7 +1680,6 @@ Lcom/android/internal/widget/LockPatternUtils;->patternToHash(Ljava/util/List;)[
Lcom/android/internal/widget/LockPatternUtils;->patternToString(Ljava/util/List;)Ljava/lang/String;
Lcom/android/internal/widget/LockPatternUtils;->reportFailedPasswordAttempt(I)V
Lcom/android/internal/widget/LockPatternUtils;->reportSuccessfulPasswordAttempt(I)V
Lcom/android/internal/widget/LockPatternUtils;->saveLockPassword(Ljava/lang/String;Ljava/lang/String;II)V
Lcom/android/internal/widget/LockPatternUtils;->setLockoutAttemptDeadline(II)J
Lcom/android/internal/widget/LockPatternUtils;->setLong(Ljava/lang/String;JI)V
Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfo(Ljava/lang/String;I)V
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ interface ILockSettings {
    long getLong(in String key, in long defaultValue, in int userId);
    @UnsupportedAppUsage
    String getString(in String key, in String defaultValue, in int userId);
    void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId);
    void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange);
    void resetKeyStore(int userId);
    VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
            in ICheckCredentialProgressCallback progressCallback);
+62 −16
Original line number Diff line number Diff line
@@ -669,17 +669,25 @@ public class LockPatternUtils {
    /**
     * Clear any lock pattern or password.
     */
    public void clearLock(byte[] savedCredential, int userHandle) {
    public boolean clearLock(byte[] savedCredential, int userHandle) {
        return clearLock(savedCredential, userHandle, false);
    }

    /**
     * Clear any lock pattern or password, with the option to ignore incorrect existing credential.
     */
    public boolean clearLock(byte[] savedCredential, int userHandle, boolean allowUntrustedChange) {
        final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
        setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);

        try{
            getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
                    savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
                    savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle,
                    allowUntrustedChange);
        } catch (Exception e) {
            Log.e(TAG, "Failed to clear lock", e);
            setKeyguardStoredPasswordQuality(currentQuality, userHandle);
            return;
            return false;
        }

        if (userHandle == UserHandle.USER_SYSTEM) {
@@ -689,6 +697,7 @@ public class LockPatternUtils {
        }

        onAfterChangingPassword(userHandle);
        return true;
    }

    /**
@@ -726,19 +735,28 @@ public class LockPatternUtils {
    /**
     * Save a lock pattern.
     * @param pattern The new pattern to save.
     * @param savedPattern The previously saved pattern, converted to byte[] format
     * @param userId the user whose pattern is to be saved.
     *
     * @return whether this was successful or not.
     */
    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
        this.saveLockPattern(pattern, null, userId);
    public boolean saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
            int userId) {
        return saveLockPattern(pattern, savedPattern, userId, false);
    }

    /**
     * Save a lock pattern.
     * @param pattern The new pattern to save.
     * @param savedPattern The previously saved pattern, converted to byte[] format
     * @param userId the user whose pattern is to be saved.
     * @param allowUntrustedChange whether we want to allow saving a new password if the existing
     * password being provided is incorrect.
     *
     * @return whether this was successful or not.
     */
    public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
            int userId) {
    public boolean saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
            int userId, boolean allowUntrustedChange) {
        if (!hasSecureLockScreen()) {
            throw new UnsupportedOperationException(
                    "This operation requires the lock screen feature.");
@@ -753,11 +771,11 @@ public class LockPatternUtils {
        setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
        try {
            getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
                    PASSWORD_QUALITY_SOMETHING, userId);
                    PASSWORD_QUALITY_SOMETHING, userId, allowUntrustedChange);
        } catch (Exception e) {
            Log.e(TAG, "Couldn't save lock pattern", e);
            setKeyguardStoredPasswordQuality(currentQuality, userId);
            return;
            return false;
        }
        // Update the device encryption password.
        if (userId == UserHandle.USER_SYSTEM
@@ -771,6 +789,7 @@ public class LockPatternUtils {

        reportPatternWasChosen(userId);
        onAfterChangingPassword(userId);
        return true;
    }

    private void updateCryptoUserInfo(int userId) {
@@ -873,17 +892,20 @@ public class LockPatternUtils {
     * password.
     * @param password The password to save
     * @param savedPassword The previously saved lock password, or null if none
     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
     * android.content.ComponentName)}
     * @param userHandle The userId of the user to change the password for
     *
     * @return whether this was successful or not.
     *
     * @deprecated Pass password as a byte array
     */
    @Deprecated
    public void saveLockPassword(String password, String savedPassword, int requestedQuality,
    public boolean saveLockPassword(String password, String savedPassword, int requestedQuality,
            int userHandle) {
        byte[] passwordBytes = password != null ? password.getBytes() : null;
        byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
        saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
        return saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
    }

    /**
@@ -895,9 +917,32 @@ public class LockPatternUtils {
     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
     * android.content.ComponentName)}
     * @param userHandle The userId of the user to change the password for
     *
     * @return whether this was successful or not.
     */
    public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
    public boolean saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
            int userHandle) {
        return saveLockPassword(password, savedPassword, requestedQuality,
                userHandle, false);
    }

    /**
     * Save a lock password.  Does not ensure that the password is as good
     * as the requested mode, but will adjust the mode to be as good as the
     * password.
     * @param password The password to save
     * @param savedPassword The previously saved lock password, or null if none
     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
     * android.content.ComponentName)}
     * @param userHandle The userId of the user to change the password for
     * @param allowUntrustedChange whether we want to allow saving a new password if the existing
     * password being provided is incorrect.
     *
     * @return whether this method saved the new password successfully or not. This flow will fail
     * and return false if the given credential is wrong and allowUntrustedChange is false.
     */
    public boolean saveLockPassword(byte[] password, byte[] savedPassword,
            int requestedQuality, int userHandle, boolean allowUntrustedChange) {
        if (!hasSecureLockScreen()) {
            throw new UnsupportedOperationException(
                    "This operation requires the lock screen feature.");
@@ -919,16 +964,17 @@ public class LockPatternUtils {
        setKeyguardStoredPasswordQuality(newKeyguardQuality, userHandle);
        try {
            getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
                    requestedQuality, userHandle);
                    requestedQuality, userHandle, allowUntrustedChange);
        } catch (Exception e) {
            Log.e(TAG, "Unable to save lock password", e);
            setKeyguardStoredPasswordQuality(currentQuality, userHandle);
            return;
            return false;
        }

        updateEncryptionPasswordIfNeeded(password, passwordQuality, userHandle);
        updatePasswordHistory(password, userHandle);
        onAfterChangingPassword(userHandle);
        return true;
    }

    /**
+33 −24
Original line number Diff line number Diff line
@@ -323,8 +323,8 @@ public class LockSettingsService extends ILockSettings.Stub {
            }
            Arrays.fill(newPasswordChars, '\u0000');
            final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
            setLockCredentialInternal(newPassword, CREDENTIAL_TYPE_PASSWORD,
                    managedUserPassword, quality, managedUserId);
            setLockCredentialInternal(newPassword, CREDENTIAL_TYPE_PASSWORD, managedUserPassword,
                    quality, managedUserId, false);
            // We store a private credential for the managed user that's unlocked by the primary
            // account holder's credential. As such, the user will never be prompted to enter this
            // password directly, so we always store a password.
@@ -1302,12 +1302,14 @@ public class LockSettingsService extends ILockSettings.Stub {
                    if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
                        setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE,
                                profilePasswordMap.get(managedUserId),
                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
                                false);
                    } else {
                        Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
                        // Supplying null here would lead to untrusted credential change
                        setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE, null,
                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
                                true);
                    }
                    mStorage.removeChildProfileLock(managedUserId);
                    removeKeystoreProfileKey(managedUserId);
@@ -1330,8 +1332,8 @@ public class LockSettingsService extends ILockSettings.Stub {
    // should call setLockCredentialInternal.
    @Override
    public void setLockCredential(byte[] credential, int type,
            byte[] savedCredential, int requestedQuality, int userId)
            throws RemoteException {
            byte[] savedCredential, int requestedQuality, int userId,
            boolean allowUntrustedChange) throws RemoteException {

        if (!mLockPatternUtils.hasSecureLockScreen()) {
            throw new UnsupportedOperationException(
@@ -1339,7 +1341,8 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
        checkWritePermission(userId);
        synchronized (mSeparateChallengeLock) {
            setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
            setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId,
                    allowUntrustedChange);
            setSeparateProfileChallengeEnabledLocked(userId, true, null);
            notifyPasswordChanged(userId);
        }
@@ -1347,7 +1350,8 @@ public class LockSettingsService extends ILockSettings.Stub {
    }

    private void setLockCredentialInternal(byte[] credential, @CredentialType int credentialType,
            byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
            byte[] savedCredential, int requestedQuality, int userId,
            boolean allowUntrustedChange) throws RemoteException {
        // Normalize savedCredential and credential such that empty string is always represented
        // as null.
        if (savedCredential == null || savedCredential.length == 0) {
@@ -1359,7 +1363,7 @@ public class LockSettingsService extends ILockSettings.Stub {
        synchronized (mSpManager) {
            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
                        requestedQuality, userId);
                        requestedQuality, userId, allowUntrustedChange);
                return;
            }
        }
@@ -1410,7 +1414,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
                        currentHandle.type, requestedQuality, userId);
                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
                        requestedQuality, userId);
                        requestedQuality, userId, allowUntrustedChange);
                return;
            }
        }
@@ -1705,7 +1709,7 @@ public class LockSettingsService extends ILockSettings.Stub {
            mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
            if (shouldReEnrollBaseZero) {
                setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false);
            }
        }

@@ -1796,7 +1800,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                        storedHash.type == CREDENTIAL_TYPE_PATTERN
                                ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
                                : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                                /* TODO(roosa): keep the same password quality */, userId);
                                /* TODO(roosa): keep the same password quality */, userId, false);
                if (!hasChallenge) {
                    notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
                    // Use credentials to create recoverable keystore snapshot.
@@ -1841,7 +1845,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                    /* TODO(roosa): keep the same password quality */;
            if (shouldReEnroll) {
                setLockCredentialInternal(credential, storedHash.type, credential,
                        reEnrollQuality, userId);
                        reEnrollQuality, userId, false);
            } else {
                // Now that we've cleared of all required GK migration, let's do the final
                // migration to synthetic password.
@@ -2544,7 +2548,8 @@ public class LockSettingsService extends ILockSettings.Stub {

    @GuardedBy("mSpManager")
    private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
            byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
            byte[] savedCredential, int requestedQuality, int userId,
            boolean allowUntrustedChange) throws RemoteException {
        if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
        if (isManagedProfileWithUnifiedLock(userId)) {
            // get credential from keystore when managed profile has unified lock
@@ -2565,27 +2570,31 @@ public class LockSettingsService extends ILockSettings.Stub {
        VerifyCredentialResponse response = authResult.gkResponse;
        AuthenticationToken auth = authResult.authToken;

        // If existing credential is provided, then it must match.
        // If existing credential is provided, the existing credential must match.
        if (savedCredential != null && auth == null) {
            throw new RemoteException("Failed to enroll " +
                    (credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
            throw new IllegalStateException("Failed to enroll "
                    + (credentialType == CREDENTIAL_TYPE_PASSWORD
                    ? "password" : "pattern"));
        }

        boolean untrustedReset = false;
        if (auth != null) {
            onAuthTokenKnownForUser(userId, auth);
        } else if (response != null
                && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
        } else if (response == null) {
            throw new IllegalStateException("Password change failed.");
        } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
            // We are performing an untrusted credential change, by DevicePolicyManager or other
            // internal callers that don't provide the existing credential
            Slog.w(TAG, "Untrusted credential change invoked");
            // Try to get a cached auth token, so we can keep SP unchanged.
            auth = mSpCache.get(userId);
            if (!allowUntrustedChange) {
                throw new IllegalStateException("Untrusted credential change was invoked but it was"
                        + " not allowed. This is likely a bug. Auth token is null: "
                        + Boolean.toString(auth == null));
            }
            untrustedReset = true;
        } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
            Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
                    (response != null ? "rate limit exceeded" : "failed"));
            return;
        } else /* responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
            throw new IllegalStateException("Rate limit exceeded, so password was not changed.");
        }

        if (auth != null) {
+5 −2
Original line number Diff line number Diff line
@@ -5133,11 +5133,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        final boolean result;
        try {
            if (token == null) {
                // This is the legacy reset password for DPM. Here we want to be able to override
                // the old device password without necessarily knowing it.
                if (!TextUtils.isEmpty(password)) {
                    mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality,
                            userHandle);
                            userHandle, /*allowUntrustedChange */true);
                } else {
                    mLockPatternUtils.clearLock(null, userHandle);
                    mLockPatternUtils.clearLock(null, userHandle,
                            /*allowUntrustedChange */ true);
                }
                result = true;
            } else {
Loading