Home | History | Annotate | Download | only in locksettings
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.locksettings;
     18 
     19 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
     20 import static android.Manifest.permission.READ_CONTACTS;
     21 import static android.content.Context.KEYGUARD_SERVICE;
     22 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
     23 
     24 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
     25 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
     26 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
     27 import static com.android.internal.widget.LockPatternUtils.USER_FRP;
     28 import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
     29 import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
     30 
     31 import android.annotation.UserIdInt;
     32 import android.app.ActivityManager;
     33 import android.app.IActivityManager;
     34 import android.app.KeyguardManager;
     35 import android.app.Notification;
     36 import android.app.NotificationManager;
     37 import android.app.PendingIntent;
     38 import android.app.admin.DevicePolicyManager;
     39 import android.app.admin.PasswordMetrics;
     40 import android.app.backup.BackupManager;
     41 import android.app.trust.IStrongAuthTracker;
     42 import android.app.trust.TrustManager;
     43 import android.content.BroadcastReceiver;
     44 import android.content.ContentResolver;
     45 import android.content.Context;
     46 import android.content.Intent;
     47 import android.content.IntentFilter;
     48 import android.content.pm.PackageManager;
     49 import android.content.pm.UserInfo;
     50 import android.content.res.Resources;
     51 import android.database.ContentObserver;
     52 import android.database.sqlite.SQLiteDatabase;
     53 import android.net.Uri;
     54 import android.os.Binder;
     55 import android.os.Bundle;
     56 import android.os.Handler;
     57 import android.os.IBinder;
     58 import android.os.IProgressListener;
     59 import android.os.Process;
     60 import android.os.RemoteException;
     61 import android.os.ResultReceiver;
     62 import android.os.ServiceManager;
     63 import android.os.ShellCallback;
     64 import android.os.StrictMode;
     65 import android.os.SystemProperties;
     66 import android.os.UserHandle;
     67 import android.os.UserManager;
     68 import android.os.storage.IStorageManager;
     69 import android.os.storage.StorageManager;
     70 import android.provider.Settings;
     71 import android.provider.Settings.Secure;
     72 import android.provider.Settings.SettingNotFoundException;
     73 import android.security.KeyStore;
     74 import android.security.keystore.AndroidKeyStoreProvider;
     75 import android.security.keystore.KeyProperties;
     76 import android.security.keystore.KeyProtection;
     77 import android.security.keystore.UserNotAuthenticatedException;
     78 import android.service.gatekeeper.GateKeeperResponse;
     79 import android.service.gatekeeper.IGateKeeperService;
     80 import android.text.TextUtils;
     81 import android.util.ArrayMap;
     82 import android.util.EventLog;
     83 import android.util.Log;
     84 import android.util.Slog;
     85 
     86 import com.android.internal.annotations.VisibleForTesting;
     87 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
     88 import com.android.internal.notification.SystemNotificationChannels;
     89 import com.android.internal.util.ArrayUtils;
     90 import com.android.internal.util.DumpUtils;
     91 import com.android.internal.util.Preconditions;
     92 import com.android.internal.widget.ICheckCredentialProgressCallback;
     93 import com.android.internal.widget.ILockSettings;
     94 import com.android.internal.widget.LockPatternUtils;
     95 import com.android.internal.widget.VerifyCredentialResponse;
     96 import com.android.server.SystemService;
     97 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
     98 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
     99 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
    100 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
    101 
    102 import libcore.util.HexEncoding;
    103 
    104 import java.io.ByteArrayOutputStream;
    105 import java.io.FileDescriptor;
    106 import java.io.FileNotFoundException;
    107 import java.io.IOException;
    108 import java.io.PrintWriter;
    109 import java.nio.charset.StandardCharsets;
    110 import java.security.InvalidAlgorithmParameterException;
    111 import java.security.InvalidKeyException;
    112 import java.security.KeyStoreException;
    113 import java.security.MessageDigest;
    114 import java.security.NoSuchAlgorithmException;
    115 import java.security.SecureRandom;
    116 import java.security.UnrecoverableKeyException;
    117 import java.security.cert.CertificateException;
    118 import java.util.Arrays;
    119 import java.util.List;
    120 import java.util.Map;
    121 import java.util.concurrent.CountDownLatch;
    122 import java.util.concurrent.TimeUnit;
    123 
    124 import javax.crypto.BadPaddingException;
    125 import javax.crypto.Cipher;
    126 import javax.crypto.IllegalBlockSizeException;
    127 import javax.crypto.KeyGenerator;
    128 import javax.crypto.NoSuchPaddingException;
    129 import javax.crypto.SecretKey;
    130 import javax.crypto.spec.GCMParameterSpec;
    131 
    132 /**
    133  * Keeps the lock pattern/password data and related settings for each user. Used by
    134  * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
    135  * lockscreen information for secondary users.
    136  *
    137  * @hide
    138  */
    139 public class LockSettingsService extends ILockSettings.Stub {
    140     private static final String TAG = "LockSettingsService";
    141     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
    142     private static final boolean DEBUG = false;
    143 
    144     private static final int PROFILE_KEY_IV_SIZE = 12;
    145     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
    146     private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
    147 
    148     // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
    149     // Do not call into ActivityManager while holding mSpManager lock.
    150     private final Object mSeparateChallengeLock = new Object();
    151 
    152     private final DeviceProvisionedObserver mDeviceProvisionedObserver =
    153             new DeviceProvisionedObserver();
    154 
    155     private final Injector mInjector;
    156     private final Context mContext;
    157     @VisibleForTesting
    158     protected final Handler mHandler;
    159     @VisibleForTesting
    160     protected final LockSettingsStorage mStorage;
    161     private final LockSettingsStrongAuth mStrongAuth;
    162     private final SynchronizedStrongAuthTracker mStrongAuthTracker;
    163 
    164     private final LockPatternUtils mLockPatternUtils;
    165     private final NotificationManager mNotificationManager;
    166     private final UserManager mUserManager;
    167     private final IActivityManager mActivityManager;
    168     private final SyntheticPasswordManager mSpManager;
    169 
    170     private final KeyStore mKeyStore;
    171 
    172     private boolean mFirstCallToVold;
    173     protected IGateKeeperService mGateKeeperService;
    174 
    175     /**
    176      * The UIDs that are used for system credential storage in keystore.
    177      */
    178     private static final int[] SYSTEM_CREDENTIAL_UIDS = {
    179             Process.WIFI_UID, Process.VPN_UID,
    180             Process.ROOT_UID, Process.SYSTEM_UID };
    181 
    182     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
    183     // devices. The most basic of these is to show/hide notifications about missing features until
    184     // the user unlocks the account and credential-encrypted storage is available.
    185     public static final class Lifecycle extends SystemService {
    186         private LockSettingsService mLockSettingsService;
    187 
    188         public Lifecycle(Context context) {
    189             super(context);
    190         }
    191 
    192         @Override
    193         public void onStart() {
    194             AndroidKeyStoreProvider.install();
    195             mLockSettingsService = new LockSettingsService(getContext());
    196             publishBinderService("lock_settings", mLockSettingsService);
    197         }
    198 
    199         @Override
    200         public void onBootPhase(int phase) {
    201             super.onBootPhase(phase);
    202             if (phase == PHASE_ACTIVITY_MANAGER_READY) {
    203                 mLockSettingsService.migrateOldDataAfterSystemReady();
    204             }
    205         }
    206 
    207         @Override
    208         public void onStartUser(int userHandle) {
    209             mLockSettingsService.onStartUser(userHandle);
    210         }
    211 
    212         @Override
    213         public void onUnlockUser(int userHandle) {
    214             mLockSettingsService.onUnlockUser(userHandle);
    215         }
    216 
    217         @Override
    218         public void onCleanupUser(int userHandle) {
    219             mLockSettingsService.onCleanupUser(userHandle);
    220         }
    221     }
    222 
    223     @VisibleForTesting
    224     protected static class SynchronizedStrongAuthTracker
    225             extends LockPatternUtils.StrongAuthTracker {
    226         public SynchronizedStrongAuthTracker(Context context) {
    227             super(context);
    228         }
    229 
    230         @Override
    231         protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
    232             synchronized (this) {
    233                 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
    234             }
    235         }
    236 
    237         @Override
    238         public int getStrongAuthForUser(int userId) {
    239             synchronized (this) {
    240                 return super.getStrongAuthForUser(userId);
    241             }
    242         }
    243 
    244         void register(LockSettingsStrongAuth strongAuth) {
    245             strongAuth.registerStrongAuthTracker(this.mStub);
    246         }
    247     }
    248 
    249     /**
    250      * Tie managed profile to primary profile if it is in unified mode and not tied before.
    251      *
    252      * @param managedUserId Managed profile user Id
    253      * @param managedUserPassword Managed profile original password (when it has separated lock).
    254      *            NULL when it does not have a separated lock before.
    255      */
    256     public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
    257         if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
    258         // Only for managed profile
    259         if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
    260             return;
    261         }
    262         // Do not tie managed profile when work challenge is enabled
    263         if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
    264             return;
    265         }
    266         // Do not tie managed profile to parent when it's done already
    267         if (mStorage.hasChildProfileLock(managedUserId)) {
    268             return;
    269         }
    270         // Do not tie it to parent when parent does not have a screen lock
    271         final int parentId = mUserManager.getProfileParent(managedUserId).id;
    272         if (!isUserSecure(parentId)) {
    273             if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
    274             return;
    275         }
    276         // Do not tie when the parent has no SID (but does have a screen lock).
    277         // This can only happen during an upgrade path where SID is yet to be
    278         // generated when the user unlocks for the first time.
    279         try {
    280             if (getGateKeeperService().getSecureUserId(parentId) == 0) {
    281                 return;
    282             }
    283         } catch (RemoteException e) {
    284             Slog.e(TAG, "Failed to talk to GateKeeper service", e);
    285             return;
    286         }
    287         if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
    288         byte[] randomLockSeed = new byte[] {};
    289         try {
    290             randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
    291             String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
    292             final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
    293             setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
    294                     managedUserPassword, quality, managedUserId);
    295             // We store a private credential for the managed user that's unlocked by the primary
    296             // account holder's credential. As such, the user will never be prompted to enter this
    297             // password directly, so we always store a password.
    298             setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
    299             tieProfileLockToParent(managedUserId, newPassword);
    300         } catch (NoSuchAlgorithmException | RemoteException e) {
    301             Slog.e(TAG, "Fail to tie managed profile", e);
    302             // Nothing client can do to fix this issue, so we do not throw exception out
    303         }
    304     }
    305 
    306     static class Injector {
    307 
    308         protected Context mContext;
    309 
    310         public Injector(Context context) {
    311             mContext = context;
    312         }
    313 
    314         public Context getContext() {
    315             return mContext;
    316         }
    317 
    318         public Handler getHandler() {
    319             return new Handler();
    320         }
    321 
    322         public LockSettingsStorage getStorage() {
    323             final LockSettingsStorage storage = new LockSettingsStorage(mContext);
    324             storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
    325                 @Override
    326                 public void initialize(SQLiteDatabase db) {
    327                     // Get the lockscreen default from a system property, if available
    328                     boolean lockScreenDisable = SystemProperties.getBoolean(
    329                             "ro.lockscreen.disable.default", false);
    330                     if (lockScreenDisable) {
    331                         storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
    332                     }
    333                 }
    334             });
    335             return storage;
    336         }
    337 
    338         public LockSettingsStrongAuth getStrongAuth() {
    339             return new LockSettingsStrongAuth(mContext);
    340         }
    341 
    342         public SynchronizedStrongAuthTracker getStrongAuthTracker() {
    343             return new SynchronizedStrongAuthTracker(mContext);
    344         }
    345 
    346         public IActivityManager getActivityManager() {
    347             return ActivityManager.getService();
    348         }
    349 
    350         public LockPatternUtils getLockPatternUtils() {
    351             return new LockPatternUtils(mContext);
    352         }
    353 
    354         public NotificationManager getNotificationManager() {
    355             return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    356         }
    357 
    358         public UserManager getUserManager() {
    359             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    360         }
    361 
    362         public DevicePolicyManager getDevicePolicyManager() {
    363             return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    364         }
    365 
    366         public KeyStore getKeyStore() {
    367             return KeyStore.getInstance();
    368         }
    369 
    370         public IStorageManager getStorageManager() {
    371             final IBinder service = ServiceManager.getService("mount");
    372             if (service != null) {
    373                 return IStorageManager.Stub.asInterface(service);
    374             }
    375             return null;
    376         }
    377 
    378         public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
    379             return new SyntheticPasswordManager(getContext(), storage, getUserManager());
    380         }
    381 
    382         public int binderGetCallingUid() {
    383             return Binder.getCallingUid();
    384         }
    385     }
    386 
    387     public LockSettingsService(Context context) {
    388         this(new Injector(context));
    389     }
    390 
    391     @VisibleForTesting
    392     protected LockSettingsService(Injector injector) {
    393         mInjector = injector;
    394         mContext = injector.getContext();
    395         mKeyStore = injector.getKeyStore();
    396         mHandler = injector.getHandler();
    397         mStrongAuth = injector.getStrongAuth();
    398         mActivityManager = injector.getActivityManager();
    399 
    400         mLockPatternUtils = injector.getLockPatternUtils();
    401         mFirstCallToVold = true;
    402 
    403         IntentFilter filter = new IntentFilter();
    404         filter.addAction(Intent.ACTION_USER_ADDED);
    405         filter.addAction(Intent.ACTION_USER_STARTING);
    406         filter.addAction(Intent.ACTION_USER_REMOVED);
    407         injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
    408                 null, null);
    409 
    410         mStorage = injector.getStorage();
    411         mNotificationManager = injector.getNotificationManager();
    412         mUserManager = injector.getUserManager();
    413         mStrongAuthTracker = injector.getStrongAuthTracker();
    414         mStrongAuthTracker.register(mStrongAuth);
    415 
    416         mSpManager = injector.getSyntheticPasswordManager(mStorage);
    417     }
    418 
    419     /**
    420      * If the account is credential-encrypted, show notification requesting the user to unlock the
    421      * device.
    422      */
    423     private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
    424         final UserInfo user = mUserManager.getUserInfo(userId);
    425         if (!user.isManagedProfile()) {
    426             // When the user is locked, we communicate it loud-and-clear
    427             // on the lockscreen; we only show a notification below for
    428             // locked managed profiles.
    429             return;
    430         }
    431 
    432         final UserHandle userHandle = user.getUserHandle();
    433         final boolean isSecure = isUserSecure(userId);
    434         if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
    435             UserInfo parent = mUserManager.getProfileParent(userId);
    436             if (parent != null &&
    437                     mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
    438                     !mUserManager.isQuietModeEnabled(userHandle)) {
    439                 // Only show notifications for managed profiles once their parent
    440                 // user is unlocked.
    441                 showEncryptionNotificationForProfile(userHandle);
    442             }
    443         }
    444     }
    445 
    446     private void showEncryptionNotificationForProfile(UserHandle user) {
    447         Resources r = mContext.getResources();
    448         CharSequence title = r.getText(
    449                 com.android.internal.R.string.user_encrypted_title);
    450         CharSequence message = r.getText(
    451                 com.android.internal.R.string.profile_encrypted_message);
    452         CharSequence detail = r.getText(
    453                 com.android.internal.R.string.profile_encrypted_detail);
    454 
    455         final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
    456         final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
    457                 user.getIdentifier());
    458         if (unlockIntent == null) {
    459             return;
    460         }
    461         unlockIntent.setFlags(
    462                 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    463         PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
    464                 PendingIntent.FLAG_UPDATE_CURRENT);
    465 
    466         showEncryptionNotification(user, title, message, detail, intent);
    467     }
    468 
    469     private void showEncryptionNotification(UserHandle user, CharSequence title,
    470             CharSequence message, CharSequence detail, PendingIntent intent) {
    471         if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
    472 
    473         // Suppress all notifications on non-FBE devices for now
    474         if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
    475 
    476         Notification notification =
    477                 new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
    478                         .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
    479                         .setWhen(0)
    480                         .setOngoing(true)
    481                         .setTicker(title)
    482                         .setColor(mContext.getColor(
    483                                 com.android.internal.R.color.system_notification_accent_color))
    484                         .setContentTitle(title)
    485                         .setContentText(message)
    486                         .setSubText(detail)
    487                         .setVisibility(Notification.VISIBILITY_PUBLIC)
    488                         .setContentIntent(intent)
    489                         .build();
    490         mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
    491             notification, user);
    492     }
    493 
    494     private void hideEncryptionNotification(UserHandle userHandle) {
    495         if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
    496         mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
    497             userHandle);
    498     }
    499 
    500     public void onCleanupUser(int userId) {
    501         hideEncryptionNotification(new UserHandle(userId));
    502     }
    503 
    504     public void onStartUser(final int userId) {
    505         maybeShowEncryptionNotificationForUser(userId);
    506     }
    507 
    508     /**
    509      * Check if profile got unlocked but the keystore is still locked. This happens on full disk
    510      * encryption devices since the profile may not yet be running when we consider unlocking it
    511      * during the normal flow. In this case unlock the keystore for the profile.
    512      */
    513     private void ensureProfileKeystoreUnlocked(int userId) {
    514         final KeyStore ks = KeyStore.getInstance();
    515         if (ks.state(userId) == KeyStore.State.LOCKED
    516                 && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
    517             Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
    518             try {
    519                 // If boot took too long and the password in vold got expired, parent keystore will
    520                 // be still locked, we ignore this case since the user will be prompted to unlock
    521                 // the device after boot.
    522                 unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
    523             } catch (RemoteException e) {
    524                 Slog.e(TAG, "Failed to unlock child profile");
    525             }
    526         }
    527     }
    528 
    529     public void onUnlockUser(final int userId) {
    530         // Perform tasks which require locks in LSS on a handler, as we are callbacks from
    531         // ActivityManager.unlockUser()
    532         mHandler.post(new Runnable() {
    533             @Override
    534             public void run() {
    535                 ensureProfileKeystoreUnlocked(userId);
    536                 // Hide notification first, as tie managed profile lock takes time
    537                 hideEncryptionNotification(new UserHandle(userId));
    538 
    539                 // Now we have unlocked the parent user we should show notifications
    540                 // about any profiles that exist.
    541                 List<UserInfo> profiles = mUserManager.getProfiles(userId);
    542                 for (int i = 0; i < profiles.size(); i++) {
    543                     UserInfo profile = profiles.get(i);
    544                     final boolean isSecure = isUserSecure(profile.id);
    545                     if (isSecure && profile.isManagedProfile()) {
    546                         UserHandle userHandle = profile.getUserHandle();
    547                         if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
    548                                 !mUserManager.isQuietModeEnabled(userHandle)) {
    549                             showEncryptionNotificationForProfile(userHandle);
    550                         }
    551                     }
    552                 }
    553 
    554                 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
    555                     tieManagedProfileLockIfNecessary(userId, null);
    556                 }
    557             }
    558         });
    559     }
    560 
    561     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    562         @Override
    563         public void onReceive(Context context, Intent intent) {
    564             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
    565                 // Notify keystore that a new user was added.
    566                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    567                 if (userHandle > UserHandle.USER_SYSTEM) {
    568                     removeUser(userHandle, /* unknownUser= */ true);
    569                 }
    570                 final KeyStore ks = KeyStore.getInstance();
    571                 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
    572                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
    573                 ks.onUserAdded(userHandle, parentHandle);
    574             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
    575                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    576                 mStorage.prefetchUser(userHandle);
    577             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
    578                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    579                 if (userHandle > 0) {
    580                     removeUser(userHandle, /* unknownUser= */ false);
    581                 }
    582             }
    583         }
    584     };
    585 
    586     @Override // binder interface
    587     public void systemReady() {
    588         if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
    589             EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
    590         }
    591         checkWritePermission(UserHandle.USER_SYSTEM);
    592         migrateOldData();
    593         try {
    594             getGateKeeperService();
    595             mSpManager.initWeaverService();
    596         } catch (RemoteException e) {
    597             Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
    598         }
    599         mDeviceProvisionedObserver.onSystemReady();
    600         // TODO: maybe skip this for split system user mode.
    601         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
    602         mStrongAuth.systemReady();
    603     }
    604 
    605     private void migrateOldData() {
    606         try {
    607             // These Settings moved before multi-user was enabled, so we only have to do it for the
    608             // root user.
    609             if (getString("migrated", null, 0) == null) {
    610                 final ContentResolver cr = mContext.getContentResolver();
    611                 for (String validSetting : VALID_SETTINGS) {
    612                     String value = Settings.Secure.getString(cr, validSetting);
    613                     if (value != null) {
    614                         setString(validSetting, value, 0);
    615                     }
    616                 }
    617                 // No need to move the password / pattern files. They're already in the right place.
    618                 setString("migrated", "true", 0);
    619                 Slog.i(TAG, "Migrated lock settings to new location");
    620             }
    621 
    622             // These Settings changed after multi-user was enabled, hence need to be moved per user.
    623             if (getString("migrated_user_specific", null, 0) == null) {
    624                 final ContentResolver cr = mContext.getContentResolver();
    625                 List<UserInfo> users = mUserManager.getUsers();
    626                 for (int user = 0; user < users.size(); user++) {
    627                     // Migrate owner info
    628                     final int userId = users.get(user).id;
    629                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
    630                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
    631                     if (!TextUtils.isEmpty(ownerInfo)) {
    632                         setString(OWNER_INFO, ownerInfo, userId);
    633                         Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
    634                     }
    635 
    636                     // Migrate owner info enabled. Note there was a bug where older platforms only
    637                     // stored this value if the checkbox was toggled at least once. The code detects
    638                     // this case by handling the exception.
    639                     final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    640                     boolean enabled;
    641                     try {
    642                         int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
    643                         enabled = ivalue != 0;
    644                         setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
    645                     } catch (SettingNotFoundException e) {
    646                         // Setting was never stored. Store it if the string is not empty.
    647                         if (!TextUtils.isEmpty(ownerInfo)) {
    648                             setLong(OWNER_INFO_ENABLED, 1, userId);
    649                         }
    650                     }
    651                     Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
    652                 }
    653                 // No need to move the password / pattern files. They're already in the right place.
    654                 setString("migrated_user_specific", "true", 0);
    655                 Slog.i(TAG, "Migrated per-user lock settings to new location");
    656             }
    657 
    658             // Migrates biometric weak such that the fallback mechanism becomes the primary.
    659             if (getString("migrated_biometric_weak", null, 0) == null) {
    660                 List<UserInfo> users = mUserManager.getUsers();
    661                 for (int i = 0; i < users.size(); i++) {
    662                     int userId = users.get(i).id;
    663                     long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    664                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    665                             userId);
    666                     long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    667                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    668                             userId);
    669                     if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
    670                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    671                                 alternateType,
    672                                 userId);
    673                     }
    674                     setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    675                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    676                             userId);
    677                 }
    678                 setString("migrated_biometric_weak", "true", 0);
    679                 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
    680             }
    681 
    682             // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
    683             // user was present on the system, so if we're upgrading to M and there is more than one
    684             // user we disable the flag to remain consistent.
    685             if (getString("migrated_lockscreen_disabled", null, 0) == null) {
    686                 final List<UserInfo> users = mUserManager.getUsers();
    687                 final int userCount = users.size();
    688                 int switchableUsers = 0;
    689                 for (int i = 0; i < userCount; i++) {
    690                     if (users.get(i).supportsSwitchTo()) {
    691                         switchableUsers++;
    692                     }
    693                 }
    694 
    695                 if (switchableUsers > 1) {
    696                     for (int i = 0; i < userCount; i++) {
    697                         int id = users.get(i).id;
    698 
    699                         if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
    700                             setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
    701                         }
    702                     }
    703                 }
    704 
    705                 setString("migrated_lockscreen_disabled", "true", 0);
    706                 Slog.i(TAG, "Migrated lockscreen disabled flag");
    707             }
    708 
    709             final List<UserInfo> users = mUserManager.getUsers();
    710             for (int i = 0; i < users.size(); i++) {
    711                 final UserInfo userInfo = users.get(i);
    712                 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
    713                     // When managed profile has a unified lock, the password quality stored has 2
    714                     // possibilities only.
    715                     // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
    716                     // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
    717                     // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
    718                     // unified lock.
    719                     final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    720                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
    721                     if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    722                         // Only possible when it's upgraded from nyc dp3
    723                         Slog.i(TAG, "Migrated tied profile lock type");
    724                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    725                                 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
    726                     } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
    727                         // It should not happen
    728                         Slog.e(TAG, "Invalid tied profile lock type: " + quality);
    729                     }
    730                 }
    731                 try {
    732                     final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
    733                     java.security.KeyStore keyStore =
    734                             java.security.KeyStore.getInstance("AndroidKeyStore");
    735                     keyStore.load(null);
    736                     if (keyStore.containsAlias(alias)) {
    737                         keyStore.deleteEntry(alias);
    738                     }
    739                 } catch (KeyStoreException | NoSuchAlgorithmException |
    740                         CertificateException | IOException e) {
    741                     Slog.e(TAG, "Unable to remove tied profile key", e);
    742                 }
    743             }
    744 
    745             boolean isWatch = mContext.getPackageManager().hasSystemFeature(
    746                     PackageManager.FEATURE_WATCH);
    747             // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
    748             // and device management the lockscreen must be re-enabled now for users that upgrade.
    749             if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
    750                 final int userCount = users.size();
    751                 for (int i = 0; i < userCount; i++) {
    752                     int id = users.get(i).id;
    753                     setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
    754                 }
    755                 setString("migrated_wear_lockscreen_disabled", "true", 0);
    756                 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
    757             }
    758         } catch (RemoteException re) {
    759             Slog.e(TAG, "Unable to migrate old data", re);
    760         }
    761     }
    762 
    763     private void migrateOldDataAfterSystemReady() {
    764         try {
    765             // Migrate the FRP credential to the persistent data block
    766             if (LockPatternUtils.frpCredentialEnabled(mContext)
    767                     && !getBoolean("migrated_frp", false, 0)) {
    768                 migrateFrpCredential();
    769                 setBoolean("migrated_frp", true, 0);
    770                 Slog.i(TAG, "Migrated migrated_frp.");
    771             }
    772         } catch (RemoteException e) {
    773             Slog.e(TAG, "Unable to migrateOldDataAfterSystemReady", e);
    774         }
    775     }
    776 
    777     /**
    778      * Migrate the credential for the FRP credential owner user if the following are satisfied:
    779      * - the user has a secure credential
    780      * - the FRP credential is not set up
    781      * - the credential is based on a synthetic password.
    782      */
    783     private void migrateFrpCredential() throws RemoteException {
    784         if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
    785             return;
    786         }
    787         for (UserInfo userInfo : mUserManager.getUsers()) {
    788             if (userOwnsFrpCredential(mContext, userInfo) && isUserSecure(userInfo.id)) {
    789                 synchronized (mSpManager) {
    790                     if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) {
    791                         int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    792                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
    793 
    794                         mSpManager.migrateFrpPasswordLocked(
    795                                 getSyntheticPasswordHandleLocked(userInfo.id),
    796                                 userInfo,
    797                                 redactActualQualityToMostLenientEquivalentQuality(actualQuality));
    798                     }
    799                 }
    800                 return;
    801             }
    802         }
    803     }
    804 
    805     /**
    806      * Returns the lowest password quality that still presents the same UI for entering it.
    807      *
    808      * For the FRP credential, we do not want to leak the actual quality of the password, only what
    809      * kind of UI it requires. However, when migrating, we only know the actual quality, not the
    810      * originally requested quality; since this is only used to determine what input variant to
    811      * present to the user, we just assume the lowest possible quality was requested.
    812      */
    813     private int redactActualQualityToMostLenientEquivalentQuality(int quality) {
    814         switch (quality) {
    815             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
    816             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
    817             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
    818                 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
    819             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
    820             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
    821                 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
    822             case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
    823             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
    824             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
    825             case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
    826             default:
    827                 return quality;
    828         }
    829     }
    830 
    831     private final void checkWritePermission(int userId) {
    832         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
    833     }
    834 
    835     private final void checkPasswordReadPermission(int userId) {
    836         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
    837     }
    838 
    839     private final void checkPasswordHavePermission(int userId) {
    840         if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
    841             EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
    842         }
    843         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
    844     }
    845 
    846     private final void checkReadPermission(String requestedKey, int userId) {
    847         final int callingUid = Binder.getCallingUid();
    848 
    849         for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
    850             String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
    851             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
    852                     != PackageManager.PERMISSION_GRANTED) {
    853                 throw new SecurityException("uid=" + callingUid
    854                         + " needs permission " + READ_CONTACTS + " to read "
    855                         + requestedKey + " for user " + userId);
    856             }
    857         }
    858 
    859         for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
    860             String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
    861             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
    862                     != PackageManager.PERMISSION_GRANTED) {
    863                 throw new SecurityException("uid=" + callingUid
    864                         + " needs permission " + PERMISSION + " to read "
    865                         + requestedKey + " for user " + userId);
    866             }
    867         }
    868     }
    869 
    870     @Override
    871     public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
    872         checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
    873         synchronized (mSeparateChallengeLock) {
    874             return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
    875         }
    876     }
    877 
    878     @Override
    879     public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
    880             String managedUserPassword) throws RemoteException {
    881         checkWritePermission(userId);
    882         synchronized (mSeparateChallengeLock) {
    883             setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
    884             if (enabled) {
    885                 mStorage.removeChildProfileLock(userId);
    886                 removeKeystoreProfileKey(userId);
    887             } else {
    888                 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
    889             }
    890         }
    891     }
    892 
    893     @Override
    894     public void setBoolean(String key, boolean value, int userId) throws RemoteException {
    895         checkWritePermission(userId);
    896         setStringUnchecked(key, userId, value ? "1" : "0");
    897     }
    898 
    899     @Override
    900     public void setLong(String key, long value, int userId) throws RemoteException {
    901         checkWritePermission(userId);
    902         setStringUnchecked(key, userId, Long.toString(value));
    903     }
    904 
    905     @Override
    906     public void setString(String key, String value, int userId) throws RemoteException {
    907         checkWritePermission(userId);
    908         setStringUnchecked(key, userId, value);
    909     }
    910 
    911     private void setStringUnchecked(String key, int userId, String value) {
    912         Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
    913 
    914         mStorage.writeKeyValue(key, value, userId);
    915         if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
    916             BackupManager.dataChanged("com.android.providers.settings");
    917         }
    918     }
    919 
    920     @Override
    921     public boolean getBoolean(String key, boolean defaultValue, int userId) {
    922         checkReadPermission(key, userId);
    923         String value = getStringUnchecked(key, null, userId);
    924         return TextUtils.isEmpty(value) ?
    925                 defaultValue : (value.equals("1") || value.equals("true"));
    926     }
    927 
    928     @Override
    929     public long getLong(String key, long defaultValue, int userId) {
    930         checkReadPermission(key, userId);
    931         String value = getStringUnchecked(key, null, userId);
    932         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
    933     }
    934 
    935     @Override
    936     public String getString(String key, String defaultValue, int userId) {
    937         checkReadPermission(key, userId);
    938         return getStringUnchecked(key, defaultValue, userId);
    939     }
    940 
    941     public String getStringUnchecked(String key, String defaultValue, int userId) {
    942         if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
    943             long ident = Binder.clearCallingIdentity();
    944             try {
    945                 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
    946             } finally {
    947                 Binder.restoreCallingIdentity(ident);
    948             }
    949         }
    950 
    951         if (userId == USER_FRP) {
    952             return getFrpStringUnchecked(key);
    953         }
    954 
    955         if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
    956             key = Settings.Secure.LOCK_PATTERN_ENABLED;
    957         }
    958 
    959         return mStorage.readKeyValue(key, defaultValue, userId);
    960     }
    961 
    962     private String getFrpStringUnchecked(String key) {
    963         if (LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
    964             return String.valueOf(readFrpPasswordQuality());
    965         }
    966         return null;
    967     }
    968 
    969     private int readFrpPasswordQuality() {
    970         return mStorage.readPersistentDataBlock().qualityForUi;
    971     }
    972 
    973     @Override
    974     public boolean havePassword(int userId) throws RemoteException {
    975         checkPasswordHavePermission(userId);
    976         synchronized (mSpManager) {
    977             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
    978                 long handle = getSyntheticPasswordHandleLocked(userId);
    979                 return mSpManager.getCredentialType(handle, userId) ==
    980                         LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
    981             }
    982         }
    983         // Do we need a permissions check here?
    984         return mStorage.hasPassword(userId);
    985     }
    986 
    987     @Override
    988     public boolean havePattern(int userId) throws RemoteException {
    989         checkPasswordHavePermission(userId);
    990         synchronized (mSpManager) {
    991             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
    992                 long handle = getSyntheticPasswordHandleLocked(userId);
    993                 return mSpManager.getCredentialType(handle, userId) ==
    994                         LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
    995             }
    996         }
    997         // Do we need a permissions check here?
    998         return mStorage.hasPattern(userId);
    999     }
   1000 
   1001     private boolean isUserSecure(int userId) {
   1002         synchronized (mSpManager) {
   1003             try {
   1004                 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
   1005                     long handle = getSyntheticPasswordHandleLocked(userId);
   1006                     return mSpManager.getCredentialType(handle, userId) !=
   1007                             LockPatternUtils.CREDENTIAL_TYPE_NONE;
   1008                 }
   1009             } catch (RemoteException e) {
   1010                 // fall through
   1011             }
   1012         }
   1013         return mStorage.hasCredential(userId);
   1014     }
   1015 
   1016     private void setKeystorePassword(String password, int userHandle) {
   1017         final KeyStore ks = KeyStore.getInstance();
   1018         ks.onUserPasswordChanged(userHandle, password);
   1019     }
   1020 
   1021     private void unlockKeystore(String password, int userHandle) {
   1022         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
   1023         final KeyStore ks = KeyStore.getInstance();
   1024         ks.unlock(userHandle, password);
   1025     }
   1026 
   1027     @VisibleForTesting
   1028     protected String getDecryptedPasswordForTiedProfile(int userId)
   1029             throws KeyStoreException, UnrecoverableKeyException,
   1030             NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
   1031             InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
   1032             CertificateException, IOException {
   1033         if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
   1034         byte[] storedData = mStorage.readChildProfileLock(userId);
   1035         if (storedData == null) {
   1036             throw new FileNotFoundException("Child profile lock file not found");
   1037         }
   1038         byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
   1039         byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
   1040                 storedData.length);
   1041         byte[] decryptionResult;
   1042         java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
   1043         keyStore.load(null);
   1044         SecretKey decryptionKey = (SecretKey) keyStore.getKey(
   1045                 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
   1046 
   1047         Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
   1048                 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
   1049 
   1050         cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
   1051         decryptionResult = cipher.doFinal(encryptedPassword);
   1052         return new String(decryptionResult, StandardCharsets.UTF_8);
   1053     }
   1054 
   1055     private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
   1056             throws RemoteException {
   1057         try {
   1058             doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
   1059                     LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
   1060                     false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
   1061         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   1062                 | NoSuchAlgorithmException | NoSuchPaddingException
   1063                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1064                 | BadPaddingException | CertificateException | IOException e) {
   1065             if (e instanceof FileNotFoundException) {
   1066                 Slog.i(TAG, "Child profile key not found");
   1067             } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
   1068                 Slog.i(TAG, "Parent keystore seems locked, ignoring");
   1069             } else {
   1070                 Slog.e(TAG, "Failed to decrypt child profile key", e);
   1071             }
   1072         }
   1073     }
   1074 
   1075     private void unlockUser(int userId, byte[] token, byte[] secret) {
   1076         // TODO: make this method fully async so we can update UI with progress strings
   1077         final CountDownLatch latch = new CountDownLatch(1);
   1078         final IProgressListener listener = new IProgressListener.Stub() {
   1079             @Override
   1080             public void onStarted(int id, Bundle extras) throws RemoteException {
   1081                 Log.d(TAG, "unlockUser started");
   1082             }
   1083 
   1084             @Override
   1085             public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
   1086                 Log.d(TAG, "unlockUser progress " + progress);
   1087             }
   1088 
   1089             @Override
   1090             public void onFinished(int id, Bundle extras) throws RemoteException {
   1091                 Log.d(TAG, "unlockUser finished");
   1092                 latch.countDown();
   1093             }
   1094         };
   1095 
   1096         try {
   1097             mActivityManager.unlockUser(userId, token, secret, listener);
   1098         } catch (RemoteException e) {
   1099             throw e.rethrowAsRuntimeException();
   1100         }
   1101 
   1102         try {
   1103             latch.await(15, TimeUnit.SECONDS);
   1104         } catch (InterruptedException e) {
   1105             Thread.currentThread().interrupt();
   1106         }
   1107         try {
   1108             if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
   1109                 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
   1110                 for (UserInfo pi : profiles) {
   1111                     // Unlock managed profile with unified lock
   1112                     if (tiedManagedProfileReadyToUnlock(pi)) {
   1113                         unlockChildProfile(pi.id, false /* ignoreUserNotAuthenticated */);
   1114                     }
   1115                 }
   1116             }
   1117         } catch (RemoteException e) {
   1118             Log.d(TAG, "Failed to unlock child profile", e);
   1119         }
   1120     }
   1121 
   1122     private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
   1123         return userInfo.isManagedProfile()
   1124                 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id)
   1125                 && mStorage.hasChildProfileLock(userInfo.id)
   1126                 && mUserManager.isUserRunning(userInfo.id);
   1127     }
   1128 
   1129     private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
   1130         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
   1131             return null;
   1132         }
   1133         Map<Integer, String> result = new ArrayMap<Integer, String>();
   1134         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
   1135         final int size = profiles.size();
   1136         for (int i = 0; i < size; i++) {
   1137             final UserInfo profile = profiles.get(i);
   1138             if (!profile.isManagedProfile()) {
   1139                 continue;
   1140             }
   1141             final int managedUserId = profile.id;
   1142             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
   1143                 continue;
   1144             }
   1145             try {
   1146                 result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId));
   1147             } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
   1148                     | NoSuchPaddingException | InvalidKeyException
   1149                     | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1150                     | BadPaddingException | CertificateException | IOException e) {
   1151                 Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " +
   1152                     managedUserId, e);
   1153             }
   1154         }
   1155         return result;
   1156     }
   1157 
   1158     /**
   1159      * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
   1160      * depending on the parent user's secure state.
   1161      *
   1162      * When clearing tied work challenges, a pre-computed password table for profiles are required,
   1163      * since changing password for profiles requires existing password, and existing passwords can
   1164      * only be computed before the parent user's password is cleared.
   1165      *
   1166      * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
   1167      * method again on profiles. However the recursion is guaranteed to terminate as this method
   1168      * terminates when the user is a managed profile.
   1169      */
   1170     private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
   1171             Map<Integer, String> profilePasswordMap) throws RemoteException {
   1172         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
   1173             return;
   1174         }
   1175         final boolean isSecure = isUserSecure(userId);
   1176         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
   1177         final int size = profiles.size();
   1178         for (int i = 0; i < size; i++) {
   1179             final UserInfo profile = profiles.get(i);
   1180             if (profile.isManagedProfile()) {
   1181                 final int managedUserId = profile.id;
   1182                 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
   1183                     continue;
   1184                 }
   1185                 if (isSecure) {
   1186                     tieManagedProfileLockIfNecessary(managedUserId, null);
   1187                 } else {
   1188                     // We use cached work profile password computed before clearing the parent's
   1189                     // credential, otherwise they get lost
   1190                     if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
   1191                         setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
   1192                                 profilePasswordMap.get(managedUserId),
   1193                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
   1194                     } else {
   1195                         Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
   1196                         // Supplying null here would lead to untrusted credential change
   1197                         setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
   1198                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
   1199                     }
   1200                     mStorage.removeChildProfileLock(managedUserId);
   1201                     removeKeystoreProfileKey(managedUserId);
   1202                 }
   1203             }
   1204         }
   1205     }
   1206 
   1207     private boolean isManagedProfileWithUnifiedLock(int userId) {
   1208         return mUserManager.getUserInfo(userId).isManagedProfile()
   1209                 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
   1210     }
   1211 
   1212     private boolean isManagedProfileWithSeparatedLock(int userId) {
   1213         return mUserManager.getUserInfo(userId).isManagedProfile()
   1214                 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
   1215     }
   1216 
   1217     // This method should be called by LockPatternUtil only, all internal methods in this class
   1218     // should call setLockCredentialInternal.
   1219     @Override
   1220     public void setLockCredential(String credential, int type, String savedCredential,
   1221             int requestedQuality, int userId)
   1222             throws RemoteException {
   1223         checkWritePermission(userId);
   1224         synchronized (mSeparateChallengeLock) {
   1225             setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
   1226             setSeparateProfileChallengeEnabled(userId, true, null);
   1227             notifyPasswordChanged(userId);
   1228         }
   1229     }
   1230 
   1231     private void setLockCredentialInternal(String credential, int credentialType,
   1232             String savedCredential, int requestedQuality, int userId) throws RemoteException {
   1233         // Normalize savedCredential and credential such that empty string is always represented
   1234         // as null.
   1235         if (TextUtils.isEmpty(savedCredential)) {
   1236             savedCredential = null;
   1237         }
   1238         if (TextUtils.isEmpty(credential)) {
   1239             credential = null;
   1240         }
   1241         synchronized (mSpManager) {
   1242             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
   1243                 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
   1244                         requestedQuality, userId);
   1245                 return;
   1246             }
   1247         }
   1248 
   1249         if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
   1250             if (credential != null) {
   1251                 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
   1252             }
   1253             clearUserKeyProtection(userId);
   1254             getGateKeeperService().clearSecureUserId(userId);
   1255             mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
   1256             setKeystorePassword(null, userId);
   1257             fixateNewestUserKeyAuth(userId);
   1258             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
   1259             notifyActivePasswordMetricsAvailable(null, userId);
   1260             return;
   1261         }
   1262         if (credential == null) {
   1263             throw new RemoteException("Null credential with mismatched credential type");
   1264         }
   1265 
   1266         CredentialHash currentHandle = mStorage.readCredentialHash(userId);
   1267         if (isManagedProfileWithUnifiedLock(userId)) {
   1268             // get credential from keystore when managed profile has unified lock
   1269             if (savedCredential == null) {
   1270                 try {
   1271                     savedCredential = getDecryptedPasswordForTiedProfile(userId);
   1272                 } catch (FileNotFoundException e) {
   1273                     Slog.i(TAG, "Child profile key not found");
   1274                 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   1275                         | NoSuchAlgorithmException | NoSuchPaddingException
   1276                         | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1277                         | BadPaddingException | CertificateException | IOException e) {
   1278                     Slog.e(TAG, "Failed to decrypt child profile key", e);
   1279                 }
   1280             }
   1281         } else {
   1282             if (currentHandle.hash == null) {
   1283                 if (savedCredential != null) {
   1284                     Slog.w(TAG, "Saved credential provided, but none stored");
   1285                 }
   1286                 savedCredential = null;
   1287             }
   1288         }
   1289         synchronized (mSpManager) {
   1290             if (shouldMigrateToSyntheticPasswordLocked(userId)) {
   1291                 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
   1292                         currentHandle.type, requestedQuality, userId);
   1293                 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
   1294                         requestedQuality, userId);
   1295                 return;
   1296             }
   1297         }
   1298         if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
   1299         byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
   1300                 userId);
   1301         if (enrolledHandle != null) {
   1302             CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
   1303             mStorage.writeCredentialHash(willStore, userId);
   1304             // push new secret and auth token to vold
   1305             GateKeeperResponse gkResponse = getGateKeeperService()
   1306                     .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
   1307             setUserKeyProtection(userId, credential, convertResponse(gkResponse));
   1308             fixateNewestUserKeyAuth(userId);
   1309             // Refresh the auth token
   1310             doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
   1311             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
   1312         } else {
   1313             throw new RemoteException("Failed to enroll " +
   1314                     (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
   1315                             : "pattern"));
   1316         }
   1317     }
   1318 
   1319     private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
   1320         return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
   1321     }
   1322 
   1323     @VisibleForTesting
   1324     protected void tieProfileLockToParent(int userId, String password) {
   1325         if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
   1326         byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
   1327         byte[] encryptionResult;
   1328         byte[] iv;
   1329         try {
   1330             KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
   1331             keyGenerator.init(new SecureRandom());
   1332             SecretKey secretKey = keyGenerator.generateKey();
   1333             java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
   1334             keyStore.load(null);
   1335             try {
   1336                 keyStore.setEntry(
   1337                         LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
   1338                         new java.security.KeyStore.SecretKeyEntry(secretKey),
   1339                         new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
   1340                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
   1341                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
   1342                                 .build());
   1343                 keyStore.setEntry(
   1344                         LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
   1345                         new java.security.KeyStore.SecretKeyEntry(secretKey),
   1346                         new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
   1347                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
   1348                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
   1349                                 .setUserAuthenticationRequired(true)
   1350                                 .setUserAuthenticationValidityDurationSeconds(30)
   1351                                 .setCriticalToDeviceEncryption(true)
   1352                                 .build());
   1353                 // Key imported, obtain a reference to it.
   1354                 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
   1355                         LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
   1356                 Cipher cipher = Cipher.getInstance(
   1357                         KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
   1358                                 + KeyProperties.ENCRYPTION_PADDING_NONE);
   1359                 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
   1360                 encryptionResult = cipher.doFinal(randomLockSeed);
   1361                 iv = cipher.getIV();
   1362             } finally {
   1363                 // The original key can now be discarded.
   1364                 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
   1365             }
   1366         } catch (CertificateException | UnrecoverableKeyException
   1367                 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
   1368                 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
   1369             throw new RuntimeException("Failed to encrypt key", e);
   1370         }
   1371         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
   1372         try {
   1373             if (iv.length != PROFILE_KEY_IV_SIZE) {
   1374                 throw new RuntimeException("Invalid iv length: " + iv.length);
   1375             }
   1376             outputStream.write(iv);
   1377             outputStream.write(encryptionResult);
   1378         } catch (IOException e) {
   1379             throw new RuntimeException("Failed to concatenate byte arrays", e);
   1380         }
   1381         mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
   1382     }
   1383 
   1384     private byte[] enrollCredential(byte[] enrolledHandle,
   1385             String enrolledCredential, String toEnroll, int userId)
   1386             throws RemoteException {
   1387         checkWritePermission(userId);
   1388         byte[] enrolledCredentialBytes = enrolledCredential == null
   1389                 ? null
   1390                 : enrolledCredential.getBytes();
   1391         byte[] toEnrollBytes = toEnroll == null
   1392                 ? null
   1393                 : toEnroll.getBytes();
   1394         GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
   1395                 enrolledCredentialBytes, toEnrollBytes);
   1396 
   1397         if (response == null) {
   1398             return null;
   1399         }
   1400 
   1401         byte[] hash = response.getPayload();
   1402         if (hash != null) {
   1403             setKeystorePassword(toEnroll, userId);
   1404         } else {
   1405             // Should not happen
   1406             Slog.e(TAG, "Throttled while enrolling a password");
   1407         }
   1408         return hash;
   1409     }
   1410 
   1411     private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
   1412         if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
   1413         addUserKeyAuth(userId, null, key);
   1414     }
   1415 
   1416     private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
   1417             throws RemoteException {
   1418         if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
   1419         if (vcr == null) {
   1420             throw new RemoteException("Null response verifying a credential we just set");
   1421         }
   1422         if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
   1423             throw new RemoteException("Non-OK response verifying a credential we just set: "
   1424                     + vcr.getResponseCode());
   1425         }
   1426         byte[] token = vcr.getPayload();
   1427         if (token == null) {
   1428             throw new RemoteException("Empty payload verifying a credential we just set");
   1429         }
   1430         addUserKeyAuth(userId, token, secretFromCredential(credential));
   1431     }
   1432 
   1433     private void clearUserKeyProtection(int userId) throws RemoteException {
   1434         if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
   1435         addUserKeyAuth(userId, null, null);
   1436     }
   1437 
   1438     private static byte[] secretFromCredential(String credential) throws RemoteException {
   1439         try {
   1440             MessageDigest digest = MessageDigest.getInstance("SHA-512");
   1441             // Personalize the hash
   1442             byte[] personalization = "Android FBE credential hash"
   1443                     .getBytes(StandardCharsets.UTF_8);
   1444             // Pad it to the block size of the hash function
   1445             personalization = Arrays.copyOf(personalization, 128);
   1446             digest.update(personalization);
   1447             digest.update(credential.getBytes(StandardCharsets.UTF_8));
   1448             return digest.digest();
   1449         } catch (NoSuchAlgorithmException e) {
   1450             throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
   1451         }
   1452     }
   1453 
   1454     private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
   1455             throws RemoteException {
   1456         final UserInfo userInfo = mUserManager.getUserInfo(userId);
   1457         final IStorageManager storageManager = mInjector.getStorageManager();
   1458         final long callingId = Binder.clearCallingIdentity();
   1459         try {
   1460             storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
   1461         } finally {
   1462             Binder.restoreCallingIdentity(callingId);
   1463         }
   1464     }
   1465 
   1466     private void fixateNewestUserKeyAuth(int userId)
   1467             throws RemoteException {
   1468         if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
   1469         final IStorageManager storageManager = mInjector.getStorageManager();
   1470         final long callingId = Binder.clearCallingIdentity();
   1471         try {
   1472             storageManager.fixateNewestUserKeyAuth(userId);
   1473         } finally {
   1474             Binder.restoreCallingIdentity(callingId);
   1475         }
   1476     }
   1477 
   1478     @Override
   1479     public void resetKeyStore(int userId) throws RemoteException {
   1480         checkWritePermission(userId);
   1481         if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
   1482         int managedUserId = -1;
   1483         String managedUserDecryptedPassword = null;
   1484         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
   1485         for (UserInfo pi : profiles) {
   1486             // Unlock managed profile with unified lock
   1487             if (pi.isManagedProfile()
   1488                     && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
   1489                     && mStorage.hasChildProfileLock(pi.id)) {
   1490                 try {
   1491                     if (managedUserId == -1) {
   1492                         managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
   1493                         managedUserId = pi.id;
   1494                     } else {
   1495                         // Should not happen
   1496                         Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
   1497                                 + ", uid2:" + pi.id);
   1498                     }
   1499                 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   1500                         | NoSuchAlgorithmException | NoSuchPaddingException
   1501                         | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1502                         | BadPaddingException | CertificateException | IOException e) {
   1503                     Slog.e(TAG, "Failed to decrypt child profile key", e);
   1504                 }
   1505             }
   1506         }
   1507         try {
   1508             // Clear all the users credentials could have been installed in for this user.
   1509             for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
   1510                 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
   1511                     mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
   1512                 }
   1513             }
   1514         } finally {
   1515             if (managedUserId != -1 && managedUserDecryptedPassword != null) {
   1516                 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
   1517                 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
   1518             }
   1519         }
   1520     }
   1521 
   1522     @Override
   1523     public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
   1524             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1525         checkPasswordReadPermission(userId);
   1526         return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
   1527     }
   1528 
   1529     @Override
   1530     public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
   1531             int userId) throws RemoteException {
   1532         checkPasswordReadPermission(userId);
   1533         return doVerifyCredential(credential, type, true, challenge, userId,
   1534                 null /* progressCallback */);
   1535     }
   1536 
   1537     /**
   1538      * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
   1539      * format.
   1540      */
   1541     private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
   1542             boolean hasChallenge, long challenge, int userId,
   1543             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1544         if (TextUtils.isEmpty(credential)) {
   1545             throw new IllegalArgumentException("Credential can't be null or empty");
   1546         }
   1547         if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
   1548                 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
   1549             Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
   1550             return VerifyCredentialResponse.ERROR;
   1551         }
   1552         VerifyCredentialResponse response = null;
   1553         response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
   1554                 userId, progressCallback);
   1555         // The user employs synthetic password based credential.
   1556         if (response != null) {
   1557             return response;
   1558         }
   1559 
   1560         if (userId == USER_FRP) {
   1561             Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
   1562             return VerifyCredentialResponse.ERROR;
   1563         }
   1564 
   1565         final CredentialHash storedHash = mStorage.readCredentialHash(userId);
   1566         if (storedHash.type != credentialType) {
   1567             Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
   1568                     + " stored: " + storedHash.type + " passed in: " + credentialType);
   1569             return VerifyCredentialResponse.ERROR;
   1570         }
   1571 
   1572         boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
   1573                 && storedHash.isBaseZeroPattern;
   1574 
   1575         String credentialToVerify;
   1576         if (shouldReEnrollBaseZero) {
   1577             credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
   1578         } else {
   1579             credentialToVerify = credential;
   1580         }
   1581 
   1582         response = verifyCredential(userId, storedHash, credentialToVerify,
   1583                 hasChallenge, challenge, progressCallback);
   1584 
   1585         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
   1586             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
   1587             if (shouldReEnrollBaseZero) {
   1588                 setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
   1589                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
   1590             }
   1591         }
   1592 
   1593         return response;
   1594     }
   1595 
   1596     @Override
   1597     public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
   1598             long challenge, int userId) throws RemoteException {
   1599         checkPasswordReadPermission(userId);
   1600         if (!isManagedProfileWithUnifiedLock(userId)) {
   1601             throw new RemoteException("User id must be managed profile with unified lock");
   1602         }
   1603         final int parentProfileId = mUserManager.getProfileParent(userId).id;
   1604         // Unlock parent by using parent's challenge
   1605         final VerifyCredentialResponse parentResponse = doVerifyCredential(
   1606                 credential,
   1607                 type,
   1608                 true /* hasChallenge */,
   1609                 challenge,
   1610                 parentProfileId,
   1611                 null /* progressCallback */);
   1612         if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
   1613             // Failed, just return parent's response
   1614             return parentResponse;
   1615         }
   1616 
   1617         try {
   1618             // Unlock work profile, and work profile with unified lock must use password only
   1619             return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
   1620                     LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
   1621                     true,
   1622                     challenge,
   1623                     userId, null /* progressCallback */);
   1624         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   1625                 | NoSuchAlgorithmException | NoSuchPaddingException
   1626                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1627                 | BadPaddingException | CertificateException | IOException e) {
   1628             Slog.e(TAG, "Failed to decrypt child profile key", e);
   1629             throw new RemoteException("Unable to get tied profile token");
   1630         }
   1631     }
   1632 
   1633     /**
   1634      * Lowest-level credential verification routine that talks to GateKeeper. If verification
   1635      * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
   1636      * hash to GK.
   1637      */
   1638     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
   1639             String credential, boolean hasChallenge, long challenge,
   1640             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1641         if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
   1642             // don't need to pass empty credentials to GateKeeper
   1643             return VerifyCredentialResponse.OK;
   1644         }
   1645 
   1646         if (storedHash == null || TextUtils.isEmpty(credential)) {
   1647             return VerifyCredentialResponse.ERROR;
   1648         }
   1649 
   1650         // We're potentially going to be doing a bunch of disk I/O below as part
   1651         // of unlocking the user, so yell if calling from the main thread.
   1652         StrictMode.noteDiskRead();
   1653 
   1654         if (storedHash.version == CredentialHash.VERSION_LEGACY) {
   1655             final byte[] hash;
   1656             if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
   1657                 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
   1658             } else {
   1659                 hash = mLockPatternUtils.passwordToHash(credential, userId);
   1660             }
   1661             if (Arrays.equals(hash, storedHash.hash)) {
   1662                 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
   1663                     unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
   1664                 } else {
   1665                     unlockKeystore(credential, userId);
   1666                 }
   1667                 // Users with legacy credentials don't have credential-backed
   1668                 // FBE keys, so just pass through a fake token/secret
   1669                 Slog.i(TAG, "Unlocking user with fake token: " + userId);
   1670                 final byte[] fakeToken = String.valueOf(userId).getBytes();
   1671                 unlockUser(userId, fakeToken, fakeToken);
   1672 
   1673                 // migrate credential to GateKeeper
   1674                 setLockCredentialInternal(credential, storedHash.type, null,
   1675                         storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
   1676                                 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
   1677                                 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
   1678                                 /* TODO(roosa): keep the same password quality */, userId);
   1679                 if (!hasChallenge) {
   1680                     notifyActivePasswordMetricsAvailable(credential, userId);
   1681                     return VerifyCredentialResponse.OK;
   1682                 }
   1683                 // Fall through to get the auth token. Technically this should never happen,
   1684                 // as a user that had a legacy credential would have to unlock their device
   1685                 // before getting to a flow with a challenge, but supporting for consistency.
   1686             } else {
   1687                 return VerifyCredentialResponse.ERROR;
   1688             }
   1689         }
   1690         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
   1691                 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
   1692         VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
   1693         boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
   1694 
   1695         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
   1696 
   1697             // credential has matched
   1698 
   1699             if (progressCallback != null) {
   1700                 progressCallback.onCredentialVerified();
   1701             }
   1702             notifyActivePasswordMetricsAvailable(credential, userId);
   1703             unlockKeystore(credential, userId);
   1704 
   1705             Slog.i(TAG, "Unlocking user " + userId + " with token length "
   1706                     + response.getPayload().length);
   1707             unlockUser(userId, response.getPayload(), secretFromCredential(credential));
   1708 
   1709             if (isManagedProfileWithSeparatedLock(userId)) {
   1710                 TrustManager trustManager =
   1711                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
   1712                 trustManager.setDeviceLockedForUser(userId, false);
   1713             }
   1714             int reEnrollQuality = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
   1715                     ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
   1716                     : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
   1717                     /* TODO(roosa): keep the same password quality */;
   1718             if (shouldReEnroll) {
   1719                 setLockCredentialInternal(credential, storedHash.type, credential,
   1720                         reEnrollQuality, userId);
   1721             } else {
   1722                 // Now that we've cleared of all required GK migration, let's do the final
   1723                 // migration to synthetic password.
   1724                 synchronized (mSpManager) {
   1725                     if (shouldMigrateToSyntheticPasswordLocked(userId)) {
   1726                         AuthenticationToken auth = initializeSyntheticPasswordLocked(
   1727                                 storedHash.hash, credential, storedHash.type, reEnrollQuality,
   1728                                 userId);
   1729                         activateEscrowTokens(auth, userId);
   1730                     }
   1731                 }
   1732             }
   1733         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
   1734             if (response.getTimeout() > 0) {
   1735                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
   1736             }
   1737         }
   1738 
   1739         return response;
   1740     }
   1741 
   1742     /**
   1743      * Call this method to notify DPMS regarding the latest password metric. This should be called
   1744      * when the user is authenticating or when a new password is being set.
   1745      */
   1746     private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
   1747         final PasswordMetrics metrics;
   1748         if (password == null) {
   1749             metrics = new PasswordMetrics();
   1750         } else {
   1751             metrics = PasswordMetrics.computeForPassword(password);
   1752             metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
   1753         }
   1754 
   1755         // Asynchronous to avoid dead lock
   1756         mHandler.post(() -> {
   1757             DevicePolicyManager dpm = (DevicePolicyManager)
   1758                     mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
   1759             dpm.setActivePasswordState(metrics, userId);
   1760         });
   1761     }
   1762 
   1763     /**
   1764      * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
   1765      * reporting the password changed.
   1766      */
   1767     private void notifyPasswordChanged(@UserIdInt int userId) {
   1768         // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
   1769         mHandler.post(() -> {
   1770             DevicePolicyManager dpm = (DevicePolicyManager)
   1771                     mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
   1772             dpm.reportPasswordChanged(userId);
   1773         });
   1774     }
   1775 
   1776     @Override
   1777     public boolean checkVoldPassword(int userId) throws RemoteException {
   1778         if (!mFirstCallToVold) {
   1779             return false;
   1780         }
   1781         mFirstCallToVold = false;
   1782 
   1783         checkPasswordReadPermission(userId);
   1784 
   1785         // There's no guarantee that this will safely connect, but if it fails
   1786         // we will simply show the lock screen when we shouldn't, so relatively
   1787         // benign. There is an outside chance something nasty would happen if
   1788         // this service restarted before vold stales out the password in this
   1789         // case. The nastiness is limited to not showing the lock screen when
   1790         // we should, within the first minute of decrypting the phone if this
   1791         // service can't connect to vold, it restarts, and then the new instance
   1792         // does successfully connect.
   1793         final IStorageManager service = mInjector.getStorageManager();
   1794         String password;
   1795         long identity = Binder.clearCallingIdentity();
   1796         try {
   1797             password = service.getPassword();
   1798             service.clearPassword();
   1799         } finally {
   1800             Binder.restoreCallingIdentity(identity);
   1801         }
   1802         if (password == null) {
   1803             return false;
   1804         }
   1805 
   1806         try {
   1807             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
   1808                 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
   1809                         null /* progressCallback */)
   1810                                 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
   1811                     return true;
   1812                 }
   1813             }
   1814         } catch (Exception e) {
   1815         }
   1816 
   1817         try {
   1818             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
   1819                 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
   1820                         null /* progressCallback */)
   1821                                 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
   1822                     return true;
   1823                 }
   1824             }
   1825         } catch (Exception e) {
   1826         }
   1827 
   1828         return false;
   1829     }
   1830 
   1831     private void removeUser(int userId, boolean unknownUser) {
   1832         mSpManager.removeUser(userId);
   1833         mStorage.removeUser(userId);
   1834         mStrongAuth.removeUser(userId);
   1835 
   1836         final KeyStore ks = KeyStore.getInstance();
   1837         ks.onUserRemoved(userId);
   1838 
   1839         try {
   1840             final IGateKeeperService gk = getGateKeeperService();
   1841             if (gk != null) {
   1842                 gk.clearSecureUserId(userId);
   1843             }
   1844         } catch (RemoteException ex) {
   1845             Slog.w(TAG, "unable to clear GK secure user id");
   1846         }
   1847         if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
   1848             removeKeystoreProfileKey(userId);
   1849         }
   1850     }
   1851 
   1852     private void removeKeystoreProfileKey(int targetUserId) {
   1853         if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
   1854         try {
   1855             java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
   1856             keyStore.load(null);
   1857             keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
   1858             keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
   1859         } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
   1860                 | IOException e) {
   1861             // We have tried our best to remove all keys
   1862             Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
   1863         }
   1864     }
   1865 
   1866     @Override
   1867     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
   1868         checkPasswordReadPermission(UserHandle.USER_ALL);
   1869         mStrongAuth.registerStrongAuthTracker(tracker);
   1870     }
   1871 
   1872     @Override
   1873     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
   1874         checkPasswordReadPermission(UserHandle.USER_ALL);
   1875         mStrongAuth.unregisterStrongAuthTracker(tracker);
   1876     }
   1877 
   1878     @Override
   1879     public void requireStrongAuth(int strongAuthReason, int userId) {
   1880         checkWritePermission(userId);
   1881         mStrongAuth.requireStrongAuth(strongAuthReason, userId);
   1882     }
   1883 
   1884     @Override
   1885     public void userPresent(int userId) {
   1886         checkWritePermission(userId);
   1887         mStrongAuth.reportUnlock(userId);
   1888     }
   1889 
   1890     @Override
   1891     public int getStrongAuthForUser(int userId) {
   1892         checkPasswordReadPermission(userId);
   1893         return mStrongAuthTracker.getStrongAuthForUser(userId);
   1894     }
   1895 
   1896     private boolean isCallerShell() {
   1897         final int callingUid = Binder.getCallingUid();
   1898         return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
   1899     }
   1900 
   1901     private void enforceShell() {
   1902         if (!isCallerShell()) {
   1903             throw new SecurityException("Caller must be shell");
   1904         }
   1905     }
   1906 
   1907     @Override
   1908     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
   1909             String[] args, ShellCallback callback, ResultReceiver resultReceiver)
   1910             throws RemoteException {
   1911         enforceShell();
   1912         final long origId = Binder.clearCallingIdentity();
   1913         try {
   1914             (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
   1915                     this, in, out, err, args, callback, resultReceiver);
   1916         } finally {
   1917             Binder.restoreCallingIdentity(origId);
   1918         }
   1919     }
   1920 
   1921     private static final String[] VALID_SETTINGS = new String[] {
   1922             LockPatternUtils.LOCKOUT_PERMANENT_KEY,
   1923             LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
   1924             LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
   1925             LockPatternUtils.PASSWORD_TYPE_KEY,
   1926             LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
   1927             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
   1928             LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
   1929             LockPatternUtils.LOCKSCREEN_OPTIONS,
   1930             LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
   1931             LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
   1932             LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
   1933             LockPatternUtils.PASSWORD_HISTORY_KEY,
   1934             Secure.LOCK_PATTERN_ENABLED,
   1935             Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
   1936             Secure.LOCK_PATTERN_VISIBLE,
   1937             Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
   1938     };
   1939 
   1940     // Reading these settings needs the contacts permission
   1941     private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
   1942             Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
   1943             Secure.LOCK_SCREEN_OWNER_INFO
   1944     };
   1945 
   1946     // Reading these settings needs the same permission as checking the password
   1947     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
   1948             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
   1949             LockPatternUtils.PASSWORD_HISTORY_KEY,
   1950             LockPatternUtils.PASSWORD_TYPE_KEY,
   1951             SEPARATE_PROFILE_CHALLENGE_KEY
   1952     };
   1953 
   1954     private static final String[] SETTINGS_TO_BACKUP = new String[] {
   1955             Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
   1956             Secure.LOCK_SCREEN_OWNER_INFO,
   1957             Secure.LOCK_PATTERN_VISIBLE,
   1958             LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
   1959     };
   1960 
   1961     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
   1962         @Override
   1963         public void binderDied() {
   1964             mGateKeeperService.asBinder().unlinkToDeath(this, 0);
   1965             mGateKeeperService = null;
   1966         }
   1967     }
   1968 
   1969     protected synchronized IGateKeeperService getGateKeeperService()
   1970             throws RemoteException {
   1971         if (mGateKeeperService != null) {
   1972             return mGateKeeperService;
   1973         }
   1974 
   1975         final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
   1976         if (service != null) {
   1977             service.linkToDeath(new GateKeeperDiedRecipient(), 0);
   1978             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
   1979             return mGateKeeperService;
   1980         }
   1981 
   1982         Slog.e(TAG, "Unable to acquire GateKeeperService");
   1983         return null;
   1984     }
   1985 
   1986     /**
   1987      * Precondition: vold and keystore unlocked.
   1988      *
   1989      * Create new synthetic password, set up synthetic password blob protected by the supplied
   1990      * user credential, and make the newly-created SP blob active.
   1991      *
   1992      * The invariant under a synthetic password is:
   1993      * 1. If user credential exists, then both vold and keystore and protected with keys derived
   1994      *     from the synthetic password.
   1995      * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
   1996      *     make it consistent with current behaviour. It also allows ActivityManager to call
   1997      *     unlockUser() with empty secret.
   1998      * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
   1999      *     whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
   2000      *     lockscreen PIN, we still maintain the existing synthetic password in a password blob
   2001      *     protected by a default PIN. The only exception is when the DPC performs an untrusted
   2002      *     credential change, in which case we have no way to derive the existing synthetic password
   2003      *     and has to create a new one.
   2004      * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
   2005      *     clears/re-creates his lockscreen PIN.
   2006      *
   2007      *
   2008      * Different cases of calling this method:
   2009      * 1. credentialHash != null
   2010      *     This implies credential != null, a new SP blob will be provisioned, and existing SID
   2011      *     migrated to associate with the new SP.
   2012      *     This happens during a normal migration case when the user currently has password.
   2013      *
   2014      * 2. credentialhash == null and credential == null
   2015      *     A new SP blob and a new SID will be created, while the user has no credentials.
   2016      *     This can happens when we are activating an escrow token on a unsecured device, during
   2017      *     which we want to create the SP structure with an empty user credential.
   2018      *
   2019      * 3. credentialhash == null and credential != null
   2020      *     This is the untrusted credential reset, OR the user sets a new lockscreen password
   2021      *     FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
   2022      */
   2023     @VisibleForTesting
   2024     protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
   2025             String credential, int credentialType, int requestedQuality,
   2026             int userId) throws RemoteException {
   2027         Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
   2028         AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(getGateKeeperService(),
   2029                 credentialHash, credential, userId);
   2030         if (auth == null) {
   2031             Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
   2032             return null;
   2033         }
   2034         long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
   2035                 credential, credentialType, auth, requestedQuality, userId);
   2036         if (credential != null) {
   2037             if (credentialHash == null) {
   2038                 // Since when initializing SP, we didn't provide an existing password handle
   2039                 // for it to migrate SID, we need to create a new SID for the user.
   2040                 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
   2041             }
   2042             mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
   2043             setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
   2044             setKeystorePassword(auth.deriveKeyStorePassword(), userId);
   2045         } else {
   2046             clearUserKeyProtection(userId);
   2047             setKeystorePassword(null, userId);
   2048             getGateKeeperService().clearSecureUserId(userId);
   2049         }
   2050         fixateNewestUserKeyAuth(userId);
   2051         setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
   2052         return auth;
   2053     }
   2054 
   2055     private long getSyntheticPasswordHandleLocked(int userId) {
   2056         return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY,
   2057                 SyntheticPasswordManager.DEFAULT_HANDLE, userId);
   2058     }
   2059 
   2060     private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
   2061         if (userId == USER_FRP) {
   2062             final int type = mStorage.readPersistentDataBlock().type;
   2063             return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
   2064         }
   2065         long handle = getSyntheticPasswordHandleLocked(userId);
   2066         // This is a global setting
   2067         long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
   2068                 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
   2069       return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
   2070     }
   2071 
   2072     @VisibleForTesting
   2073     protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
   2074         long handle = getSyntheticPasswordHandleLocked(userId);
   2075         // This is a global setting
   2076         long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
   2077                 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
   2078         return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
   2079     }
   2080 
   2081     private void enableSyntheticPasswordLocked() throws RemoteException {
   2082         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
   2083     }
   2084 
   2085     private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
   2086             credentialType, boolean hasChallenge, long challenge, int userId,
   2087             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   2088         if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
   2089         if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
   2090             userCredential = null;
   2091         }
   2092 
   2093         final AuthenticationResult authResult;
   2094         VerifyCredentialResponse response;
   2095         synchronized (mSpManager) {
   2096             if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
   2097                 return null;
   2098             }
   2099             if (userId == USER_FRP) {
   2100                 return mSpManager.verifyFrpCredential(getGateKeeperService(),
   2101                         userCredential, credentialType, progressCallback);
   2102             }
   2103 
   2104             long handle = getSyntheticPasswordHandleLocked(userId);
   2105             authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
   2106                     getGateKeeperService(), handle, userCredential, userId);
   2107 
   2108             if (authResult.credentialType != credentialType) {
   2109                 Slog.e(TAG, "Credential type mismatch.");
   2110                 return VerifyCredentialResponse.ERROR;
   2111             }
   2112             response = authResult.gkResponse;
   2113             // credential has matched
   2114             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
   2115                 // perform verifyChallenge with synthetic password which generates the real GK auth
   2116                 // token and response for the current user
   2117                 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
   2118                         challenge, userId);
   2119                 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
   2120                     // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
   2121                     // match the recorded GK password handle.
   2122                     Slog.wtf(TAG, "verifyChallenge with SP failed.");
   2123                     return VerifyCredentialResponse.ERROR;
   2124                 }
   2125             }
   2126         }
   2127 
   2128         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
   2129             if (progressCallback != null) {
   2130                 progressCallback.onCredentialVerified();
   2131             }
   2132             notifyActivePasswordMetricsAvailable(userCredential, userId);
   2133             unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
   2134 
   2135             final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
   2136             Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
   2137             unlockUser(userId, null, secret);
   2138 
   2139             activateEscrowTokens(authResult.authToken, userId);
   2140 
   2141             if (isManagedProfileWithSeparatedLock(userId)) {
   2142                 TrustManager trustManager =
   2143                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
   2144                 trustManager.setDeviceLockedForUser(userId, false);
   2145             }
   2146             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
   2147         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
   2148             if (response.getTimeout() > 0) {
   2149                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
   2150             }
   2151         }
   2152 
   2153         return response;
   2154     }
   2155 
   2156     /**
   2157      * Change the user's lockscreen password by creating a new SP blob and update the handle, based
   2158      * on an existing authentication token. Even though a new SP blob is created, the underlying
   2159      * synthetic password is never changed.
   2160      *
   2161      * When clearing credential, we keep the SP unchanged, but clear its password handle so its
   2162      * SID is gone. We also clear password from (software-based) keystore and vold, which will be
   2163      * added back when new password is set in future.
   2164      */
   2165     private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
   2166             AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
   2167         if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
   2168         long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
   2169                 credential, credentialType, auth, requestedQuality, userId);
   2170         final Map<Integer, String> profilePasswords;
   2171         if (credential != null) {
   2172             // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
   2173             profilePasswords = null;
   2174 
   2175             if (mSpManager.hasSidForUser(userId)) {
   2176                 // We are changing password of a secured device, nothing more needed as
   2177                 // createPasswordBasedSyntheticPassword has already taken care of maintaining
   2178                 // the password handle and SID unchanged.
   2179 
   2180                 //refresh auth token
   2181                 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
   2182             } else {
   2183                 // A new password is set on a previously-unsecured device, we need to generate
   2184                 // a new SID, and re-add keys to vold and keystore.
   2185                 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
   2186                 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
   2187                 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
   2188                 fixateNewestUserKeyAuth(userId);
   2189                 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
   2190             }
   2191         } else {
   2192             // Cache all profile password if they use unified work challenge. This will later be
   2193             // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
   2194             profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
   2195 
   2196             // we are clearing password of a secured device, so need to nuke SID as well.
   2197             mSpManager.clearSidForUser(userId);
   2198             getGateKeeperService().clearSecureUserId(userId);
   2199             // Clear key from vold so ActivityManager can just unlock the user with empty secret
   2200             // during boot.
   2201             clearUserKeyProtection(userId);
   2202             fixateNewestUserKeyAuth(userId);
   2203             setKeystorePassword(null, userId);
   2204         }
   2205         setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
   2206         synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
   2207 
   2208         notifyActivePasswordMetricsAvailable(credential, userId);
   2209         return newHandle;
   2210     }
   2211 
   2212     private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
   2213             String savedCredential, int requestedQuality, int userId) throws RemoteException {
   2214         if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
   2215         if (isManagedProfileWithUnifiedLock(userId)) {
   2216             // get credential from keystore when managed profile has unified lock
   2217             try {
   2218                 savedCredential = getDecryptedPasswordForTiedProfile(userId);
   2219             } catch (FileNotFoundException e) {
   2220                 Slog.i(TAG, "Child profile key not found");
   2221             } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   2222                     | NoSuchAlgorithmException | NoSuchPaddingException
   2223                     | InvalidAlgorithmParameterException | IllegalBlockSizeException
   2224                     | BadPaddingException | CertificateException | IOException e) {
   2225                 Slog.e(TAG, "Failed to decrypt child profile key", e);
   2226             }
   2227         }
   2228         long handle = getSyntheticPasswordHandleLocked(userId);
   2229         AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
   2230                 getGateKeeperService(), handle, savedCredential, userId);
   2231         VerifyCredentialResponse response = authResult.gkResponse;
   2232         AuthenticationToken auth = authResult.authToken;
   2233 
   2234         // If existing credential is provided, then it must match.
   2235         if (savedCredential != null && auth == null) {
   2236             throw new RemoteException("Failed to enroll " +
   2237                     (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
   2238                             : "pattern"));
   2239         }
   2240 
   2241         if (auth != null) {
   2242             // We are performing a trusted credential change i.e. a correct existing credential
   2243             // is provided
   2244             setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
   2245                     userId);
   2246             mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
   2247         } else if (response != null
   2248                 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){
   2249             // We are performing an untrusted credential change i.e. by DevicePolicyManager.
   2250             // So provision a new SP and SID. This would invalidate existing escrow tokens.
   2251             // Still support this for now but this flow will be removed in the next release.
   2252 
   2253             Slog.w(TAG, "Untrusted credential change invoked");
   2254             initializeSyntheticPasswordLocked(null, credential, credentialType, requestedQuality,
   2255                     userId);
   2256             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
   2257             mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
   2258 
   2259             notifyActivePasswordMetricsAvailable(credential, userId);
   2260         } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
   2261             Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
   2262                     (response != null ? "rate limit exceeded" : "failed"));
   2263             return;
   2264         }
   2265     }
   2266 
   2267     @Override
   2268     public long addEscrowToken(byte[] token, int userId) throws RemoteException {
   2269         ensureCallerSystemUid();
   2270         if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
   2271         synchronized (mSpManager) {
   2272             enableSyntheticPasswordLocked();
   2273             // Migrate to synthetic password based credentials if the user has no password,
   2274             // the token can then be activated immediately.
   2275             AuthenticationToken auth = null;
   2276             if (!isUserSecure(userId)) {
   2277                 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
   2278                     auth = initializeSyntheticPasswordLocked(null, null,
   2279                             LockPatternUtils.CREDENTIAL_TYPE_NONE,
   2280                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
   2281                 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
   2282                     long pwdHandle = getSyntheticPasswordHandleLocked(userId);
   2283                     auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
   2284                             pwdHandle, null, userId).authToken;
   2285                 }
   2286             }
   2287             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
   2288                 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
   2289                 if (!mSpManager.hasEscrowData(userId)) {
   2290                     throw new SecurityException("Escrow token is disabled on the current user");
   2291                 }
   2292             }
   2293             long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
   2294             if (auth != null) {
   2295                 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
   2296             }
   2297             return handle;
   2298         }
   2299     }
   2300 
   2301     private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
   2302         if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
   2303         synchronized (mSpManager) {
   2304             disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
   2305             for (long handle : mSpManager.getPendingTokensForUser(userId)) {
   2306                 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
   2307                 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
   2308             }
   2309         }
   2310     }
   2311 
   2312     @Override
   2313     public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
   2314         ensureCallerSystemUid();
   2315         synchronized (mSpManager) {
   2316             return mSpManager.existsHandle(handle, userId);
   2317         }
   2318     }
   2319 
   2320     @Override
   2321     public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
   2322         ensureCallerSystemUid();
   2323         synchronized (mSpManager) {
   2324             if (handle == getSyntheticPasswordHandleLocked(userId)) {
   2325                 Slog.w(TAG, "Cannot remove password handle");
   2326                 return false;
   2327             }
   2328             if (mSpManager.removePendingToken(handle, userId)) {
   2329                 return true;
   2330             }
   2331             if (mSpManager.existsHandle(handle, userId)) {
   2332                 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
   2333                 return true;
   2334             } else {
   2335                 return false;
   2336             }
   2337         }
   2338     }
   2339 
   2340     @Override
   2341     public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
   2342             byte[] token, int requestedQuality, int userId) throws RemoteException {
   2343         ensureCallerSystemUid();
   2344         boolean result;
   2345         synchronized (mSpManager) {
   2346             if (!mSpManager.hasEscrowData(userId)) {
   2347                 throw new SecurityException("Escrow token is disabled on the current user");
   2348             }
   2349             result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
   2350                     requestedQuality, userId);
   2351         }
   2352         if (result) {
   2353             synchronized (mSeparateChallengeLock) {
   2354                 setSeparateProfileChallengeEnabled(userId, true, null);
   2355             }
   2356             notifyPasswordChanged(userId);
   2357         }
   2358         return result;
   2359     }
   2360 
   2361     private boolean setLockCredentialWithTokenInternal(String credential, int type,
   2362             long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
   2363         synchronized (mSpManager) {
   2364             AuthenticationResult result = mSpManager.unwrapTokenBasedSyntheticPassword(
   2365                     getGateKeeperService(), tokenHandle, token, userId);
   2366             if (result.authToken == null) {
   2367                 Slog.w(TAG, "Invalid escrow token supplied");
   2368                 return false;
   2369             }
   2370             if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
   2371                 // Most likely, an untrusted credential reset happened in the past which
   2372                 // changed the synthetic password
   2373                 Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
   2374                         + "verification.");
   2375                 return false;
   2376             }
   2377             // Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable()
   2378             // called by setLockCredentialWithAuthTokenLocked().
   2379             // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
   2380             setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
   2381             long oldHandle = getSyntheticPasswordHandleLocked(userId);
   2382             setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
   2383                     requestedQuality, userId);
   2384             mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
   2385             return true;
   2386         }
   2387     }
   2388 
   2389     @Override
   2390     public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
   2391             throws RemoteException {
   2392         ensureCallerSystemUid();
   2393         AuthenticationResult authResult;
   2394         synchronized (mSpManager) {
   2395             if (!mSpManager.hasEscrowData(userId)) {
   2396                 throw new SecurityException("Escrow token is disabled on the current user");
   2397             }
   2398             authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
   2399                     tokenHandle, token, userId);
   2400             if (authResult.authToken == null) {
   2401                 Slog.w(TAG, "Invalid escrow token supplied");
   2402                 return;
   2403             }
   2404         }
   2405         unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
   2406     }
   2407 
   2408     @Override
   2409     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
   2410         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
   2411 
   2412         pw.println("Current lock settings service state:");
   2413         pw.println(String.format("SP Enabled = %b",
   2414                 mLockPatternUtils.isSyntheticPasswordEnabled()));
   2415 
   2416         List<UserInfo> users = mUserManager.getUsers();
   2417         for (int user = 0; user < users.size(); user++) {
   2418             final int userId = users.get(user).id;
   2419             pw.println("    User " + userId);
   2420             synchronized (mSpManager) {
   2421                 pw.println(String.format("        SP Handle = %x",
   2422                         getSyntheticPasswordHandleLocked(userId)));
   2423             }
   2424             try {
   2425                 pw.println(String.format("        SID = %x",
   2426                         getGateKeeperService().getSecureUserId(userId)));
   2427             } catch (RemoteException e) {
   2428                 // ignore.
   2429             }
   2430         }
   2431     }
   2432 
   2433     private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
   2434         long ident = Binder.clearCallingIdentity();
   2435         try {
   2436             // Managed profile should have escrow enabled
   2437             if (mUserManager.getUserInfo(userId).isManagedProfile()) {
   2438                 Slog.i(TAG, "Managed profile can have escrow token");
   2439                 return;
   2440             }
   2441             DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
   2442             // Devices with Device Owner should have escrow enabled on all users.
   2443             if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
   2444                 Slog.i(TAG, "Corp-owned device can have escrow token");
   2445                 return;
   2446             }
   2447             // We could also have a profile owner on the given (non-managed) user for unicorn cases
   2448             if (dpm.getProfileOwnerAsUser(userId) != null) {
   2449                 Slog.i(TAG, "User with profile owner can have escrow token");
   2450                 return;
   2451             }
   2452             // If the device is yet to be provisioned (still in SUW), there is still
   2453             // a chance that Device Owner will be set on the device later, so postpone
   2454             // disabling escrow token for now.
   2455             if (!dpm.isDeviceProvisioned()) {
   2456                 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
   2457                 return;
   2458             }
   2459 
   2460             // Escrow tokens are enabled on automotive builds.
   2461             if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
   2462                 return;
   2463             }
   2464 
   2465             // Disable escrow token permanently on all other device/user types.
   2466             Slog.i(TAG, "Disabling escrow token on user " + userId);
   2467             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
   2468                 mSpManager.destroyEscrowData(userId);
   2469             }
   2470         } catch (RemoteException e) {
   2471             Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
   2472         } finally {
   2473             Binder.restoreCallingIdentity(ident);
   2474         }
   2475     }
   2476 
   2477     private void ensureCallerSystemUid() throws SecurityException {
   2478         final int callingUid = mInjector.binderGetCallingUid();
   2479         if (callingUid != Process.SYSTEM_UID) {
   2480             throw new SecurityException("Only system can call this API.");
   2481         }
   2482     }
   2483 
   2484     private class DeviceProvisionedObserver extends ContentObserver {
   2485         private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
   2486                 Settings.Global.DEVICE_PROVISIONED);
   2487 
   2488         private boolean mRegistered;
   2489 
   2490         public DeviceProvisionedObserver() {
   2491             super(null);
   2492         }
   2493 
   2494         @Override
   2495         public void onChange(boolean selfChange, Uri uri) {
   2496             if (mDeviceProvisionedUri.equals(uri)) {
   2497                 updateRegistration();
   2498 
   2499                 if (isProvisioned()) {
   2500                     Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
   2501                     reportDeviceSetupComplete();
   2502                     clearFrpCredentialIfOwnerNotSecure();
   2503                 }
   2504             }
   2505         }
   2506 
   2507         public void onSystemReady() {
   2508             if (frpCredentialEnabled(mContext)) {
   2509                 updateRegistration();
   2510             } else {
   2511                 // If we don't intend to use frpCredentials and we're not provisioned yet, send
   2512                 // deviceSetupComplete immediately, so gatekeeper can discard any lingering
   2513                 // credentials immediately.
   2514                 if (!isProvisioned()) {
   2515                     Slog.i(TAG, "FRP credential disabled, reporting device setup complete "
   2516                             + "to Gatekeeper immediately");
   2517                     reportDeviceSetupComplete();
   2518                 }
   2519             }
   2520         }
   2521 
   2522         private void reportDeviceSetupComplete() {
   2523             try {
   2524                 getGateKeeperService().reportDeviceSetupComplete();
   2525             } catch (RemoteException e) {
   2526                 Slog.e(TAG, "Failure reporting to IGateKeeperService", e);
   2527             }
   2528         }
   2529 
   2530         /**
   2531          * Clears the FRP credential if the user that controls it does not have a secure
   2532          * lockscreen.
   2533          */
   2534         private void clearFrpCredentialIfOwnerNotSecure() {
   2535             List<UserInfo> users = mUserManager.getUsers();
   2536             for (UserInfo user : users) {
   2537                 if (userOwnsFrpCredential(mContext, user)) {
   2538                     if (!isUserSecure(user.id)) {
   2539                         mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
   2540                                 0, null);
   2541                     }
   2542                     return;
   2543                 }
   2544             }
   2545         }
   2546 
   2547         private void updateRegistration() {
   2548             boolean register = !isProvisioned();
   2549             if (register == mRegistered) {
   2550                 return;
   2551             }
   2552             if (register) {
   2553                 mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri,
   2554                         false, this);
   2555             } else {
   2556                 mContext.getContentResolver().unregisterContentObserver(this);
   2557             }
   2558             mRegistered = register;
   2559         }
   2560 
   2561         private boolean isProvisioned() {
   2562             return Settings.Global.getInt(mContext.getContentResolver(),
   2563                     Settings.Global.DEVICE_PROVISIONED, 0) != 0;
   2564         }
   2565     }
   2566 }
   2567