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