diff options
| author | 2017-08-08 16:19:33 +0200 | |
|---|---|---|
| committer | 2017-08-11 16:09:10 +0200 | |
| commit | 60dcbbf9232dc4b19c39c0a131b9819ea86dbda2 (patch) | |
| tree | f6b810848621dd3b97c87f0bcb837987b8bf1552 | |
| parent | 365ce730bd8ba09f710999bba8fa5a78137cff89 (diff) | |
FRP: Add migration for upgrading from a version without FRP credential
Adds logic to migrate the device owners credential to
the persistent data block if the device has been upgraded
from a version without FRP credential to one with.
Change-Id: I239aaf64506969d60eba8098bfceb24f846ccc94
Fixes: 63039966
Test: Migrate phone from OC-DR1 build. Factory reset. Verify FRP credential works.
| -rw-r--r-- | services/core/java/com/android/server/locksettings/LockSettingsService.java | 88 | ||||
| -rw-r--r-- | services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java | 17 | 
2 files changed, 97 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index a105c8414afe..2ce7e60067ac 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -192,6 +192,14 @@ public class LockSettingsService extends ILockSettings.Stub {          }          @Override +        public void onBootPhase(int phase) { +            super.onBootPhase(phase); +            if (phase == PHASE_ACTIVITY_MANAGER_READY) { +                mLockSettingsService.migrateOldDataAfterSystemReady(); +            } +        } + +        @Override          public void onStartUser(int userHandle) {              mLockSettingsService.onStartUser(userHandle);          } @@ -720,6 +728,73 @@ public class LockSettingsService extends ILockSettings.Stub {          }      } +    private void migrateOldDataAfterSystemReady() { +        try { +            // Migrate the FRP credential to the persistent data block +            if (LockPatternUtils.frpCredentialEnabled() && !getBoolean("migrated_frp", false, 0)) { +                migrateFrpCredential(); +                setBoolean("migrated_frp", true, 0); +                Slog.i(TAG, "Migrated migrated_frp."); +            } +        } catch (RemoteException e) { +            Slog.e(TAG, "Unable to migrateOldDataAfterSystemReady", e); +        } +    } + +    /** +     * Migrate the credential for the FRP credential owner user if the following are satisfied: +     * - the user has a secure credential +     * - the FRP credential is not set up +     * - the credential is based on a synthetic password. +     */ +    private void migrateFrpCredential() throws RemoteException { +        if (mStorage.readPersistentDataBlock() != PersistentData.NONE) { +            return; +        } +        for (UserInfo userInfo : mUserManager.getUsers()) { +            if (userOwnsFrpCredential(userInfo) && isUserSecure(userInfo.id)) { +                synchronized (mSpManager) { +                    if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) { +                        int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY, +                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id); + +                        mSpManager.migrateFrpPasswordLocked( +                                getSyntheticPasswordHandleLocked(userInfo.id), +                                userInfo, +                                redactActualQualityToMostLenientEquivalentQuality(actualQuality)); +                    } +                } +                return; +            } +        } +    } + +    /** +     * Returns the lowest password quality that still presents the same UI for entering it. +     * +     * For the FRP credential, we do not want to leak the actual quality of the password, only what +     * kind of UI it requires. However, when migrating, we only know the actual quality, not the +     * originally requested quality; since this is only used to determine what input variant to +     * present to the user, we just assume the lowest possible quality was requested. +     */ +    private int redactActualQualityToMostLenientEquivalentQuality(int quality) { +        switch (quality) { +            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: +            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: +            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: +                return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; +            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: +            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: +                return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; +            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: +            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: +            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: +            case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK: +            default: +                return quality; +        } +    } +      private final void checkWritePermission(int userId) {          mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");      } @@ -803,7 +878,7 @@ public class LockSettingsService extends ILockSettings.Stub {      }      @Override -    public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { +    public boolean getBoolean(String key, boolean defaultValue, int userId) {          checkReadPermission(key, userId);          String value = getStringUnchecked(key, null, userId);          return TextUtils.isEmpty(value) ? @@ -811,14 +886,14 @@ public class LockSettingsService extends ILockSettings.Stub {      }      @Override -    public long getLong(String key, long defaultValue, int userId) throws RemoteException { +    public long getLong(String key, long defaultValue, int userId) {          checkReadPermission(key, userId);          String value = getStringUnchecked(key, null, userId);          return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);      }      @Override -    public String getString(String key, String defaultValue, int userId) throws RemoteException { +    public String getString(String key, String defaultValue, int userId) {          checkReadPermission(key, userId);          return getStringUnchecked(key, defaultValue, userId);      } @@ -1923,11 +1998,8 @@ public class LockSettingsService extends ILockSettings.Stub {      }      private long getSyntheticPasswordHandleLocked(int userId) { -        try { -            return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId); -        } catch (RemoteException e) { -            return SyntheticPasswordManager.DEFAULT_HANDLE; -        } +        return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, +                SyntheticPasswordManager.DEFAULT_HANDLE, userId);      }      private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException { diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 603e46a49e19..ded42c020b45 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -19,6 +19,7 @@ package com.android.server.locksettings;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.admin.DevicePolicyManager; +import android.content.pm.UserInfo;  import android.hardware.weaver.V1_0.IWeaver;  import android.hardware.weaver.V1_0.WeaverConfig;  import android.hardware.weaver.V1_0.WeaverReadResponse; @@ -642,6 +643,22 @@ public class SyntheticPasswordManager {      } +    public void migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality) { +        if (mStorage.getPersistentDataBlock() != null +                && LockPatternUtils.userOwnsFrpCredential(userInfo)) { +            PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, +                    userInfo.id)); +            if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) { +                int weaverSlot = loadWeaverSlot(handle, userInfo.id); +                if (weaverSlot != INVALID_WEAVER_SLOT) { +                    synchronizeWeaverFrpPassword(pwd, requestedQuality, userInfo.id, weaverSlot); +                } else { +                    synchronizeFrpPassword(pwd, requestedQuality, userInfo.id); +                } +            } +        } +    } +      private void synchronizeFrpPassword(PasswordData pwd,              int requestedQuality, int userId) {          if (mStorage.getPersistentDataBlock() != null  |