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