1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.locksettings;
18 
19 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
20 import static android.Manifest.permission.MANAGE_BIOMETRIC;
21 import static android.Manifest.permission.READ_CONTACTS;
22 import static android.content.Context.KEYGUARD_SERVICE;
23 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
24 import static android.os.UserHandle.USER_ALL;
25 
26 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
27 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
28 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
29 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
30 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
31 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
32 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
33 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
34 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
35 import static com.android.internal.widget.LockPatternUtils.USER_FRP;
36 import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
37 import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
38 
39 import android.annotation.IntDef;
40 import android.annotation.NonNull;
41 import android.annotation.Nullable;
42 import android.annotation.UserIdInt;
43 import android.app.ActivityManager;
44 import android.app.IActivityManager;
45 import android.app.KeyguardManager;
46 import android.app.Notification;
47 import android.app.NotificationManager;
48 import android.app.PendingIntent;
49 import android.app.admin.DevicePolicyManager;
50 import android.app.admin.DevicePolicyManagerInternal;
51 import android.app.admin.DeviceStateCache;
52 import android.app.admin.PasswordMetrics;
53 import android.app.trust.IStrongAuthTracker;
54 import android.app.trust.TrustManager;
55 import android.content.BroadcastReceiver;
56 import android.content.ContentResolver;
57 import android.content.Context;
58 import android.content.Intent;
59 import android.content.IntentFilter;
60 import android.content.pm.PackageManager;
61 import android.content.pm.UserInfo;
62 import android.content.res.Resources;
63 import android.database.ContentObserver;
64 import android.database.sqlite.SQLiteDatabase;
65 import android.hardware.authsecret.V1_0.IAuthSecret;
66 import android.hardware.biometrics.BiometricManager;
67 import android.hardware.face.Face;
68 import android.hardware.face.FaceManager;
69 import android.hardware.fingerprint.Fingerprint;
70 import android.hardware.fingerprint.FingerprintManager;
71 import android.net.Uri;
72 import android.os.Binder;
73 import android.os.Bundle;
74 import android.os.Handler;
75 import android.os.IBinder;
76 import android.os.IProgressListener;
77 import android.os.Process;
78 import android.os.RemoteException;
79 import android.os.ResultReceiver;
80 import android.os.ServiceManager;
81 import android.os.ShellCallback;
82 import android.os.StrictMode;
83 import android.os.SystemProperties;
84 import android.os.UserHandle;
85 import android.os.UserManager;
86 import android.os.UserManagerInternal;
87 import android.os.storage.IStorageManager;
88 import android.os.storage.StorageManager;
89 import android.provider.Settings;
90 import android.provider.Settings.Secure;
91 import android.provider.Settings.SettingNotFoundException;
92 import android.security.KeyStore;
93 import android.security.keystore.AndroidKeyStoreProvider;
94 import android.security.keystore.KeyProperties;
95 import android.security.keystore.KeyProtection;
96 import android.security.keystore.UserNotAuthenticatedException;
97 import android.security.keystore.recovery.KeyChainProtectionParams;
98 import android.security.keystore.recovery.KeyChainSnapshot;
99 import android.security.keystore.recovery.RecoveryCertPath;
100 import android.security.keystore.recovery.WrappedApplicationKey;
101 import android.service.gatekeeper.GateKeeperResponse;
102 import android.service.gatekeeper.IGateKeeperService;
103 import android.text.TextUtils;
104 import android.util.ArrayMap;
105 import android.util.ArraySet;
106 import android.util.EventLog;
107 import android.util.Slog;
108 import android.util.SparseArray;
109 
110 import com.android.internal.annotations.GuardedBy;
111 import com.android.internal.annotations.VisibleForTesting;
112 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
113 import com.android.internal.notification.SystemNotificationChannels;
114 import com.android.internal.util.DumpUtils;
115 import com.android.internal.util.IndentingPrintWriter;
116 import com.android.internal.widget.ICheckCredentialProgressCallback;
117 import com.android.internal.widget.ILockSettings;
118 import com.android.internal.widget.LockPatternUtils;
119 import com.android.internal.widget.LockSettingsInternal;
120 import com.android.internal.widget.LockscreenCredential;
121 import com.android.internal.widget.RebootEscrowListener;
122 import com.android.internal.widget.VerifyCredentialResponse;
123 import com.android.server.LocalServices;
124 import com.android.server.ServiceThread;
125 import com.android.server.SystemService;
126 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
127 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
128 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
129 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
130 import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
131 import com.android.server.wm.WindowManagerInternal;
132 
133 import libcore.util.HexEncoding;
134 
135 import java.io.ByteArrayOutputStream;
136 import java.io.FileDescriptor;
137 import java.io.FileNotFoundException;
138 import java.io.IOException;
139 import java.io.PrintWriter;
140 import java.security.GeneralSecurityException;
141 import java.security.InvalidAlgorithmParameterException;
142 import java.security.InvalidKeyException;
143 import java.security.KeyStoreException;
144 import java.security.MessageDigest;
145 import java.security.NoSuchAlgorithmException;
146 import java.security.SecureRandom;
147 import java.security.UnrecoverableKeyException;
148 import java.security.cert.CertificateException;
149 import java.text.SimpleDateFormat;
150 import java.util.ArrayList;
151 import java.util.Arrays;
152 import java.util.Date;
153 import java.util.List;
154 import java.util.Map;
155 import java.util.NoSuchElementException;
156 import java.util.Objects;
157 import java.util.Set;
158 import java.util.concurrent.CountDownLatch;
159 import java.util.concurrent.TimeUnit;
160 
161 import javax.crypto.BadPaddingException;
162 import javax.crypto.Cipher;
163 import javax.crypto.IllegalBlockSizeException;
164 import javax.crypto.KeyGenerator;
165 import javax.crypto.NoSuchPaddingException;
166 import javax.crypto.SecretKey;
167 import javax.crypto.spec.GCMParameterSpec;
168 
169 /**
170  * Keeps the lock pattern/password data and related settings for each user. Used by
171  * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
172  * lockscreen information for secondary users.
173  *
174  * @hide
175  */
176 public class LockSettingsService extends ILockSettings.Stub {
177     private static final String TAG = "LockSettingsService";
178     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
179     private static final String BIOMETRIC_PERMISSION = MANAGE_BIOMETRIC;
180     private static final boolean DEBUG = false;
181 
182     private static final int PROFILE_KEY_IV_SIZE = 12;
183     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
184     private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
185     private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
186     private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
187 
188     // No challenge provided
189     private static final int CHALLENGE_NONE = 0;
190     // Challenge was provided from the external caller (non-LockSettingsService)
191     private static final int CHALLENGE_FROM_CALLER = 1;
192     // Challenge was generated from within LockSettingsService, for resetLockout. When challenge
193     // type is set to internal, LSS will revokeChallenge after all profiles for that user are
194     // unlocked.
195     private static final int CHALLENGE_INTERNAL = 2;
196 
197     @IntDef({CHALLENGE_NONE,
198             CHALLENGE_FROM_CALLER,
199             CHALLENGE_INTERNAL})
200     @interface ChallengeType {}
201 
202     // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
203     // Do not call into ActivityManager while holding mSpManager lock.
204     private final Object mSeparateChallengeLock = new Object();
205 
206     private final DeviceProvisionedObserver mDeviceProvisionedObserver =
207             new DeviceProvisionedObserver();
208 
209     private final Injector mInjector;
210     private final Context mContext;
211     @VisibleForTesting
212     protected final Handler mHandler;
213     @VisibleForTesting
214     protected final LockSettingsStorage mStorage;
215     private final LockSettingsStrongAuth mStrongAuth;
216     private final SynchronizedStrongAuthTracker mStrongAuthTracker;
217 
218     private final NotificationManager mNotificationManager;
219     private final UserManager mUserManager;
220     private final IStorageManager mStorageManager;
221     private final IActivityManager mActivityManager;
222     private final SyntheticPasswordManager mSpManager;
223 
224     private final KeyStore mKeyStore;
225 
226     private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
227     private ManagedProfilePasswordCache mManagedProfilePasswordCache;
228 
229     private final RebootEscrowManager mRebootEscrowManager;
230 
231     private boolean mFirstCallToVold;
232 
233     // Current password metric for all users on the device. Updated when user unlocks
234     // the device or changes password. Removed when user is stopped.
235     @GuardedBy("this")
236     final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>();
237     @VisibleForTesting
238     protected boolean mHasSecureLockScreen;
239 
240     protected IGateKeeperService mGateKeeperService;
241     protected IAuthSecret mAuthSecretService;
242 
243     private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
244 
245     /**
246      * The UIDs that are used for system credential storage in keystore.
247      */
248     private static final int[] SYSTEM_CREDENTIAL_UIDS = {
249             Process.WIFI_UID, Process.VPN_UID,
250             Process.ROOT_UID, Process.SYSTEM_UID };
251 
252     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
253     // devices. The most basic of these is to show/hide notifications about missing features until
254     // the user unlocks the account and credential-encrypted storage is available.
255     public static final class Lifecycle extends SystemService {
256         private LockSettingsService mLockSettingsService;
257 
Lifecycle(Context context)258         public Lifecycle(Context context) {
259             super(context);
260         }
261 
262         @Override
onStart()263         public void onStart() {
264             AndroidKeyStoreProvider.install();
265             mLockSettingsService = new LockSettingsService(getContext());
266             publishBinderService("lock_settings", mLockSettingsService);
267         }
268 
269         @Override
onBootPhase(int phase)270         public void onBootPhase(int phase) {
271             super.onBootPhase(phase);
272             if (phase == PHASE_ACTIVITY_MANAGER_READY) {
273                 mLockSettingsService.migrateOldDataAfterSystemReady();
274             }
275         }
276 
277         @Override
onStartUser(int userHandle)278         public void onStartUser(int userHandle) {
279             mLockSettingsService.onStartUser(userHandle);
280         }
281 
282         @Override
onUnlockUser(int userHandle)283         public void onUnlockUser(int userHandle) {
284             mLockSettingsService.onUnlockUser(userHandle);
285         }
286 
287         @Override
onCleanupUser(int userHandle)288         public void onCleanupUser(int userHandle) {
289             mLockSettingsService.onCleanupUser(userHandle);
290         }
291     }
292 
293     @VisibleForTesting
294     protected static class SynchronizedStrongAuthTracker
295             extends LockPatternUtils.StrongAuthTracker {
SynchronizedStrongAuthTracker(Context context)296         public SynchronizedStrongAuthTracker(Context context) {
297             super(context);
298         }
299 
300         @Override
handleStrongAuthRequiredChanged(int strongAuthFlags, int userId)301         protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
302             synchronized (this) {
303                 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
304             }
305         }
306 
307         @Override
getStrongAuthForUser(int userId)308         public int getStrongAuthForUser(int userId) {
309             synchronized (this) {
310                 return super.getStrongAuthForUser(userId);
311             }
312         }
313 
register(LockSettingsStrongAuth strongAuth)314         void register(LockSettingsStrongAuth strongAuth) {
315             strongAuth.registerStrongAuthTracker(getStub());
316         }
317     }
318 
319     private class PendingResetLockout {
320         final int mUserId;
321         final byte[] mHAT;
PendingResetLockout(int userId, byte[] hat)322         PendingResetLockout(int userId, byte[] hat) {
323             mUserId = userId;
324             mHAT = hat;
325         }
326     }
327 
generateRandomProfilePassword()328     private LockscreenCredential generateRandomProfilePassword() {
329         byte[] randomLockSeed = new byte[] {};
330         try {
331             randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
332             char[] newPasswordChars = HexEncoding.encode(randomLockSeed);
333             byte[] newPassword = new byte[newPasswordChars.length];
334             for (int i = 0; i < newPasswordChars.length; i++) {
335                 newPassword[i] = (byte) newPasswordChars[i];
336             }
337             LockscreenCredential credential =
338                     LockscreenCredential.createManagedPassword(newPassword);
339             Arrays.fill(newPasswordChars, '\u0000');
340             Arrays.fill(newPassword, (byte) 0);
341             Arrays.fill(randomLockSeed, (byte) 0);
342             return credential;
343         } catch (NoSuchAlgorithmException e) {
344             throw new IllegalStateException("Fail to generate profile password", e);
345         }
346     }
347 
348     /**
349      * Tie managed profile to primary profile if it is in unified mode and not tied before.
350      *
351      * @param managedUserId Managed profile user Id
352      * @param managedUserPassword Managed profile original password (when it has separated lock).
353      */
tieManagedProfileLockIfNecessary(int managedUserId, LockscreenCredential managedUserPassword)354     public void tieManagedProfileLockIfNecessary(int managedUserId,
355             LockscreenCredential managedUserPassword) {
356         if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
357         // Only for managed profile
358         if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
359             return;
360         }
361         // Do not tie managed profile when work challenge is enabled
362         if (getSeparateProfileChallengeEnabledInternal(managedUserId)) {
363             return;
364         }
365         // Do not tie managed profile to parent when it's done already
366         if (mStorage.hasChildProfileLock(managedUserId)) {
367             return;
368         }
369         // If parent does not have a screen lock, simply clear credential from the managed profile,
370         // to maintain the invariant that unified profile should always have the same secure state
371         // as its parent.
372         final int parentId = mUserManager.getProfileParent(managedUserId).id;
373         if (!isUserSecure(parentId) && !managedUserPassword.isNone()) {
374             if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock but profile has one");
375 
376             setLockCredentialInternal(LockscreenCredential.createNone(), managedUserPassword,
377                     managedUserId, /* isLockTiedToParent= */ true);
378             return;
379         }
380         // Do not tie when the parent has no SID (but does have a screen lock).
381         // This can only happen during an upgrade path where SID is yet to be
382         // generated when the user unlocks for the first time.
383         try {
384             if (getGateKeeperService().getSecureUserId(parentId) == 0) {
385                 return;
386             }
387         } catch (RemoteException e) {
388             Slog.e(TAG, "Failed to talk to GateKeeper service", e);
389             return;
390         }
391         if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
392         try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) {
393             setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId,
394                     /* isLockTiedToParent= */ true);
395             tieProfileLockToParent(managedUserId, unifiedProfilePassword);
396             mManagedProfilePasswordCache.storePassword(managedUserId, unifiedProfilePassword);
397         }
398     }
399 
400     static class Injector {
401 
402         protected Context mContext;
403 
Injector(Context context)404         public Injector(Context context) {
405             mContext = context;
406         }
407 
getContext()408         public Context getContext() {
409             return mContext;
410         }
411 
getServiceThread()412         public ServiceThread getServiceThread() {
413             ServiceThread handlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
414                     true /*allowIo*/);
415             handlerThread.start();
416             return handlerThread;
417         }
418 
getHandler(ServiceThread handlerThread)419         public Handler getHandler(ServiceThread handlerThread) {
420             return new Handler(handlerThread.getLooper());
421         }
422 
getStorage()423         public LockSettingsStorage getStorage() {
424             final LockSettingsStorage storage = new LockSettingsStorage(mContext);
425             storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
426                 @Override
427                 public void initialize(SQLiteDatabase db) {
428                     // Get the lockscreen default from a system property, if available
429                     boolean lockScreenDisable = SystemProperties.getBoolean(
430                             "ro.lockscreen.disable.default", false);
431                     if (lockScreenDisable) {
432                         storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
433                     }
434                 }
435             });
436             return storage;
437         }
438 
getStrongAuth()439         public LockSettingsStrongAuth getStrongAuth() {
440             return new LockSettingsStrongAuth(mContext);
441         }
442 
getStrongAuthTracker()443         public SynchronizedStrongAuthTracker getStrongAuthTracker() {
444             return new SynchronizedStrongAuthTracker(mContext);
445         }
446 
getActivityManager()447         public IActivityManager getActivityManager() {
448             return ActivityManager.getService();
449         }
450 
getNotificationManager()451         public NotificationManager getNotificationManager() {
452             return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
453         }
454 
getUserManager()455         public UserManager getUserManager() {
456             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
457         }
458 
getUserManagerInternal()459         public UserManagerInternal getUserManagerInternal() {
460             return LocalServices.getService(UserManagerInternal.class);
461         }
462 
463         /**
464          * Return the {@link DevicePolicyManager} object.
465          *
466          * Since LockSettingsService is considered a lower-level component than DevicePolicyManager,
467          * do NOT hold any lock in this class while calling into DevicePolicyManager to prevent
468          * the risk of deadlock.
469          */
getDevicePolicyManager()470         public DevicePolicyManager getDevicePolicyManager() {
471             return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
472         }
473 
getDeviceStateCache()474         public DeviceStateCache getDeviceStateCache() {
475             return DeviceStateCache.getInstance();
476         }
477 
getKeyStore()478         public KeyStore getKeyStore() {
479             return KeyStore.getInstance();
480         }
481 
getRecoverableKeyStoreManager(KeyStore keyStore)482         public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
483             return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
484         }
485 
getStorageManager()486         public IStorageManager getStorageManager() {
487             final IBinder service = ServiceManager.getService("mount");
488             if (service != null) {
489                 return IStorageManager.Stub.asInterface(service);
490             }
491             return null;
492         }
493 
getSyntheticPasswordManager(LockSettingsStorage storage)494         public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
495             return new SyntheticPasswordManager(getContext(), storage, getUserManager(),
496                     new PasswordSlotManager());
497         }
498 
getRebootEscrowManager(RebootEscrowManager.Callbacks callbacks, LockSettingsStorage storage)499         public RebootEscrowManager getRebootEscrowManager(RebootEscrowManager.Callbacks callbacks,
500                 LockSettingsStorage storage) {
501             return new RebootEscrowManager(mContext, callbacks, storage);
502         }
503 
hasEnrolledBiometrics(int userId)504         public boolean hasEnrolledBiometrics(int userId) {
505             BiometricManager bm = mContext.getSystemService(BiometricManager.class);
506             return bm.hasEnrolledBiometrics(userId);
507         }
508 
binderGetCallingUid()509         public int binderGetCallingUid() {
510             return Binder.getCallingUid();
511         }
512 
isGsiRunning()513         public boolean isGsiRunning() {
514             return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
515         }
516 
getFingerprintManager()517         public FingerprintManager getFingerprintManager() {
518             if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
519                 return (FingerprintManager) mContext.getSystemService(Context.FINGERPRINT_SERVICE);
520             } else {
521                 return null;
522             }
523         }
524 
getFaceManager()525         public FaceManager getFaceManager() {
526             if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
527                 return (FaceManager) mContext.getSystemService(Context.FACE_SERVICE);
528             } else {
529                 return null;
530             }
531         }
532 
settingsGlobalGetInt(ContentResolver contentResolver, String keyName, int defaultValue)533         public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
534                 int defaultValue) {
535             return Settings.Global.getInt(contentResolver, keyName, defaultValue);
536         }
537 
settingsSecureGetInt(ContentResolver contentResolver, String keyName, int defaultValue, int userId)538         public int settingsSecureGetInt(ContentResolver contentResolver, String keyName,
539                 int defaultValue, int userId) {
540             return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId);
541         }
542 
getManagedProfilePasswordCache()543         public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() {
544             try {
545                 java.security.KeyStore ks = java.security.KeyStore.getInstance("AndroidKeyStore");
546                 ks.load(null);
547                 return new ManagedProfilePasswordCache(ks, getUserManager());
548             } catch (Exception e) {
549                 throw new IllegalStateException("Cannot load keystore", e);
550             }
551         }
552     }
553 
LockSettingsService(Context context)554     public LockSettingsService(Context context) {
555         this(new Injector(context));
556     }
557 
558     @VisibleForTesting
LockSettingsService(Injector injector)559     protected LockSettingsService(Injector injector) {
560         mInjector = injector;
561         mContext = injector.getContext();
562         mKeyStore = injector.getKeyStore();
563         mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
564         mHandler = injector.getHandler(injector.getServiceThread());
565         mStrongAuth = injector.getStrongAuth();
566         mActivityManager = injector.getActivityManager();
567 
568         mFirstCallToVold = true;
569 
570         IntentFilter filter = new IntentFilter();
571         filter.addAction(Intent.ACTION_USER_ADDED);
572         filter.addAction(Intent.ACTION_USER_STARTING);
573         filter.addAction(Intent.ACTION_USER_REMOVED);
574         injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
575                 null, null);
576 
577         mStorage = injector.getStorage();
578         mNotificationManager = injector.getNotificationManager();
579         mUserManager = injector.getUserManager();
580         mStorageManager = injector.getStorageManager();
581         mStrongAuthTracker = injector.getStrongAuthTracker();
582         mStrongAuthTracker.register(mStrongAuth);
583 
584         mSpManager = injector.getSyntheticPasswordManager(mStorage);
585         mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache();
586 
587         mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
588                 mStorage);
589 
590         LocalServices.addService(LockSettingsInternal.class, new LocalService());
591     }
592 
593     /**
594      * If the account is credential-encrypted, show notification requesting the user to unlock the
595      * device.
596      */
maybeShowEncryptionNotificationForUser(@serIdInt int userId)597     private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
598         final UserInfo user = mUserManager.getUserInfo(userId);
599         if (!user.isManagedProfile()) {
600             // When the user is locked, we communicate it loud-and-clear
601             // on the lockscreen; we only show a notification below for
602             // locked managed profiles.
603             return;
604         }
605 
606         if (isUserKeyUnlocked(userId)) {
607             // If storage is not locked, the user will be automatically unlocked so there is
608             // no need to show the notification.
609             return;
610         }
611 
612         final UserHandle userHandle = user.getUserHandle();
613         final boolean isSecure = isUserSecure(userId);
614         if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
615             UserInfo parent = mUserManager.getProfileParent(userId);
616             if (parent != null &&
617                     mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
618                     !mUserManager.isQuietModeEnabled(userHandle)) {
619                 // Only show notifications for managed profiles once their parent
620                 // user is unlocked.
621                 showEncryptionNotificationForProfile(userHandle);
622             }
623         }
624     }
625 
showEncryptionNotificationForProfile(UserHandle user)626     private void showEncryptionNotificationForProfile(UserHandle user) {
627         Resources r = mContext.getResources();
628         CharSequence title = r.getText(
629                 com.android.internal.R.string.profile_encrypted_title);
630         CharSequence message = r.getText(
631                 com.android.internal.R.string.profile_encrypted_message);
632         CharSequence detail = r.getText(
633                 com.android.internal.R.string.profile_encrypted_detail);
634 
635         final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
636         final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
637                 user.getIdentifier());
638         if (unlockIntent == null) {
639             return;
640         }
641         unlockIntent.setFlags(
642                 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
643         PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
644                 PendingIntent.FLAG_UPDATE_CURRENT);
645 
646         showEncryptionNotification(user, title, message, detail, intent);
647     }
648 
showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message, CharSequence detail, PendingIntent intent)649     private void showEncryptionNotification(UserHandle user, CharSequence title,
650             CharSequence message, CharSequence detail, PendingIntent intent) {
651         if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
652 
653         // Suppress all notifications on non-FBE devices for now
654         if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
655 
656         Notification notification =
657                 new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
658                         .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
659                         .setWhen(0)
660                         .setOngoing(true)
661                         .setTicker(title)
662                         .setColor(mContext.getColor(
663                                 com.android.internal.R.color.system_notification_accent_color))
664                         .setContentTitle(title)
665                         .setContentText(message)
666                         .setSubText(detail)
667                         .setVisibility(Notification.VISIBILITY_PUBLIC)
668                         .setContentIntent(intent)
669                         .build();
670         mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
671             notification, user);
672     }
673 
hideEncryptionNotification(UserHandle userHandle)674     private void hideEncryptionNotification(UserHandle userHandle) {
675         if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
676         mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
677             userHandle);
678     }
679 
onCleanupUser(int userId)680     public void onCleanupUser(int userId) {
681         hideEncryptionNotification(new UserHandle(userId));
682         // User is stopped with its CE key evicted. Restore strong auth requirement to the default
683         // flags after boot since stopping and restarting a user later is equivalent to rebooting
684         // the device.
685         int strongAuthRequired = LockPatternUtils.StrongAuthTracker.getDefaultFlags(mContext);
686         requireStrongAuth(strongAuthRequired, userId);
687         synchronized (this) {
688             mUserPasswordMetrics.remove(userId);
689         }
690     }
691 
onStartUser(final int userId)692     public void onStartUser(final int userId) {
693         maybeShowEncryptionNotificationForUser(userId);
694     }
695 
696     /**
697      * Clean up states associated with the given user, in case the userId is reused but LSS didn't
698      * get a chance to do cleanup previously during ACTION_USER_REMOVED.
699      *
700      * Internally, LSS stores serial number for each user and check it against the current user's
701      * serial number to determine if the userId is reused and invoke cleanup code.
702      */
cleanupDataForReusedUserIdIfNecessary(int userId)703     private void cleanupDataForReusedUserIdIfNecessary(int userId) {
704         if (userId == UserHandle.USER_SYSTEM) {
705             // Short circuit as we never clean up user 0.
706             return;
707         }
708         // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse.
709         int serialNumber = mUserManager.getUserSerialNumber(userId);
710 
711         int storedSerialNumber = mStorage.getInt(USER_SERIAL_NUMBER_KEY, -1, userId);
712         if (storedSerialNumber != serialNumber) {
713             // If LockSettingsStorage does not have a copy of the serial number, it could be either
714             // this is a user created before the serial number recording logic is introduced, or
715             // the user does not exist or was removed and cleaned up properly. In either case, don't
716             // invoke removeUser().
717             if (storedSerialNumber != -1) {
718                 removeUser(userId, /* unknownUser */ true);
719             }
720             mStorage.setInt(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
721         }
722     }
723 
724     /**
725      * Check if profile got unlocked but the keystore is still locked. This happens on full disk
726      * encryption devices since the profile may not yet be running when we consider unlocking it
727      * during the normal flow. In this case unlock the keystore for the profile.
728      */
ensureProfileKeystoreUnlocked(int userId)729     private void ensureProfileKeystoreUnlocked(int userId) {
730         final KeyStore ks = KeyStore.getInstance();
731         if (ks.state(userId) == KeyStore.State.LOCKED
732                 && mUserManager.getUserInfo(userId).isManagedProfile()
733                 && hasUnifiedChallenge(userId)) {
734             Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
735             // If boot took too long and the password in vold got expired, parent keystore will
736             // be still locked, we ignore this case since the user will be prompted to unlock
737             // the device after boot.
738             unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */,
739                     CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */);
740         }
741     }
742 
onUnlockUser(final int userId)743     public void onUnlockUser(final int userId) {
744         // Perform tasks which require locks in LSS on a handler, as we are callbacks from
745         // ActivityManager.unlockUser()
746         mHandler.post(new Runnable() {
747             @Override
748             public void run() {
749                 cleanupDataForReusedUserIdIfNecessary(userId);
750                 ensureProfileKeystoreUnlocked(userId);
751                 // Hide notification first, as tie managed profile lock takes time
752                 hideEncryptionNotification(new UserHandle(userId));
753 
754                 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
755                     tieManagedProfileLockIfNecessary(userId, LockscreenCredential.createNone());
756                 }
757 
758                 // If the user doesn't have a credential, try and derive their secret for the
759                 // AuthSecret HAL. The secret will have been enrolled if the user previously set a
760                 // credential and still needs to be passed to the HAL once that credential is
761                 // removed.
762                 if (mUserManager.getUserInfo(userId).isPrimary() && !isUserSecure(userId)) {
763                     tryDeriveAuthTokenForUnsecuredPrimaryUser(userId);
764                 }
765             }
766         });
767     }
768 
tryDeriveAuthTokenForUnsecuredPrimaryUser(@serIdInt int userId)769     private void tryDeriveAuthTokenForUnsecuredPrimaryUser(@UserIdInt int userId) {
770         synchronized (mSpManager) {
771             // Make sure the user has a synthetic password to derive
772             if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
773                 return;
774             }
775 
776             final long handle = getSyntheticPasswordHandleLocked(userId);
777             AuthenticationResult result =
778                     mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
779                             handle, LockscreenCredential.createNone(), userId, null);
780             if (result.authToken != null) {
781                 Slog.i(TAG, "Retrieved auth token for user " + userId);
782                 onAuthTokenKnownForUser(userId, result.authToken);
783             } else {
784                 Slog.e(TAG, "Auth token not available for user " + userId);
785             }
786         }
787     }
788 
789     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
790         @Override
791         public void onReceive(Context context, Intent intent) {
792             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
793                 // Notify keystore that a new user was added.
794                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
795                 final KeyStore ks = KeyStore.getInstance();
796                 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
797                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
798                 ks.onUserAdded(userHandle, parentHandle);
799             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
800                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
801                 mStorage.prefetchUser(userHandle);
802             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
803                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
804                 if (userHandle > 0) {
805                     removeUser(userHandle, /* unknownUser= */ false);
806                 }
807             }
808         }
809     };
810 
811     @Override // binder interface
systemReady()812     public void systemReady() {
813         if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
814             EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
815         }
816         checkWritePermission(UserHandle.USER_SYSTEM);
817 
818         mHasSecureLockScreen = mContext.getPackageManager()
819                 .hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN);
820         migrateOldData();
821         getGateKeeperService();
822         mSpManager.initWeaverService();
823         getAuthSecretHal();
824         mDeviceProvisionedObserver.onSystemReady();
825         mRebootEscrowManager.loadRebootEscrowDataIfAvailable();
826         // TODO: maybe skip this for split system user mode.
827         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
828     }
829 
getAuthSecretHal()830     private void getAuthSecretHal() {
831         try {
832             mAuthSecretService = IAuthSecret.getService(/* retry */ true);
833         } catch (NoSuchElementException e) {
834             Slog.i(TAG, "Device doesn't implement AuthSecret HAL");
835         } catch (RemoteException e) {
836             Slog.w(TAG, "Failed to get AuthSecret HAL", e);
837         }
838     }
839 
migrateOldData()840     private void migrateOldData() {
841         // These Settings moved before multi-user was enabled, so we only have to do it for the
842         // root user.
843         if (getString("migrated", null, 0) == null) {
844             final ContentResolver cr = mContext.getContentResolver();
845             for (String validSetting : VALID_SETTINGS) {
846                 String value = Settings.Secure.getString(cr, validSetting);
847                 if (value != null) {
848                     setString(validSetting, value, 0);
849                 }
850             }
851             // No need to move the password / pattern files. They're already in the right place.
852             setString("migrated", "true", 0);
853             Slog.i(TAG, "Migrated lock settings to new location");
854         }
855 
856         // These Settings changed after multi-user was enabled, hence need to be moved per user.
857         if (getString("migrated_user_specific", null, 0) == null) {
858             final ContentResolver cr = mContext.getContentResolver();
859             List<UserInfo> users = mUserManager.getUsers();
860             for (int user = 0; user < users.size(); user++) {
861                 // Migrate owner info
862                 final int userId = users.get(user).id;
863                 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
864                 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
865                 if (!TextUtils.isEmpty(ownerInfo)) {
866                     setString(OWNER_INFO, ownerInfo, userId);
867                     Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
868                 }
869 
870                 // Migrate owner info enabled. Note there was a bug where older platforms only
871                 // stored this value if the checkbox was toggled at least once. The code detects
872                 // this case by handling the exception.
873                 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
874                 boolean enabled;
875                 try {
876                     int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
877                     enabled = ivalue != 0;
878                     setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
879                 } catch (SettingNotFoundException e) {
880                     // Setting was never stored. Store it if the string is not empty.
881                     if (!TextUtils.isEmpty(ownerInfo)) {
882                         setLong(OWNER_INFO_ENABLED, 1, userId);
883                     }
884                 }
885                 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
886             }
887             // No need to move the password / pattern files. They're already in the right place.
888             setString("migrated_user_specific", "true", 0);
889             Slog.i(TAG, "Migrated per-user lock settings to new location");
890         }
891 
892         // Migrates biometric weak such that the fallback mechanism becomes the primary.
893         if (getString("migrated_biometric_weak", null, 0) == null) {
894             List<UserInfo> users = mUserManager.getUsers();
895             for (int i = 0; i < users.size(); i++) {
896                 int userId = users.get(i).id;
897                 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
898                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
899                         userId);
900                 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
901                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
902                         userId);
903                 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
904                     setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
905                             alternateType,
906                             userId);
907                 }
908                 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
909                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
910                         userId);
911             }
912             setString("migrated_biometric_weak", "true", 0);
913             Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
914         }
915 
916         // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
917         // user was present on the system, so if we're upgrading to M and there is more than one
918         // user we disable the flag to remain consistent.
919         if (getString("migrated_lockscreen_disabled", null, 0) == null) {
920             final List<UserInfo> users = mUserManager.getUsers();
921             final int userCount = users.size();
922             int switchableUsers = 0;
923             for (int i = 0; i < userCount; i++) {
924                 if (users.get(i).supportsSwitchTo()) {
925                     switchableUsers++;
926                 }
927             }
928 
929             if (switchableUsers > 1) {
930                 for (int i = 0; i < userCount; i++) {
931                     int id = users.get(i).id;
932 
933                     if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
934                         setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
935                     }
936                 }
937             }
938 
939             setString("migrated_lockscreen_disabled", "true", 0);
940             Slog.i(TAG, "Migrated lockscreen disabled flag");
941         }
942 
943         boolean isWatch = mContext.getPackageManager().hasSystemFeature(
944                 PackageManager.FEATURE_WATCH);
945         // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
946         // and device management the lockscreen must be re-enabled now for users that upgrade.
947         if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
948             final List<UserInfo> users = mUserManager.getUsers();
949             final int userCount = users.size();
950             for (int i = 0; i < userCount; i++) {
951                 int id = users.get(i).id;
952                 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
953             }
954             setString("migrated_wear_lockscreen_disabled", "true", 0);
955             Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
956         }
957     }
958 
migrateOldDataAfterSystemReady()959     private void migrateOldDataAfterSystemReady() {
960         // Migrate the FRP credential to the persistent data block
961         if (LockPatternUtils.frpCredentialEnabled(mContext)
962                 && !getBoolean("migrated_frp", false, 0)) {
963             migrateFrpCredential();
964             setBoolean("migrated_frp", true, 0);
965             Slog.i(TAG, "Migrated migrated_frp.");
966         }
967     }
968 
969     /**
970      * Migrate the credential for the FRP credential owner user if the following are satisfied:
971      * - the user has a secure credential
972      * - the FRP credential is not set up
973      * - the credential is based on a synthetic password.
974      */
migrateFrpCredential()975     private void migrateFrpCredential() {
976         if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
977             return;
978         }
979         for (UserInfo userInfo : mUserManager.getUsers()) {
980             if (userOwnsFrpCredential(mContext, userInfo) && isUserSecure(userInfo.id)) {
981                 synchronized (mSpManager) {
982                     if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) {
983                         int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
984                                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
985 
986                         mSpManager.migrateFrpPasswordLocked(
987                                 getSyntheticPasswordHandleLocked(userInfo.id),
988                                 userInfo,
989                                 redactActualQualityToMostLenientEquivalentQuality(actualQuality));
990                     }
991                 }
992                 return;
993             }
994         }
995     }
996 
997     /**
998      * Returns the lowest password quality that still presents the same UI for entering it.
999      *
1000      * For the FRP credential, we do not want to leak the actual quality of the password, only what
1001      * kind of UI it requires. However, when migrating, we only know the actual quality, not the
1002      * originally requested quality; since this is only used to determine what input variant to
1003      * present to the user, we just assume the lowest possible quality was requested.
1004      */
redactActualQualityToMostLenientEquivalentQuality(int quality)1005     private int redactActualQualityToMostLenientEquivalentQuality(int quality) {
1006         switch (quality) {
1007             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
1008             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
1009             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
1010                 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
1011             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
1012             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
1013                 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
1014             case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
1015             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
1016             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
1017             case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
1018             default:
1019                 return quality;
1020         }
1021     }
1022 
enforceFrpResolved()1023     private void enforceFrpResolved() {
1024         final ContentResolver cr = mContext.getContentResolver();
1025         final boolean inSetupWizard = mInjector.settingsSecureGetInt(cr,
1026                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_SYSTEM) == 0;
1027         final boolean secureFrp = mInjector.settingsSecureGetInt(cr,
1028                 Settings.Secure.SECURE_FRP_MODE, 0, UserHandle.USER_SYSTEM) == 1;
1029         if (inSetupWizard && secureFrp) {
1030             throw new SecurityException("Cannot change credential in SUW while factory reset"
1031                     + " protection is not resolved yet");
1032         }
1033     }
1034 
checkWritePermission(int userId)1035     private final void checkWritePermission(int userId) {
1036         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
1037     }
1038 
checkPasswordReadPermission(int userId)1039     private final void checkPasswordReadPermission(int userId) {
1040         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
1041     }
1042 
checkPasswordHavePermission(int userId)1043     private final void checkPasswordHavePermission(int userId) {
1044         if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
1045             EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
1046         }
1047         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
1048     }
1049 
checkReadPermission(String requestedKey, int userId)1050     private final void checkReadPermission(String requestedKey, int userId) {
1051         final int callingUid = Binder.getCallingUid();
1052 
1053         for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
1054             String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
1055             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
1056                     != PackageManager.PERMISSION_GRANTED) {
1057                 throw new SecurityException("uid=" + callingUid
1058                         + " needs permission " + READ_CONTACTS + " to read "
1059                         + requestedKey + " for user " + userId);
1060             }
1061         }
1062 
1063         for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
1064             String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
1065             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
1066                     != PackageManager.PERMISSION_GRANTED) {
1067                 throw new SecurityException("uid=" + callingUid
1068                         + " needs permission " + PERMISSION + " to read "
1069                         + requestedKey + " for user " + userId);
1070             }
1071         }
1072     }
1073 
checkBiometricPermission()1074     private final void checkBiometricPermission() {
1075         mContext.enforceCallingOrSelfPermission(BIOMETRIC_PERMISSION, "LockSettingsBiometric");
1076     }
1077 
1078     @Override
hasSecureLockScreen()1079     public boolean hasSecureLockScreen() {
1080         return mHasSecureLockScreen;
1081     }
1082 
1083     @Override
getSeparateProfileChallengeEnabled(int userId)1084     public boolean getSeparateProfileChallengeEnabled(int userId) {
1085         checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
1086         return getSeparateProfileChallengeEnabledInternal(userId);
1087     }
1088 
getSeparateProfileChallengeEnabledInternal(int userId)1089     private boolean getSeparateProfileChallengeEnabledInternal(int userId) {
1090         synchronized (mSeparateChallengeLock) {
1091             return mStorage.getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
1092         }
1093     }
1094 
1095     @Override
setSeparateProfileChallengeEnabled(int userId, boolean enabled, LockscreenCredential managedUserPassword)1096     public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
1097             LockscreenCredential managedUserPassword) {
1098         checkWritePermission(userId);
1099         if (!mHasSecureLockScreen) {
1100             throw new UnsupportedOperationException(
1101                     "This operation requires secure lock screen feature.");
1102         }
1103         synchronized (mSeparateChallengeLock) {
1104             setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword != null
1105                     ? managedUserPassword : LockscreenCredential.createNone());
1106         }
1107         notifySeparateProfileChallengeChanged(userId);
1108     }
1109 
1110     @GuardedBy("mSeparateChallengeLock")
setSeparateProfileChallengeEnabledLocked(@serIdInt int userId, boolean enabled, LockscreenCredential managedUserPassword)1111     private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId,
1112             boolean enabled, LockscreenCredential managedUserPassword) {
1113         final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
1114         setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
1115         try {
1116             if (enabled) {
1117                 mStorage.removeChildProfileLock(userId);
1118                 removeKeystoreProfileKey(userId);
1119             } else {
1120                 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
1121             }
1122         } catch (IllegalStateException e) {
1123             setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, old, userId);
1124             throw e;
1125         }
1126     }
1127 
notifySeparateProfileChallengeChanged(int userId)1128     private void notifySeparateProfileChallengeChanged(int userId) {
1129         // LSS cannot call into DPM directly, otherwise it will cause deadlock.
1130         // In this case, calling DPM on a handler thread is OK since DPM doesn't
1131         // expect reportSeparateProfileChallengeChanged() to happen synchronously.
1132         mHandler.post(() -> {
1133             final DevicePolicyManagerInternal dpmi = LocalServices.getService(
1134                     DevicePolicyManagerInternal.class);
1135             if (dpmi != null) {
1136                 dpmi.reportSeparateProfileChallengeChanged(userId);
1137             }
1138         });
1139     }
1140 
1141     @Override
setBoolean(String key, boolean value, int userId)1142     public void setBoolean(String key, boolean value, int userId) {
1143         checkWritePermission(userId);
1144         mStorage.setBoolean(key, value, userId);
1145     }
1146 
1147     @Override
setLong(String key, long value, int userId)1148     public void setLong(String key, long value, int userId) {
1149         checkWritePermission(userId);
1150         mStorage.setLong(key, value, userId);
1151     }
1152 
1153     @Override
setString(String key, String value, int userId)1154     public void setString(String key, String value, int userId) {
1155         checkWritePermission(userId);
1156         mStorage.setString(key, value, userId);
1157     }
1158 
1159     @Override
getBoolean(String key, boolean defaultValue, int userId)1160     public boolean getBoolean(String key, boolean defaultValue, int userId) {
1161         checkReadPermission(key, userId);
1162         if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
1163             return getCredentialTypeInternal(userId) == CREDENTIAL_TYPE_PATTERN;
1164         }
1165         return mStorage.getBoolean(key, defaultValue, userId);
1166     }
1167 
1168     @Override
getLong(String key, long defaultValue, int userId)1169     public long getLong(String key, long defaultValue, int userId) {
1170         checkReadPermission(key, userId);
1171         return mStorage.getLong(key, defaultValue, userId);
1172     }
1173 
1174     @Override
getString(String key, String defaultValue, int userId)1175     public String getString(String key, String defaultValue, int userId) {
1176         checkReadPermission(key, userId);
1177         return mStorage.getString(key, defaultValue, userId);
1178     }
1179 
setKeyguardStoredQuality(int quality, int userId)1180     private void setKeyguardStoredQuality(int quality, int userId) {
1181         if (DEBUG) Slog.d(TAG, "setKeyguardStoredQuality: user=" + userId + " quality=" + quality);
1182         mStorage.setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId);
1183     }
1184 
getKeyguardStoredQuality(int userId)1185     private int getKeyguardStoredQuality(int userId) {
1186         return (int) mStorage.getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
1187                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
1188     }
1189 
1190     @Override
getCredentialType(int userId)1191     public int getCredentialType(int userId) {
1192         checkPasswordHavePermission(userId);
1193         return getCredentialTypeInternal(userId);
1194     }
1195 
1196     // TODO: this is a hot path, can we optimize it?
1197     /**
1198      * Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
1199      * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
1200      * {@link #CREDENTIAL_TYPE_PASSWORD}
1201      */
getCredentialTypeInternal(int userId)1202     public int getCredentialTypeInternal(int userId) {
1203         if (userId == USER_FRP) {
1204             return getFrpCredentialType();
1205         }
1206         synchronized (mSpManager) {
1207             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1208                 final long handle = getSyntheticPasswordHandleLocked(userId);
1209                 int rawType = mSpManager.getCredentialType(handle, userId);
1210                 if (rawType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
1211                     return rawType;
1212                 }
1213                 return pinOrPasswordQualityToCredentialType(getKeyguardStoredQuality(userId));
1214             }
1215         }
1216         // Intentional duplication of the getKeyguardStoredQuality() call above since this is a
1217         // unlikely code path (device with pre-synthetic password credential). We want to skip
1218         // calling getKeyguardStoredQuality whenever possible.
1219         final int savedQuality = getKeyguardStoredQuality(userId);
1220         if (savedQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1221                 && mStorage.hasPattern(userId)) {
1222             return CREDENTIAL_TYPE_PATTERN;
1223         }
1224         if (savedQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1225                 && mStorage.hasPassword(userId)) {
1226             return pinOrPasswordQualityToCredentialType(savedQuality);
1227         }
1228         return CREDENTIAL_TYPE_NONE;
1229     }
1230 
getFrpCredentialType()1231     private int getFrpCredentialType() {
1232         PersistentData data = mStorage.readPersistentDataBlock();
1233         if (data.type != PersistentData.TYPE_SP && data.type != PersistentData.TYPE_SP_WEAVER) {
1234             return CREDENTIAL_TYPE_NONE;
1235         }
1236         int credentialType = SyntheticPasswordManager.getFrpCredentialType(data.payload);
1237         if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
1238             return credentialType;
1239         }
1240         return pinOrPasswordQualityToCredentialType(data.qualityForUi);
1241     }
1242 
pinOrPasswordQualityToCredentialType(int quality)1243     private static int pinOrPasswordQualityToCredentialType(int quality) {
1244         if (LockPatternUtils.isQualityAlphabeticPassword(quality)) {
1245             return CREDENTIAL_TYPE_PASSWORD;
1246         }
1247         if (LockPatternUtils.isQualityNumericPin(quality)) {
1248             return CREDENTIAL_TYPE_PIN;
1249         }
1250         throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
1251     }
1252 
isUserSecure(int userId)1253     private boolean isUserSecure(int userId) {
1254         return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
1255     }
1256 
setKeystorePassword(byte[] password, int userHandle)1257     private void setKeystorePassword(byte[] password, int userHandle) {
1258         final KeyStore ks = KeyStore.getInstance();
1259         // TODO(b/120484642): Update keystore to accept byte[] passwords
1260         String passwordString = password == null ? null : new String(password);
1261         ks.onUserPasswordChanged(userHandle, passwordString);
1262     }
1263 
unlockKeystore(byte[] password, int userHandle)1264     private void unlockKeystore(byte[] password, int userHandle) {
1265         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
1266         // TODO(b/120484642): Update keystore to accept byte[] passwords
1267         String passwordString = password == null ? null : new String(password);
1268         final KeyStore ks = KeyStore.getInstance();
1269         ks.unlock(userHandle, passwordString);
1270     }
1271 
1272     @VisibleForTesting /** Note: this method is overridden in unit tests */
getDecryptedPasswordForTiedProfile(int userId)1273     protected LockscreenCredential getDecryptedPasswordForTiedProfile(int userId)
1274             throws KeyStoreException, UnrecoverableKeyException,
1275             NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
1276             InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
1277             CertificateException, IOException {
1278         if (DEBUG) Slog.v(TAG, "Get child profile decrypted key");
1279         byte[] storedData = mStorage.readChildProfileLock(userId);
1280         if (storedData == null) {
1281             throw new FileNotFoundException("Child profile lock file not found");
1282         }
1283         byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
1284         byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
1285                 storedData.length);
1286         byte[] decryptionResult;
1287         java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1288         keyStore.load(null);
1289         SecretKey decryptionKey = (SecretKey) keyStore.getKey(
1290                 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
1291 
1292         Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
1293                 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
1294 
1295         cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
1296         decryptionResult = cipher.doFinal(encryptedPassword);
1297         LockscreenCredential credential = LockscreenCredential.createManagedPassword(
1298                 decryptionResult);
1299         Arrays.fill(decryptionResult, (byte) 0);
1300         mManagedProfilePasswordCache.storePassword(userId, credential);
1301         return credential;
1302     }
1303 
unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated, @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts)1304     private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated,
1305             @ChallengeType int challengeType, long challenge,
1306             @Nullable ArrayList<PendingResetLockout> resetLockouts) {
1307         try {
1308             doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
1309                     challengeType, challenge, profileHandle, null /* progressCallback */,
1310                     resetLockouts);
1311         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1312                 | NoSuchAlgorithmException | NoSuchPaddingException
1313                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1314                 | BadPaddingException | CertificateException | IOException e) {
1315             if (e instanceof FileNotFoundException) {
1316                 Slog.i(TAG, "Child profile key not found");
1317             } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
1318                 Slog.i(TAG, "Parent keystore seems locked, ignoring");
1319             } else {
1320                 Slog.e(TAG, "Failed to decrypt child profile key", e);
1321             }
1322         }
1323     }
1324 
unlockUser(int userId, byte[] token, byte[] secret)1325     private void unlockUser(int userId, byte[] token, byte[] secret) {
1326         unlockUser(userId, token, secret, CHALLENGE_NONE, 0 /* challenge */, null);
1327     }
1328 
1329     /**
1330      * Unlock the user (both storage and user state) and its associated managed profiles
1331      * synchronously.
1332      *
1333      * <em>Be very careful about the risk of deadlock here: ActivityManager.unlockUser()
1334      * can end up calling into other system services to process user unlock request (via
1335      * {@link com.android.server.SystemServiceManager#unlockUser} </em>
1336      */
unlockUser(int userId, byte[] token, byte[] secret, @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts)1337     private void unlockUser(int userId, byte[] token, byte[] secret,
1338             @ChallengeType int challengeType, long challenge,
1339             @Nullable ArrayList<PendingResetLockout> resetLockouts) {
1340         Slog.i(TAG, "Unlocking user " + userId + " with secret only, length "
1341                 + (secret != null ? secret.length : 0));
1342         // TODO: make this method fully async so we can update UI with progress strings
1343         final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId);
1344         final CountDownLatch latch = new CountDownLatch(1);
1345         final IProgressListener listener = new IProgressListener.Stub() {
1346             @Override
1347             public void onStarted(int id, Bundle extras) throws RemoteException {
1348                 Slog.d(TAG, "unlockUser started");
1349             }
1350 
1351             @Override
1352             public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
1353                 Slog.d(TAG, "unlockUser progress " + progress);
1354             }
1355 
1356             @Override
1357             public void onFinished(int id, Bundle extras) throws RemoteException {
1358                 Slog.d(TAG, "unlockUser finished");
1359                 latch.countDown();
1360             }
1361         };
1362 
1363         try {
1364             mActivityManager.unlockUser(userId, token, secret, listener);
1365         } catch (RemoteException e) {
1366             throw e.rethrowAsRuntimeException();
1367         }
1368 
1369         try {
1370             latch.await(15, TimeUnit.SECONDS);
1371         } catch (InterruptedException e) {
1372             Thread.currentThread().interrupt();
1373         }
1374 
1375         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1376             return;
1377         }
1378 
1379         for (UserInfo profile : mUserManager.getProfiles(userId)) {
1380             if (profile.id == userId) continue;
1381             if (!profile.isManagedProfile()) continue;
1382 
1383             if (hasUnifiedChallenge(profile.id)) {
1384                 if (mUserManager.isUserRunning(profile.id)) {
1385                     // Unlock managed profile with unified lock
1386                     // Must pass the challenge on for resetLockout, so it's not over-written, which
1387                     // causes LockSettingsService to revokeChallenge inappropriately.
1388                     unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */,
1389                             challengeType, challenge, resetLockouts);
1390                 } else {
1391                     try {
1392                         // Profile not ready for unlock yet, but decrypt the unified challenge now
1393                         // so it goes into the cache
1394                         getDecryptedPasswordForTiedProfile(profile.id);
1395                     } catch (GeneralSecurityException | IOException e) {
1396                         Slog.d(TAG, "Cache work profile password failed", e);
1397                     }
1398                 }
1399             }
1400             // Now we have unlocked the parent user and attempted to unlock the profile we should
1401             // show notifications if the profile is still locked.
1402             if (!alreadyUnlocked) {
1403                 long ident = clearCallingIdentity();
1404                 try {
1405                     maybeShowEncryptionNotificationForUser(profile.id);
1406                 } finally {
1407                     restoreCallingIdentity(ident);
1408                 }
1409             }
1410 
1411         }
1412 
1413         if (resetLockouts != null && !resetLockouts.isEmpty()) {
1414             mHandler.post(() -> {
1415                 final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
1416                 final PackageManager pm = mContext.getPackageManager();
1417                 for (int i = 0; i < resetLockouts.size(); i++) {
1418                     bm.setActiveUser(resetLockouts.get(i).mUserId);
1419                     bm.resetLockout(resetLockouts.get(i).mHAT);
1420                 }
1421                 if (challengeType == CHALLENGE_INTERNAL
1422                         && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
1423                     mContext.getSystemService(FaceManager.class).revokeChallenge();
1424                 }
1425             });
1426         }
1427     }
1428 
hasUnifiedChallenge(int userId)1429     private boolean hasUnifiedChallenge(int userId) {
1430         return !getSeparateProfileChallengeEnabledInternal(userId)
1431                 && mStorage.hasChildProfileLock(userId);
1432     }
1433 
getDecryptedPasswordsForAllTiedProfiles(int userId)1434     private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
1435         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1436             return null;
1437         }
1438         Map<Integer, LockscreenCredential> result = new ArrayMap<>();
1439         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1440         final int size = profiles.size();
1441         for (int i = 0; i < size; i++) {
1442             final UserInfo profile = profiles.get(i);
1443             if (!profile.isManagedProfile()) {
1444                 continue;
1445             }
1446             final int managedUserId = profile.id;
1447             if (getSeparateProfileChallengeEnabledInternal(managedUserId)) {
1448                 continue;
1449             }
1450             try {
1451                 result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId));
1452             } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
1453                     | NoSuchPaddingException | InvalidKeyException
1454                     | InvalidAlgorithmParameterException | IllegalBlockSizeException
1455                     | BadPaddingException | CertificateException | IOException e) {
1456                 Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " +
1457                     managedUserId, e);
1458             }
1459         }
1460         return result;
1461     }
1462 
1463     /**
1464      * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1465      * depending on the parent user's secure state.
1466      *
1467      * When clearing tied work challenges, a pre-computed password table for profiles are required,
1468      * since changing password for profiles requires existing password, and existing passwords can
1469      * only be computed before the parent user's password is cleared.
1470      *
1471      * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1472      * method again on profiles. However the recursion is guaranteed to terminate as this method
1473      * terminates when the user is a managed profile.
1474      */
synchronizeUnifiedWorkChallengeForProfiles(int userId, Map<Integer, LockscreenCredential> profilePasswordMap)1475     private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1476             Map<Integer, LockscreenCredential> profilePasswordMap) {
1477         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1478             return;
1479         }
1480         final boolean isSecure = isUserSecure(userId);
1481         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1482         final int size = profiles.size();
1483         for (int i = 0; i < size; i++) {
1484             final UserInfo profile = profiles.get(i);
1485             if (profile.isManagedProfile()) {
1486                 final int managedUserId = profile.id;
1487                 if (getSeparateProfileChallengeEnabledInternal(managedUserId)) {
1488                     continue;
1489                 }
1490                 if (isSecure) {
1491                     tieManagedProfileLockIfNecessary(managedUserId,
1492                             LockscreenCredential.createNone());
1493                 } else {
1494                     // We use cached work profile password computed before clearing the parent's
1495                     // credential, otherwise they get lost
1496                     if (profilePasswordMap != null
1497                             && profilePasswordMap.containsKey(managedUserId)) {
1498                         setLockCredentialInternal(LockscreenCredential.createNone(),
1499                                 profilePasswordMap.get(managedUserId),
1500                                 managedUserId,
1501                                 /* isLockTiedToParent= */ true);
1502                         mStorage.removeChildProfileLock(managedUserId);
1503                         removeKeystoreProfileKey(managedUserId);
1504                     } else {
1505                         Slog.wtf(TAG, "Attempt to clear tied challenge, but no password supplied.");
1506                     }
1507                 }
1508             }
1509         }
1510     }
1511 
isManagedProfileWithUnifiedLock(int userId)1512     private boolean isManagedProfileWithUnifiedLock(int userId) {
1513         return mUserManager.getUserInfo(userId).isManagedProfile()
1514                 && !getSeparateProfileChallengeEnabledInternal(userId);
1515     }
1516 
isManagedProfileWithSeparatedLock(int userId)1517     private boolean isManagedProfileWithSeparatedLock(int userId) {
1518         return mUserManager.getUserInfo(userId).isManagedProfile()
1519                 && getSeparateProfileChallengeEnabledInternal(userId);
1520     }
1521 
1522     /**
1523      * Send credentials for user {@code userId} to {@link RecoverableKeyStoreManager} during an
1524      * unlock operation.
1525      */
sendCredentialsOnUnlockIfRequired(LockscreenCredential credential, int userId)1526     private void sendCredentialsOnUnlockIfRequired(LockscreenCredential credential, int userId) {
1527         // Don't send credentials during the factory reset protection flow.
1528         if (userId == USER_FRP) {
1529             return;
1530         }
1531 
1532         // A profile with a unified lock screen stores a randomly generated credential, so skip it.
1533         // Its parent will send credentials for the profile, as it stores the unified lock
1534         // credential.
1535         if (isManagedProfileWithUnifiedLock(userId)) {
1536             return;
1537         }
1538 
1539         // RecoverableKeyStoreManager expects null for empty credential.
1540         final byte[] secret = credential.isNone() ? null : credential.getCredential();
1541         // Send credentials for the user and any child profiles that share its lock screen.
1542         for (int profileId : getProfilesWithSameLockScreen(userId)) {
1543             mRecoverableKeyStoreManager.lockScreenSecretAvailable(
1544                     credential.getType(), secret, profileId);
1545         }
1546     }
1547 
1548     /**
1549      * Send credentials for user {@code userId} to {@link RecoverableKeyStoreManager} when its
1550      * credentials are set/changed.
1551      */
sendCredentialsOnChangeIfRequired( LockscreenCredential credential, int userId, boolean isLockTiedToParent)1552     private void sendCredentialsOnChangeIfRequired(
1553             LockscreenCredential credential, int userId, boolean isLockTiedToParent) {
1554         // A profile whose lock screen is being tied to its parent's will either have a randomly
1555         // generated credential (creation) or null (removal). We rely on the parent to send its
1556         // credentials for the profile in both cases as it stores the unified lock credential.
1557         if (isLockTiedToParent) {
1558             return;
1559         }
1560 
1561         // RecoverableKeyStoreManager expects null for empty credential.
1562         final byte[] secret = credential.isNone() ? null : credential.getCredential();
1563         // Send credentials for the user and any child profiles that share its lock screen.
1564         for (int profileId : getProfilesWithSameLockScreen(userId)) {
1565             mRecoverableKeyStoreManager.lockScreenSecretChanged(
1566                     credential.getType(), secret, profileId);
1567         }
1568     }
1569 
1570     /**
1571      * Returns all profiles of {@code userId}, including itself, that have the same lock screen
1572      * challenge.
1573      */
getProfilesWithSameLockScreen(int userId)1574     private Set<Integer> getProfilesWithSameLockScreen(int userId) {
1575         Set<Integer> profiles = new ArraySet<>();
1576         for (UserInfo profile : mUserManager.getProfiles(userId)) {
1577             if (profile.id == userId
1578                     || (profile.profileGroupId == userId
1579                             && isManagedProfileWithUnifiedLock(profile.id))) {
1580                 profiles.add(profile.id);
1581             }
1582         }
1583         return profiles;
1584     }
1585 
1586     // This method should be called by LockPatternUtil only, all internal methods in this class
1587     // should call setLockCredentialInternal.
1588     @Override
setLockCredential(LockscreenCredential credential, LockscreenCredential savedCredential, int userId)1589     public boolean setLockCredential(LockscreenCredential credential,
1590             LockscreenCredential savedCredential, int userId) {
1591 
1592         if (!mHasSecureLockScreen) {
1593             throw new UnsupportedOperationException(
1594                     "This operation requires secure lock screen feature");
1595         }
1596         checkWritePermission(userId);
1597         enforceFrpResolved();
1598 
1599         // When changing credential for profiles with unified challenge, some callers
1600         // will pass in empty credential while others will pass in the credential of
1601         // the parent user. setLockCredentialInternal() handles the formal case (empty
1602         // credential) correctly but not the latter. As a stopgap fix, convert the latter
1603         // case to the formal. The long-term fix would be fixing LSS such that it should
1604         // accept only the parent user credential on its public API interfaces, swap it
1605         // with the profile's random credential at that API boundary (i.e. here) and make
1606         // sure LSS internally does not special case profile with unififed challenge: b/80170828.
1607         if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
1608             // Verify the parent credential again, to make sure we have a fresh enough
1609             // auth token such that getDecryptedPasswordForTiedProfile() inside
1610             // setLockCredentialInternal() can function correctly.
1611             verifyCredential(savedCredential, /* challenge */ 0,
1612                     mUserManager.getProfileParent(userId).id);
1613             savedCredential.zeroize();
1614             savedCredential = LockscreenCredential.createNone();
1615         }
1616         synchronized (mSeparateChallengeLock) {
1617             if (!setLockCredentialInternal(credential, savedCredential,
1618                     userId, /* isLockTiedToParent= */ false)) {
1619                 scheduleGc();
1620                 return false;
1621             }
1622             setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
1623             notifyPasswordChanged(userId);
1624         }
1625         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1626             // Make sure the profile doesn't get locked straight after setting work challenge.
1627             setDeviceUnlockedForUser(userId);
1628         }
1629         notifySeparateProfileChallengeChanged(userId);
1630         scheduleGc();
1631         return true;
1632     }
1633 
1634     /**
1635      * @param savedCredential if the user is a managed profile with unified challenge and
1636      *   savedCredential is empty, LSS will try to re-derive the profile password internally.
1637      *     TODO (b/80170828): Fix this so profile password is always passed in.
1638      * @param isLockTiedToParent is {@code true} if {@code userId} is a profile and its new
1639      *     credentials are being tied to its parent's credentials.
1640      */
setLockCredentialInternal(LockscreenCredential credential, LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent)1641     private boolean setLockCredentialInternal(LockscreenCredential credential,
1642             LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
1643         Objects.requireNonNull(credential);
1644         Objects.requireNonNull(savedCredential);
1645         synchronized (mSpManager) {
1646             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1647                 return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
1648                         isLockTiedToParent);
1649             }
1650         }
1651 
1652         if (credential.isNone()) {
1653             clearUserKeyProtection(userId, null);
1654             gateKeeperClearSecureUserId(userId);
1655             mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
1656             // Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path,
1657             // since it forms part of the state that determines the credential type
1658             // @see getCredentialTypeInternal
1659             setKeyguardStoredQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
1660             setKeystorePassword(null, userId);
1661             fixateNewestUserKeyAuth(userId);
1662             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1663             setUserPasswordMetrics(LockscreenCredential.createNone(), userId);
1664             sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
1665             return true;
1666         }
1667 
1668         CredentialHash currentHandle = mStorage.readCredentialHash(userId);
1669         if (isManagedProfileWithUnifiedLock(userId)) {
1670             // get credential from keystore when managed profile has unified lock
1671             if (savedCredential.isNone()) {
1672                 try {
1673                     //TODO: remove as part of b/80170828
1674                     savedCredential = getDecryptedPasswordForTiedProfile(userId);
1675                 } catch (FileNotFoundException e) {
1676                     Slog.i(TAG, "Child profile key not found");
1677                 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1678                         | NoSuchAlgorithmException | NoSuchPaddingException
1679                         | InvalidAlgorithmParameterException | IllegalBlockSizeException
1680                         | BadPaddingException | CertificateException | IOException e) {
1681                     Slog.e(TAG, "Failed to decrypt child profile key", e);
1682                 }
1683             }
1684         } else {
1685             if (currentHandle.hash == null) {
1686                 if (!savedCredential.isNone()) {
1687                     Slog.w(TAG, "Saved credential provided, but none stored");
1688                 }
1689                 savedCredential.close();
1690                 savedCredential = LockscreenCredential.createNone();
1691             }
1692         }
1693         synchronized (mSpManager) {
1694             if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1695                 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId);
1696                 return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
1697                         isLockTiedToParent);
1698             }
1699         }
1700         if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
1701         byte[] enrolledHandle = enrollCredential(currentHandle.hash,
1702                 savedCredential.getCredential(), credential.getCredential(), userId);
1703         if (enrolledHandle == null) {
1704             Slog.w(TAG, String.format("Failed to enroll %s: incorrect credential",
1705                     credential.isPattern() ? "pattern" : "password"));
1706             return false;
1707         }
1708         CredentialHash willStore = CredentialHash.create(enrolledHandle, credential.getType());
1709         mStorage.writeCredentialHash(willStore, userId);
1710         // Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path,
1711         // since it forms part of the state that determines the credential type
1712         // @see getCredentialTypeInternal
1713         setKeyguardStoredQuality(
1714                 LockPatternUtils.credentialTypeToPasswordQuality(credential.getType()), userId);
1715         // push new secret and auth token to vold
1716         GateKeeperResponse gkResponse;
1717         try {
1718             gkResponse = getGateKeeperService().verifyChallenge(userId, 0, willStore.hash,
1719                     credential.getCredential());
1720         } catch (RemoteException e) {
1721             throw new IllegalStateException("Failed to verify current credential", e);
1722         }
1723         setUserKeyProtection(userId, credential, convertResponse(gkResponse));
1724         fixateNewestUserKeyAuth(userId);
1725         // Refresh the auth token
1726         doVerifyCredential(credential, CHALLENGE_FROM_CALLER, 0, userId,
1727                 null /* progressCallback */);
1728         synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1729         sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
1730         return true;
1731     }
1732 
convertResponse(GateKeeperResponse gateKeeperResponse)1733     private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
1734         return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
1735     }
1736 
1737     @VisibleForTesting /** Note: this method is overridden in unit tests */
tieProfileLockToParent(int userId, LockscreenCredential password)1738     protected void tieProfileLockToParent(int userId, LockscreenCredential password) {
1739         if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1740         byte[] encryptionResult;
1741         byte[] iv;
1742         try {
1743             KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1744             keyGenerator.init(new SecureRandom());
1745             SecretKey secretKey = keyGenerator.generateKey();
1746             java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1747             keyStore.load(null);
1748             try {
1749                 keyStore.setEntry(
1750                         LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1751                         new java.security.KeyStore.SecretKeyEntry(secretKey),
1752                         new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1753                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1754                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1755                                 .build());
1756                 keyStore.setEntry(
1757                         LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1758                         new java.security.KeyStore.SecretKeyEntry(secretKey),
1759                         new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1760                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1761                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1762                                 .setUserAuthenticationRequired(true)
1763                                 .setUserAuthenticationValidityDurationSeconds(30)
1764                                 .setCriticalToDeviceEncryption(true)
1765                                 .build());
1766                 // Key imported, obtain a reference to it.
1767                 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1768                         LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1769                 Cipher cipher = Cipher.getInstance(
1770                         KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1771                                 + KeyProperties.ENCRYPTION_PADDING_NONE);
1772                 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1773                 encryptionResult = cipher.doFinal(password.getCredential());
1774                 iv = cipher.getIV();
1775             } finally {
1776                 // The original key can now be discarded.
1777                 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1778             }
1779         } catch (CertificateException | UnrecoverableKeyException
1780                 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
1781                 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1782             throw new IllegalStateException("Failed to encrypt key", e);
1783         }
1784         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1785         try {
1786             if (iv.length != PROFILE_KEY_IV_SIZE) {
1787                 throw new IllegalArgumentException("Invalid iv length: " + iv.length);
1788             }
1789             outputStream.write(iv);
1790             outputStream.write(encryptionResult);
1791         } catch (IOException e) {
1792             throw new IllegalStateException("Failed to concatenate byte arrays", e);
1793         }
1794         mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1795     }
1796 
enrollCredential(byte[] enrolledHandle, byte[] enrolledCredential, byte[] toEnroll, int userId)1797     private byte[] enrollCredential(byte[] enrolledHandle,
1798             byte[] enrolledCredential, byte[] toEnroll, int userId) {
1799         checkWritePermission(userId);
1800         GateKeeperResponse response;
1801         try {
1802             response = getGateKeeperService().enroll(userId, enrolledHandle,
1803                     enrolledCredential, toEnroll);
1804         } catch (RemoteException e) {
1805             Slog.e(TAG, "Failed to enroll credential", e);
1806             return null;
1807         }
1808 
1809         if (response == null) {
1810             return null;
1811         }
1812 
1813         byte[] hash = response.getPayload();
1814         if (hash != null) {
1815             setKeystorePassword(toEnroll, userId);
1816         } else {
1817             // Should not happen
1818             Slog.e(TAG, "Throttled while enrolling a password");
1819         }
1820         return hash;
1821     }
1822 
setAuthlessUserKeyProtection(int userId, byte[] key)1823     private void setAuthlessUserKeyProtection(int userId, byte[] key) {
1824         if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1825         addUserKeyAuth(userId, null, key);
1826     }
1827 
setUserKeyProtection(int userId, LockscreenCredential credential, VerifyCredentialResponse vcr)1828     private void setUserKeyProtection(int userId, LockscreenCredential credential,
1829             VerifyCredentialResponse vcr) {
1830         if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
1831         if (vcr == null) {
1832             throw new IllegalArgumentException("Null response verifying a credential we just set");
1833         }
1834         if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1835             throw new IllegalArgumentException("Non-OK response verifying a credential we just set "
1836                     + vcr.getResponseCode());
1837         }
1838         byte[] token = vcr.getPayload();
1839         if (token == null) {
1840             throw new IllegalArgumentException("Empty payload verifying a credential we just set");
1841         }
1842         addUserKeyAuth(userId, token, secretFromCredential(credential));
1843     }
1844 
clearUserKeyProtection(int userId, byte[] secret)1845     private void clearUserKeyProtection(int userId, byte[] secret) {
1846         if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
1847         final UserInfo userInfo = mUserManager.getUserInfo(userId);
1848         final long callingId = Binder.clearCallingIdentity();
1849         try {
1850             mStorageManager.clearUserKeyAuth(userId, userInfo.serialNumber, null, secret);
1851         } catch (RemoteException e) {
1852             throw new IllegalStateException("clearUserKeyAuth failed user=" + userId);
1853         } finally {
1854             Binder.restoreCallingIdentity(callingId);
1855         }
1856     }
1857 
secretFromCredential(LockscreenCredential credential)1858     private static byte[] secretFromCredential(LockscreenCredential credential) {
1859         try {
1860             MessageDigest digest = MessageDigest.getInstance("SHA-512");
1861             // Personalize the hash
1862             byte[] personalization = "Android FBE credential hash".getBytes();
1863             // Pad it to the block size of the hash function
1864             personalization = Arrays.copyOf(personalization, 128);
1865             digest.update(personalization);
1866             digest.update(credential.getCredential());
1867             return digest.digest();
1868         } catch (NoSuchAlgorithmException e) {
1869             throw new IllegalStateException("NoSuchAlgorithmException for SHA-512");
1870         }
1871     }
1872 
isUserKeyUnlocked(int userId)1873     private boolean isUserKeyUnlocked(int userId) {
1874         try {
1875             return mStorageManager.isUserKeyUnlocked(userId);
1876         } catch (RemoteException e) {
1877             Slog.e(TAG, "failed to check user key locked state", e);
1878             return false;
1879         }
1880     }
1881 
1882     /** Unlock disk encryption */
unlockUserKey(int userId, byte[] token, byte[] secret)1883     private void unlockUserKey(int userId, byte[] token, byte[] secret) {
1884         final UserInfo userInfo = mUserManager.getUserInfo(userId);
1885         try {
1886             mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
1887         } catch (RemoteException e) {
1888             throw new IllegalStateException("Failed to unlock user key " + userId, e);
1889 
1890         }
1891     }
1892 
addUserKeyAuth(int userId, byte[] token, byte[] secret)1893     private void addUserKeyAuth(int userId, byte[] token, byte[] secret) {
1894         final UserInfo userInfo = mUserManager.getUserInfo(userId);
1895         final long callingId = Binder.clearCallingIdentity();
1896         try {
1897             mStorageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
1898         } catch (RemoteException e) {
1899             throw new IllegalStateException("Failed to add new key to vold " + userId, e);
1900         } finally {
1901             Binder.restoreCallingIdentity(callingId);
1902         }
1903     }
1904 
fixateNewestUserKeyAuth(int userId)1905     private void fixateNewestUserKeyAuth(int userId) {
1906         if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
1907         final long callingId = Binder.clearCallingIdentity();
1908         try {
1909             mStorageManager.fixateNewestUserKeyAuth(userId);
1910         } catch (RemoteException e) {
1911             // OK to ignore the exception as vold would just accept both old and new
1912             // keys if this call fails, and will fix itself during the next boot
1913             Slog.w(TAG, "fixateNewestUserKeyAuth failed", e);
1914         } finally {
1915             Binder.restoreCallingIdentity(callingId);
1916         }
1917     }
1918 
1919     @Override
resetKeyStore(int userId)1920     public void resetKeyStore(int userId) {
1921         checkWritePermission(userId);
1922         if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1923         int managedUserId = -1;
1924         LockscreenCredential managedUserDecryptedPassword = null;
1925         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1926         for (UserInfo pi : profiles) {
1927             // Unlock managed profile with unified lock
1928             if (pi.isManagedProfile()
1929                     && !getSeparateProfileChallengeEnabledInternal(pi.id)
1930                     && mStorage.hasChildProfileLock(pi.id)) {
1931                 try {
1932                     if (managedUserId == -1) {
1933                         managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1934                         managedUserId = pi.id;
1935                     } else {
1936                         // Should not happen
1937                         Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1938                                 + ", uid2:" + pi.id);
1939                     }
1940                 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1941                         | NoSuchAlgorithmException | NoSuchPaddingException
1942                         | InvalidAlgorithmParameterException | IllegalBlockSizeException
1943                         | BadPaddingException | CertificateException | IOException e) {
1944                     Slog.e(TAG, "Failed to decrypt child profile key", e);
1945                 }
1946             }
1947         }
1948         try {
1949             // Clear all the users credentials could have been installed in for this user.
1950             for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1951                 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1952                     mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1953                 }
1954             }
1955         } finally {
1956             if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1957                 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
1958                 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
1959             }
1960         }
1961         if (managedUserDecryptedPassword != null) {
1962             managedUserDecryptedPassword.zeroize();
1963         }
1964     }
1965 
1966     @Override
checkCredential(LockscreenCredential credential, int userId, ICheckCredentialProgressCallback progressCallback)1967     public VerifyCredentialResponse checkCredential(LockscreenCredential credential, int userId,
1968             ICheckCredentialProgressCallback progressCallback) {
1969         checkPasswordReadPermission(userId);
1970         try {
1971             return doVerifyCredential(credential, CHALLENGE_NONE, 0, userId, progressCallback);
1972         } finally {
1973             scheduleGc();
1974         }
1975     }
1976 
1977     @Override
verifyCredential(LockscreenCredential credential, long challenge, int userId)1978     public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
1979             long challenge, int userId) {
1980         checkPasswordReadPermission(userId);
1981         @ChallengeType int challengeType = CHALLENGE_FROM_CALLER;
1982         if (challenge == 0) {
1983             Slog.w(TAG, "VerifyCredential called with challenge=0");
1984             challengeType = CHALLENGE_NONE;
1985 
1986         }
1987         try {
1988             return doVerifyCredential(credential, challengeType, challenge, userId,
1989                     null /* progressCallback */);
1990         } finally {
1991             scheduleGc();
1992         }
1993     }
1994 
doVerifyCredential(LockscreenCredential credential, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback)1995     private VerifyCredentialResponse doVerifyCredential(LockscreenCredential credential,
1996             @ChallengeType int challengeType, long challenge, int userId,
1997             ICheckCredentialProgressCallback progressCallback) {
1998         return doVerifyCredential(credential, challengeType, challenge, userId,
1999                 progressCallback, null /* resetLockouts */);
2000     }
2001 
2002     /**
2003      * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
2004      * format.
2005      */
doVerifyCredential(LockscreenCredential credential, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback, @Nullable ArrayList<PendingResetLockout> resetLockouts)2006     private VerifyCredentialResponse doVerifyCredential(LockscreenCredential credential,
2007             @ChallengeType int challengeType, long challenge, int userId,
2008             ICheckCredentialProgressCallback progressCallback,
2009             @Nullable ArrayList<PendingResetLockout> resetLockouts) {
2010         if (credential == null || credential.isNone()) {
2011             throw new IllegalArgumentException("Credential can't be null or empty");
2012         }
2013         if (userId == USER_FRP && mInjector.settingsGlobalGetInt(mContext.getContentResolver(),
2014                 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
2015             Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
2016             return VerifyCredentialResponse.ERROR;
2017         }
2018         VerifyCredentialResponse response = null;
2019         response = spBasedDoVerifyCredential(credential, challengeType, challenge,
2020                 userId, progressCallback, resetLockouts);
2021         // The user employs synthetic password based credential.
2022         if (response != null) {
2023             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2024                 sendCredentialsOnUnlockIfRequired(credential, userId);
2025             }
2026             return response;
2027         }
2028 
2029         if (userId == USER_FRP) {
2030             Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
2031             return VerifyCredentialResponse.ERROR;
2032         }
2033 
2034         final CredentialHash storedHash = mStorage.readCredentialHash(userId);
2035         if (!credential.checkAgainstStoredType(storedHash.type)) {
2036             Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
2037                     + " stored: " + storedHash.type + " passed in: " + credential.getType());
2038             return VerifyCredentialResponse.ERROR;
2039         }
2040 
2041         response = verifyCredential(userId, storedHash, credential,
2042                 challengeType, challenge, progressCallback);
2043 
2044         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2045             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
2046         }
2047 
2048         return response;
2049     }
2050 
2051     @Override
verifyTiedProfileChallenge(LockscreenCredential credential, long challenge, int userId)2052     public VerifyCredentialResponse verifyTiedProfileChallenge(LockscreenCredential credential,
2053             long challenge, int userId) {
2054         checkPasswordReadPermission(userId);
2055         if (!isManagedProfileWithUnifiedLock(userId)) {
2056             throw new IllegalArgumentException("User id must be managed profile with unified lock");
2057         }
2058         final int parentProfileId = mUserManager.getProfileParent(userId).id;
2059         // Unlock parent by using parent's challenge
2060         final VerifyCredentialResponse parentResponse = doVerifyCredential(
2061                 credential,
2062                 CHALLENGE_FROM_CALLER,
2063                 challenge,
2064                 parentProfileId,
2065                 null /* progressCallback */);
2066         if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2067             // Failed, just return parent's response
2068             return parentResponse;
2069         }
2070 
2071         try {
2072             // Unlock work profile, and work profile with unified lock must use password only
2073             return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
2074                     CHALLENGE_FROM_CALLER,
2075                     challenge,
2076                     userId, null /* progressCallback */);
2077         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2078                 | NoSuchAlgorithmException | NoSuchPaddingException
2079                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
2080                 | BadPaddingException | CertificateException | IOException e) {
2081             Slog.e(TAG, "Failed to decrypt child profile key", e);
2082             throw new IllegalStateException("Unable to get tied profile token");
2083         } finally {
2084             scheduleGc();
2085         }
2086     }
2087 
2088     /**
2089      * Lowest-level credential verification routine that talks to GateKeeper. If verification
2090      * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
2091      * hash to GK.
2092      */
verifyCredential(int userId, CredentialHash storedHash, LockscreenCredential credential, @ChallengeType int challengeType, long challenge, ICheckCredentialProgressCallback progressCallback)2093     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
2094             LockscreenCredential credential, @ChallengeType int challengeType, long challenge,
2095             ICheckCredentialProgressCallback progressCallback) {
2096         if ((storedHash == null || storedHash.hash.length == 0) && credential.isNone()) {
2097             // don't need to pass empty credentials to GateKeeper
2098             return VerifyCredentialResponse.OK;
2099         }
2100 
2101         if (storedHash == null || storedHash.hash.length == 0 || credential.isNone()) {
2102             return VerifyCredentialResponse.ERROR;
2103         }
2104 
2105         // We're potentially going to be doing a bunch of disk I/O below as part
2106         // of unlocking the user, so yell if calling from the main thread.
2107         StrictMode.noteDiskRead();
2108 
2109         GateKeeperResponse gateKeeperResponse;
2110         try {
2111             gateKeeperResponse = getGateKeeperService().verifyChallenge(
2112                     userId, challenge, storedHash.hash, credential.getCredential());
2113         } catch (RemoteException e) {
2114             Slog.e(TAG, "gatekeeper verify failed", e);
2115             gateKeeperResponse = GateKeeperResponse.ERROR;
2116         }
2117         VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
2118         boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
2119 
2120         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2121 
2122             // credential has matched
2123 
2124             if (progressCallback != null) {
2125                 try {
2126                     progressCallback.onCredentialVerified();
2127                 } catch (RemoteException e) {
2128                     Slog.w(TAG, "progressCallback throws exception", e);
2129                 }
2130             }
2131             setUserPasswordMetrics(credential, userId);
2132             unlockKeystore(credential.getCredential(), userId);
2133 
2134             Slog.i(TAG, "Unlocking user " + userId + " with token length "
2135                     + response.getPayload().length);
2136             unlockUser(userId, response.getPayload(), secretFromCredential(credential));
2137 
2138             if (isManagedProfileWithSeparatedLock(userId)) {
2139                 setDeviceUnlockedForUser(userId);
2140             }
2141             if (shouldReEnroll) {
2142                 setLockCredentialInternal(credential, credential,
2143                         userId, /* isLockTiedToParent= */ false);
2144             } else {
2145                 // Now that we've cleared of all required GK migration, let's do the final
2146                 // migration to synthetic password.
2147                 synchronized (mSpManager) {
2148                     if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2149                         AuthenticationToken auth = initializeSyntheticPasswordLocked(
2150                                 storedHash.hash, credential,  userId);
2151                         activateEscrowTokens(auth, userId);
2152                     }
2153                 }
2154             }
2155             // Use credentials to create recoverable keystore snapshot.
2156             sendCredentialsOnUnlockIfRequired(credential, userId);
2157 
2158         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
2159             if (response.getTimeout() > 0) {
2160                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
2161             }
2162         }
2163 
2164         return response;
2165     }
2166 
2167     /**
2168      * Keep track of the given user's latest password metric. This should be called
2169      * when the user is authenticating or when a new password is being set. In comparison,
2170      * {@link #notifyPasswordChanged} only needs to be called when the user changes the password.
2171      */
setUserPasswordMetrics(LockscreenCredential password, @UserIdInt int userHandle)2172     private void setUserPasswordMetrics(LockscreenCredential password, @UserIdInt int userHandle) {
2173         synchronized (this) {
2174             mUserPasswordMetrics.put(userHandle, PasswordMetrics.computeForCredential(password));
2175         }
2176     }
2177 
2178     @VisibleForTesting
getUserPasswordMetrics(int userHandle)2179     PasswordMetrics getUserPasswordMetrics(int userHandle) {
2180         if (!isUserSecure(userHandle)) {
2181             // for users without password, mUserPasswordMetrics might not be initialized
2182             // since the user never unlock the device manually. In this case, always
2183             // return a default metrics object. This is to distinguish this case from
2184             // the case where during boot user password is unknown yet (returning null here)
2185             return new PasswordMetrics(CREDENTIAL_TYPE_NONE);
2186         }
2187         synchronized (this) {
2188             return mUserPasswordMetrics.get(userHandle);
2189         }
2190     }
2191 
loadPasswordMetrics(AuthenticationToken auth, int userHandle)2192     private PasswordMetrics loadPasswordMetrics(AuthenticationToken auth, int userHandle) {
2193         synchronized (mSpManager) {
2194             return mSpManager.getPasswordMetrics(auth, getSyntheticPasswordHandleLocked(userHandle),
2195                     userHandle);
2196         }
2197     }
2198 
2199     /**
2200      * Call after {@link #setUserPasswordMetrics} so metrics are updated before
2201      * reporting the password changed.
2202      */
notifyPasswordChanged(@serIdInt int userId)2203     private void notifyPasswordChanged(@UserIdInt int userId) {
2204         mHandler.post(() -> {
2205             mInjector.getDevicePolicyManager().reportPasswordChanged(userId);
2206             LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId);
2207         });
2208     }
2209 
createPattern(String patternString)2210     private LockscreenCredential createPattern(String patternString) {
2211         final byte[] patternBytes = patternString.getBytes();
2212         LockscreenCredential pattern = LockscreenCredential.createPattern(
2213                 LockPatternUtils.byteArrayToPattern(patternBytes));
2214         Arrays.fill(patternBytes, (byte) 0);
2215         return pattern;
2216     }
2217 
2218     @Override
checkVoldPassword(int userId)2219     public boolean checkVoldPassword(int userId) {
2220         if (!mFirstCallToVold) {
2221             return false;
2222         }
2223         mFirstCallToVold = false;
2224 
2225         checkPasswordReadPermission(userId);
2226 
2227         // There's no guarantee that this will safely connect, but if it fails
2228         // we will simply show the lock screen when we shouldn't, so relatively
2229         // benign. There is an outside chance something nasty would happen if
2230         // this service restarted before vold stales out the password in this
2231         // case. The nastiness is limited to not showing the lock screen when
2232         // we should, within the first minute of decrypting the phone if this
2233         // service can't connect to vold, it restarts, and then the new instance
2234         // does successfully connect.
2235         final IStorageManager service = mInjector.getStorageManager();
2236         // TODO(b/120484642): Update vold to return a password as a byte array
2237         String password;
2238         long identity = Binder.clearCallingIdentity();
2239         try {
2240             password = service.getPassword();
2241             service.clearPassword();
2242         } catch (RemoteException e) {
2243             Slog.w(TAG, "vold getPassword() failed", e);
2244             return false;
2245         } finally {
2246             Binder.restoreCallingIdentity(identity);
2247         }
2248         if (TextUtils.isEmpty(password)) {
2249             return false;
2250         }
2251 
2252         try {
2253             final LockscreenCredential credential;
2254             switch (getCredentialTypeInternal(userId)) {
2255                 case CREDENTIAL_TYPE_PATTERN:
2256                     credential = createPattern(password);
2257                     break;
2258                 case CREDENTIAL_TYPE_PIN:
2259                     credential = LockscreenCredential.createPin(password);
2260                     break;
2261                 case CREDENTIAL_TYPE_PASSWORD:
2262                     credential = LockscreenCredential.createPassword(password);
2263                     break;
2264                 default:
2265                     credential = null;
2266                     Slog.e(TAG, "Unknown credential type");
2267             }
2268 
2269             if (credential != null
2270                     && checkCredential(credential, userId, null /* progressCallback */)
2271                                 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
2272                 return true;
2273             }
2274         } catch (Exception e) {
2275             Slog.e(TAG, "checkVoldPassword failed: ", e);
2276         }
2277 
2278         return false;
2279     }
2280 
removeUser(int userId, boolean unknownUser)2281     private void removeUser(int userId, boolean unknownUser) {
2282         Slog.i(TAG, "RemoveUser: " + userId);
2283         mSpManager.removeUser(userId);
2284         mStrongAuth.removeUser(userId);
2285 
2286         final KeyStore ks = KeyStore.getInstance();
2287         ks.onUserRemoved(userId);
2288         mManagedProfilePasswordCache.removePassword(userId);
2289 
2290         gateKeeperClearSecureUserId(userId);
2291         if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
2292             removeKeystoreProfileKey(userId);
2293         }
2294         // Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
2295         // can make the assumption that no USER_SERIAL_NUMBER_KEY means user is fully removed.
2296         mStorage.removeUser(userId);
2297     }
2298 
removeKeystoreProfileKey(int targetUserId)2299     private void removeKeystoreProfileKey(int targetUserId) {
2300         Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId);
2301         try {
2302             java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
2303             keyStore.load(null);
2304             keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
2305             keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
2306         } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
2307                 | IOException e) {
2308             // We have tried our best to remove all keys
2309             Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
2310         }
2311     }
2312 
2313     @Override
registerStrongAuthTracker(IStrongAuthTracker tracker)2314     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
2315         checkPasswordReadPermission(UserHandle.USER_ALL);
2316         mStrongAuth.registerStrongAuthTracker(tracker);
2317     }
2318 
2319     @Override
unregisterStrongAuthTracker(IStrongAuthTracker tracker)2320     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
2321         checkPasswordReadPermission(UserHandle.USER_ALL);
2322         mStrongAuth.unregisterStrongAuthTracker(tracker);
2323     }
2324 
2325     @Override
requireStrongAuth(int strongAuthReason, int userId)2326     public void requireStrongAuth(int strongAuthReason, int userId) {
2327         checkWritePermission(userId);
2328         mStrongAuth.requireStrongAuth(strongAuthReason, userId);
2329     }
2330 
2331     @Override
reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId)2332     public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
2333         checkBiometricPermission();
2334         mStrongAuth.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
2335     }
2336 
2337     @Override
scheduleNonStrongBiometricIdleTimeout(int userId)2338     public void scheduleNonStrongBiometricIdleTimeout(int userId) {
2339         checkBiometricPermission();
2340         mStrongAuth.scheduleNonStrongBiometricIdleTimeout(userId);
2341     }
2342 
2343     @Override
userPresent(int userId)2344     public void userPresent(int userId) {
2345         checkWritePermission(userId);
2346         mStrongAuth.reportUnlock(userId);
2347     }
2348 
2349     @Override
getStrongAuthForUser(int userId)2350     public int getStrongAuthForUser(int userId) {
2351         checkPasswordReadPermission(userId);
2352         return mStrongAuthTracker.getStrongAuthForUser(userId);
2353     }
2354 
isCallerShell()2355     private boolean isCallerShell() {
2356         final int callingUid = Binder.getCallingUid();
2357         return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
2358     }
2359 
enforceShell()2360     private void enforceShell() {
2361         if (!isCallerShell()) {
2362             throw new SecurityException("Caller must be shell");
2363         }
2364     }
2365 
2366     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)2367     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2368             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
2369         enforceShell();
2370         final long origId = Binder.clearCallingIdentity();
2371         try {
2372             (new LockSettingsShellCommand(new LockPatternUtils(mContext))).exec(
2373                     this, in, out, err, args, callback, resultReceiver);
2374         } finally {
2375             Binder.restoreCallingIdentity(origId);
2376         }
2377     }
2378 
2379     @Override
initRecoveryServiceWithSigFile(@onNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile)2380     public void initRecoveryServiceWithSigFile(@NonNull String rootCertificateAlias,
2381             @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile)
2382             throws RemoteException {
2383         mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(rootCertificateAlias,
2384                 recoveryServiceCertFile, recoveryServiceSigFile);
2385     }
2386 
2387     @Override
getKeyChainSnapshot()2388     public @NonNull KeyChainSnapshot getKeyChainSnapshot() throws RemoteException {
2389         return mRecoverableKeyStoreManager.getKeyChainSnapshot();
2390     }
2391 
2392     @Override
setSnapshotCreatedPendingIntent(@ullable PendingIntent intent)2393     public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
2394             throws RemoteException {
2395         mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent);
2396     }
2397 
2398     @Override
setServerParams(byte[] serverParams)2399     public void setServerParams(byte[] serverParams) throws RemoteException {
2400         mRecoverableKeyStoreManager.setServerParams(serverParams);
2401     }
2402 
2403     @Override
setRecoveryStatus(String alias, int status)2404     public void setRecoveryStatus(String alias, int status) throws RemoteException {
2405         mRecoverableKeyStoreManager.setRecoveryStatus(alias, status);
2406     }
2407 
2408     @Override
getRecoveryStatus()2409     public @NonNull Map getRecoveryStatus() throws RemoteException {
2410         return mRecoverableKeyStoreManager.getRecoveryStatus();
2411     }
2412 
2413     @Override
setRecoverySecretTypes(@onNull @eyChainProtectionParams.UserSecretType int[] secretTypes)2414     public void setRecoverySecretTypes(@NonNull @KeyChainProtectionParams.UserSecretType
2415             int[] secretTypes) throws RemoteException {
2416         mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
2417     }
2418 
2419     @Override
getRecoverySecretTypes()2420     public @NonNull int[] getRecoverySecretTypes() throws RemoteException {
2421         return mRecoverableKeyStoreManager.getRecoverySecretTypes();
2422 
2423     }
2424 
2425     @Override
startRecoverySessionWithCertPath(@onNull String sessionId, @NonNull String rootCertificateAlias, @NonNull RecoveryCertPath verifierCertPath, @NonNull byte[] vaultParams, @NonNull byte[] vaultChallenge, @NonNull List<KeyChainProtectionParams> secrets)2426     public @NonNull byte[] startRecoverySessionWithCertPath(@NonNull String sessionId,
2427             @NonNull String rootCertificateAlias, @NonNull RecoveryCertPath verifierCertPath,
2428             @NonNull byte[] vaultParams, @NonNull byte[] vaultChallenge,
2429             @NonNull List<KeyChainProtectionParams> secrets)
2430             throws RemoteException {
2431         return mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
2432                 sessionId, rootCertificateAlias, verifierCertPath, vaultParams, vaultChallenge,
2433                 secrets);
2434     }
2435 
2436     @Override
recoverKeyChainSnapshot( @onNull String sessionId, @NonNull byte[] recoveryKeyBlob, @NonNull List<WrappedApplicationKey> applicationKeys)2437     public Map<String, String> recoverKeyChainSnapshot(
2438             @NonNull String sessionId,
2439             @NonNull byte[] recoveryKeyBlob,
2440             @NonNull List<WrappedApplicationKey> applicationKeys) throws RemoteException {
2441         return mRecoverableKeyStoreManager.recoverKeyChainSnapshot(
2442                 sessionId, recoveryKeyBlob, applicationKeys);
2443     }
2444 
2445     @Override
closeSession(@onNull String sessionId)2446     public void closeSession(@NonNull String sessionId) throws RemoteException {
2447         mRecoverableKeyStoreManager.closeSession(sessionId);
2448     }
2449 
2450     @Override
removeKey(@onNull String alias)2451     public void removeKey(@NonNull String alias) throws RemoteException {
2452         mRecoverableKeyStoreManager.removeKey(alias);
2453     }
2454 
2455     @Override
generateKey(@onNull String alias)2456     public @Nullable String generateKey(@NonNull String alias) throws RemoteException {
2457         return mRecoverableKeyStoreManager.generateKey(alias);
2458     }
2459 
2460     @Override
generateKeyWithMetadata( @onNull String alias, @Nullable byte[] metadata)2461     public @Nullable String generateKeyWithMetadata(
2462             @NonNull String alias, @Nullable byte[] metadata) throws RemoteException {
2463         return mRecoverableKeyStoreManager.generateKeyWithMetadata(alias, metadata);
2464     }
2465 
2466     @Override
importKey(@onNull String alias, @NonNull byte[] keyBytes)2467     public @Nullable String importKey(@NonNull String alias, @NonNull byte[] keyBytes)
2468             throws RemoteException {
2469         return mRecoverableKeyStoreManager.importKey(alias, keyBytes);
2470     }
2471 
2472     @Override
importKeyWithMetadata(@onNull String alias, @NonNull byte[] keyBytes, @Nullable byte[] metadata)2473     public @Nullable String importKeyWithMetadata(@NonNull String alias, @NonNull byte[] keyBytes,
2474             @Nullable byte[] metadata) throws RemoteException {
2475         return mRecoverableKeyStoreManager.importKeyWithMetadata(alias, keyBytes, metadata);
2476     }
2477 
2478     @Override
getKey(@onNull String alias)2479     public @Nullable String getKey(@NonNull String alias) throws RemoteException {
2480         return mRecoverableKeyStoreManager.getKey(alias);
2481     }
2482 
2483     private static final String[] VALID_SETTINGS = new String[] {
2484             LockPatternUtils.LOCKOUT_PERMANENT_KEY,
2485             LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
2486             LockPatternUtils.PASSWORD_TYPE_KEY,
2487             LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
2488             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2489             LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
2490             LockPatternUtils.LOCKSCREEN_OPTIONS,
2491             LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
2492             LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
2493             LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
2494             LockPatternUtils.PASSWORD_HISTORY_KEY,
2495             Secure.LOCK_PATTERN_ENABLED,
2496             Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
2497             Secure.LOCK_PATTERN_VISIBLE,
2498             Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
2499     };
2500 
2501     // Reading these settings needs the contacts permission
2502     private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
2503             Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
2504             Secure.LOCK_SCREEN_OWNER_INFO
2505     };
2506 
2507     // Reading these settings needs the same permission as checking the password
2508     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
2509             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2510             LockPatternUtils.PASSWORD_HISTORY_KEY,
2511             LockPatternUtils.PASSWORD_TYPE_KEY,
2512             SEPARATE_PROFILE_CHALLENGE_KEY
2513     };
2514 
2515     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
2516         @Override
binderDied()2517         public void binderDied() {
2518             mGateKeeperService.asBinder().unlinkToDeath(this, 0);
2519             mGateKeeperService = null;
2520         }
2521     }
2522 
getGateKeeperService()2523     protected synchronized IGateKeeperService getGateKeeperService() {
2524         if (mGateKeeperService != null) {
2525             return mGateKeeperService;
2526         }
2527 
2528         final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
2529         if (service != null) {
2530             try {
2531                 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
2532             } catch (RemoteException e) {
2533                 Slog.w(TAG, " Unable to register death recipient", e);
2534             }
2535             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
2536             return mGateKeeperService;
2537         }
2538 
2539         Slog.e(TAG, "Unable to acquire GateKeeperService");
2540         return null;
2541     }
2542 
gateKeeperClearSecureUserId(int userId)2543     private void gateKeeperClearSecureUserId(int userId) {
2544         try {
2545             getGateKeeperService().clearSecureUserId(userId);
2546         } catch (RemoteException e) {
2547             Slog.w(TAG, "Failed to clear SID", e);
2548         }
2549     }
2550 
onAuthTokenKnownForUser(@serIdInt int userId, AuthenticationToken auth)2551     private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
2552         if (mInjector.isGsiRunning()) {
2553             Slog.w(TAG, "Running in GSI; skipping calls to AuthSecret and RebootEscrow");
2554             return;
2555         }
2556 
2557         mRebootEscrowManager.callToRebootEscrowIfNeeded(userId, auth.getVersion(),
2558                 auth.getSyntheticPassword());
2559 
2560         callToAuthSecretIfNeeded(userId, auth);
2561     }
2562 
callToAuthSecretIfNeeded(@serIdInt int userId, AuthenticationToken auth)2563     private void callToAuthSecretIfNeeded(@UserIdInt int userId,
2564             AuthenticationToken auth) {
2565         // Pass the primary user's auth secret to the HAL
2566         if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
2567             try {
2568                 final byte[] rawSecret = auth.deriveVendorAuthSecret();
2569                 final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length);
2570                 for (int i = 0; i < rawSecret.length; ++i) {
2571                     secret.add(rawSecret[i]);
2572                 }
2573                 mAuthSecretService.primaryUserCredential(secret);
2574             } catch (RemoteException e) {
2575                 Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
2576             }
2577         }
2578     }
2579 
2580     /**
2581      * Precondition: vold and keystore unlocked.
2582      *
2583      * Create new synthetic password, set up synthetic password blob protected by the supplied
2584      * user credential, and make the newly-created SP blob active.
2585      *
2586      * The invariant under a synthetic password is:
2587      * 1. If user credential exists, then both vold and keystore and protected with keys derived
2588      *     from the synthetic password.
2589      * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
2590      *     make it consistent with current behaviour. It also allows ActivityManager to call
2591      *     unlockUser() with empty secret.
2592      * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
2593      *     whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
2594      *     lockscreen PIN, we still maintain the existing synthetic password in a password blob
2595      *     protected by a default PIN.
2596      * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
2597      *     clears/re-creates his lockscreen PIN.
2598      *
2599      *
2600      * Different cases of calling this method:
2601      * 1. credentialHash != null
2602      *     This implies credential != null, a new SP blob will be provisioned, and existing SID
2603      *     migrated to associate with the new SP.
2604      *     This happens during a normal migration case when the user currently has password.
2605      *
2606      * 2. credentialhash == null and credential == null
2607      *     A new SP blob and will be created, while the user has no credentials.
2608      *     This can happens when we are activating an escrow token on a unsecured device, during
2609      *     which we want to create the SP structure with an empty user credential.
2610      *     This could also happen during an untrusted reset to clear password.
2611      *
2612      * 3. credentialhash == null and credential != null
2613      *     The user sets a new lockscreen password FOR THE FIRST TIME on a SP-enabled device.
2614      *     New credential and new SID will be created
2615      */
2616     @GuardedBy("mSpManager")
2617     @VisibleForTesting
initializeSyntheticPasswordLocked(byte[] credentialHash, LockscreenCredential credential, int userId)2618     protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
2619             LockscreenCredential credential, int userId) {
2620         Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
2621         final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
2622                 getGateKeeperService(), credentialHash, credential, userId);
2623         onAuthTokenKnownForUser(userId, auth);
2624         if (auth == null) {
2625             Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
2626             return null;
2627         }
2628         long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
2629                 credential, auth, userId);
2630         if (!credential.isNone()) {
2631             if (credentialHash == null) {
2632                 // Since when initializing SP, we didn't provide an existing password handle
2633                 // for it to migrate SID, we need to create a new SID for the user.
2634                 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2635             }
2636             mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2637             setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2638             setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2639         } else {
2640             clearUserKeyProtection(userId, null);
2641             setKeystorePassword(null, userId);
2642             gateKeeperClearSecureUserId(userId);
2643         }
2644         fixateNewestUserKeyAuth(userId);
2645         setSyntheticPasswordHandleLocked(handle, userId);
2646         return auth;
2647     }
2648 
2649     @VisibleForTesting
getSyntheticPasswordHandleLocked(int userId)2650     long getSyntheticPasswordHandleLocked(int userId) {
2651         return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY,
2652                 SyntheticPasswordManager.DEFAULT_HANDLE, userId);
2653     }
2654 
setSyntheticPasswordHandleLocked(long handle, int userId)2655     private void setSyntheticPasswordHandleLocked(long handle, int userId) {
2656         final long oldHandle = getSyntheticPasswordHandleLocked(userId);
2657         setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
2658         setLong(PREV_SYNTHETIC_PASSWORD_HANDLE_KEY, oldHandle, userId);
2659         setLong(SYNTHETIC_PASSWORD_UPDATE_TIME_KEY, System.currentTimeMillis(), userId);
2660 
2661     }
2662 
2663     @VisibleForTesting
isSyntheticPasswordBasedCredential(int userId)2664     boolean isSyntheticPasswordBasedCredential(int userId) {
2665         synchronized (mSpManager) {
2666             return isSyntheticPasswordBasedCredentialLocked(userId);
2667         }
2668     }
2669 
isSyntheticPasswordBasedCredentialLocked(int userId)2670     private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
2671         if (userId == USER_FRP) {
2672             final int type = mStorage.readPersistentDataBlock().type;
2673             return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
2674         }
2675         long handle = getSyntheticPasswordHandleLocked(userId);
2676         return handle != SyntheticPasswordManager.DEFAULT_HANDLE;
2677     }
2678 
2679     @VisibleForTesting
shouldMigrateToSyntheticPasswordLocked(int userId)2680     protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
2681         return true;
2682     }
2683 
spBasedDoVerifyCredential(LockscreenCredential userCredential, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback, @Nullable ArrayList<PendingResetLockout> resetLockouts)2684     private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential,
2685             @ChallengeType int challengeType, long challenge,
2686             int userId, ICheckCredentialProgressCallback progressCallback,
2687             @Nullable ArrayList<PendingResetLockout> resetLockouts) {
2688 
2689         final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId);
2690 
2691         Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " challengeType=" + challengeType
2692                 + " hasEnrolledBiometrics=" + hasEnrolledBiometrics);
2693 
2694         final PackageManager pm = mContext.getPackageManager();
2695         // TODO: When lockout is handled under the HAL for all biometrics (fingerprint),
2696         // we need to generate challenge for each one, have it signed by GK and reset lockout
2697         // for each modality.
2698         if (challengeType == CHALLENGE_NONE && pm.hasSystemFeature(PackageManager.FEATURE_FACE)
2699                 && hasEnrolledBiometrics) {
2700             // If there are multiple profiles in the same account, ensure we only generate the
2701             // challenge once.
2702             challengeType = CHALLENGE_INTERNAL;
2703             challenge = mContext.getSystemService(FaceManager.class).generateChallenge();
2704         }
2705 
2706         final AuthenticationResult authResult;
2707         VerifyCredentialResponse response;
2708         synchronized (mSpManager) {
2709             if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
2710                 return null;
2711             }
2712             if (userId == USER_FRP) {
2713                 return mSpManager.verifyFrpCredential(getGateKeeperService(),
2714                         userCredential, progressCallback);
2715             }
2716 
2717             long handle = getSyntheticPasswordHandleLocked(userId);
2718             authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
2719                     getGateKeeperService(), handle, userCredential, userId, progressCallback);
2720 
2721             response = authResult.gkResponse;
2722             // credential has matched
2723             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2724                 // perform verifyChallenge with synthetic password which generates the real GK auth
2725                 // token and response for the current user
2726                 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
2727                         challenge, userId);
2728                 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2729                     // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
2730                     // match the recorded GK password handle.
2731                     Slog.wtf(TAG, "verifyChallenge with SP failed.");
2732                     return VerifyCredentialResponse.ERROR;
2733                 }
2734             }
2735         }
2736         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2737             // Do resetLockout / revokeChallenge when all profiles are unlocked
2738             if (hasEnrolledBiometrics) {
2739                 if (resetLockouts == null) {
2740                     resetLockouts = new ArrayList<>();
2741                 }
2742                 resetLockouts.add(new PendingResetLockout(userId, response.getPayload()));
2743             }
2744 
2745             onCredentialVerified(authResult.authToken, challengeType, challenge, resetLockouts,
2746                     PasswordMetrics.computeForCredential(userCredential), userId);
2747         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
2748             if (response.getTimeout() > 0) {
2749                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
2750             }
2751         }
2752 
2753         return response;
2754     }
2755 
onCredentialVerified(AuthenticationToken authToken, @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts, PasswordMetrics metrics, int userId)2756     private void onCredentialVerified(AuthenticationToken authToken,
2757             @ChallengeType int challengeType, long challenge,
2758             @Nullable ArrayList<PendingResetLockout> resetLockouts, PasswordMetrics metrics,
2759             int userId) {
2760 
2761         if (metrics != null) {
2762             synchronized (this) {
2763                 mUserPasswordMetrics.put(userId,  metrics);
2764             }
2765         } else {
2766             Slog.wtf(TAG, "Null metrics after credential verification");
2767         }
2768 
2769         unlockKeystore(authToken.deriveKeyStorePassword(), userId);
2770 
2771         {
2772             final byte[] secret = authToken.deriveDiskEncryptionKey();
2773             unlockUser(userId, null, secret, challengeType, challenge, resetLockouts);
2774             Arrays.fill(secret, (byte) 0);
2775         }
2776         activateEscrowTokens(authToken, userId);
2777 
2778         if (isManagedProfileWithSeparatedLock(userId)) {
2779             setDeviceUnlockedForUser(userId);
2780         }
2781         mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
2782 
2783         onAuthTokenKnownForUser(userId, authToken);
2784     }
2785 
setDeviceUnlockedForUser(int userId)2786     private void setDeviceUnlockedForUser(int userId) {
2787         final TrustManager trustManager = mContext.getSystemService(TrustManager.class);
2788         trustManager.setDeviceLockedForUser(userId, false);
2789     }
2790 
2791     /**
2792      * Change the user's lockscreen password by creating a new SP blob and update the handle, based
2793      * on an existing authentication token. Even though a new SP blob is created, the underlying
2794      * synthetic password is never changed.
2795      *
2796      * When clearing credential, we keep the SP unchanged, but clear its password handle so its
2797      * SID is gone. We also clear password from (software-based) keystore and vold, which will be
2798      * added back when new password is set in future.
2799      */
2800     @GuardedBy("mSpManager")
setLockCredentialWithAuthTokenLocked(LockscreenCredential credential, AuthenticationToken auth, int userId)2801     private long setLockCredentialWithAuthTokenLocked(LockscreenCredential credential,
2802             AuthenticationToken auth, int userId) {
2803         if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
2804         long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
2805                 credential, auth, userId);
2806         final Map<Integer, LockscreenCredential> profilePasswords;
2807         if (!credential.isNone()) {
2808             // not needed by synchronizeUnifiedWorkChallengeForProfiles()
2809             profilePasswords = null;
2810 
2811             if (mSpManager.hasSidForUser(userId)) {
2812                 // We are changing password of a secured device, nothing more needed as
2813                 // createPasswordBasedSyntheticPassword has already taken care of maintaining
2814                 // the password handle and SID unchanged.
2815 
2816                 //refresh auth token
2817                 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2818             } else {
2819                 // A new password is set on a previously-unsecured device, we need to generate
2820                 // a new SID, and re-add keys to vold and keystore.
2821                 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2822                 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2823                 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2824                 fixateNewestUserKeyAuth(userId);
2825                 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2826             }
2827         } else {
2828             // Cache all profile password if they use unified work challenge. This will later be
2829             // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
2830             profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
2831 
2832             // we are clearing password of a secured device, so need to nuke SID as well.
2833             mSpManager.clearSidForUser(userId);
2834             gateKeeperClearSecureUserId(userId);
2835             // Clear key from vold so ActivityManager can just unlock the user with empty secret
2836             // during boot. Vold storage needs to be unlocked before manipulation of the keys can
2837             // succeed.
2838             unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
2839             clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2840             fixateNewestUserKeyAuth(userId);
2841             unlockKeystore(auth.deriveKeyStorePassword(), userId);
2842             setKeystorePassword(null, userId);
2843             removeBiometricsForUser(userId);
2844         }
2845         setSyntheticPasswordHandleLocked(newHandle, userId);
2846         synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
2847 
2848         setUserPasswordMetrics(credential, userId);
2849         mManagedProfilePasswordCache.removePassword(userId);
2850 
2851         if (profilePasswords != null) {
2852             for (Map.Entry<Integer, LockscreenCredential> entry : profilePasswords.entrySet()) {
2853                 entry.getValue().zeroize();
2854             }
2855         }
2856 
2857         return newHandle;
2858     }
2859 
removeBiometricsForUser(int userId)2860     private void removeBiometricsForUser(int userId) {
2861         removeAllFingerprintForUser(userId);
2862         removeAllFaceForUser(userId);
2863     }
2864 
removeAllFingerprintForUser(final int userId)2865     private void removeAllFingerprintForUser(final int userId) {
2866         FingerprintManager mFingerprintManager = mInjector.getFingerprintManager();
2867         if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
2868             if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
2869                 mFingerprintManager.setActiveUser(userId);
2870                 CountDownLatch latch = new CountDownLatch(1);
2871                 // For the purposes of M and N, groupId is the same as userId.
2872                 Fingerprint finger = new Fingerprint(null, userId, 0, 0);
2873                 mFingerprintManager.remove(finger, userId,
2874                         fingerprintManagerRemovalCallback(latch));
2875                 try {
2876                     latch.await(10000, TimeUnit.MILLISECONDS);
2877                 } catch (InterruptedException e) {
2878                     Slog.e(TAG, "Latch interrupted when removing fingerprint", e);
2879                 }
2880             }
2881         }
2882     }
2883 
removeAllFaceForUser(final int userId)2884     private void removeAllFaceForUser(final int userId) {
2885         FaceManager mFaceManager = mInjector.getFaceManager();
2886         if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
2887             if (mFaceManager.hasEnrolledTemplates(userId)) {
2888                 mFaceManager.setActiveUser(userId);
2889                 CountDownLatch latch = new CountDownLatch(1);
2890                 Face face = new Face(null, 0, 0);
2891                 mFaceManager.remove(face, userId, faceManagerRemovalCallback(latch));
2892                 try {
2893                     latch.await(10000, TimeUnit.MILLISECONDS);
2894                 } catch (InterruptedException e) {
2895                     Slog.e(TAG, "Latch interrupted when removing face", e);
2896                 }
2897             }
2898         }
2899     }
2900 
fingerprintManagerRemovalCallback( CountDownLatch latch)2901     private FingerprintManager.RemovalCallback fingerprintManagerRemovalCallback(
2902             CountDownLatch latch) {
2903         return new FingerprintManager.RemovalCallback() {
2904             @Override
2905             public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence err) {
2906                 Slog.e(TAG, String.format(
2907                         "Can't remove fingerprint %d in group %d. Reason: %s",
2908                         fp.getBiometricId(), fp.getGroupId(), err));
2909                 latch.countDown();
2910             }
2911 
2912             @Override
2913             public void onRemovalSucceeded(Fingerprint fp, int remaining) {
2914                 if (remaining == 0) {
2915                     latch.countDown();
2916                 }
2917             }
2918         };
2919     }
2920 
2921     private FaceManager.RemovalCallback faceManagerRemovalCallback(CountDownLatch latch) {
2922         return new FaceManager.RemovalCallback() {
2923             @Override
2924             public void onRemovalError(Face face, int errMsgId, CharSequence err) {
2925                 Slog.e(TAG, String.format("Can't remove face %d. Reason: %s",
2926                         face.getBiometricId(), err));
2927                 latch.countDown();
2928             }
2929 
2930             @Override
2931             public void onRemovalSucceeded(Face face, int remaining) {
2932                 if (remaining == 0) {
2933                     latch.countDown();
2934                 }
2935             }
2936         };
2937     }
2938 
2939     /**
2940      * @param savedCredential if the user is a managed profile with unified challenge and
2941      *   savedCredential is empty, LSS will try to re-derive the profile password internally.
2942      *     TODO (b/80170828): Fix this so profile password is always passed in.
2943      */
2944     @GuardedBy("mSpManager")
2945     private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential,
2946             LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
2947         if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2948         if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
2949             // get credential from keystore when managed profile has unified lock
2950             try {
2951                 //TODO: remove as part of b/80170828
2952                 savedCredential = getDecryptedPasswordForTiedProfile(userId);
2953             } catch (FileNotFoundException e) {
2954                 Slog.i(TAG, "Child profile key not found");
2955             } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2956                     | NoSuchAlgorithmException | NoSuchPaddingException
2957                     | InvalidAlgorithmParameterException | IllegalBlockSizeException
2958                     | BadPaddingException | CertificateException | IOException e) {
2959                 Slog.e(TAG, "Failed to decrypt child profile key", e);
2960             }
2961         }
2962         long handle = getSyntheticPasswordHandleLocked(userId);
2963         AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
2964                 getGateKeeperService(), handle, savedCredential, userId, null);
2965         VerifyCredentialResponse response = authResult.gkResponse;
2966         AuthenticationToken auth = authResult.authToken;
2967 
2968         if (auth == null) {
2969             if (response == null
2970                     || response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
2971                 Slog.w(TAG, "Failed to enroll: incorrect credential.");
2972                 return false;
2973             }
2974             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
2975                 Slog.w(TAG, "Failed to enroll: rate limit exceeded.");
2976                 return false;
2977             }
2978             // Should not be reachable, but just in case.
2979             throw new IllegalStateException("password change failed");
2980         }
2981 
2982         onAuthTokenKnownForUser(userId, auth);
2983         setLockCredentialWithAuthTokenLocked(credential, auth, userId);
2984         mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2985         sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
2986         return true;
2987     }
2988 
2989     /**
2990      * Returns a fixed pseudorandom byte string derived from the user's synthetic password.
2991      * This is used to salt the password history hash to protect the hash against offline
2992      * bruteforcing, since rederiving this value requires a successful authentication.
2993      * If user is a managed profile with unified challenge, currentCredential is ignored.
2994      */
2995     @Override
2996     public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) {
2997         checkPasswordReadPermission(userId);
2998         try {
2999             if (isManagedProfileWithUnifiedLock(userId)) {
3000                 try {
3001                     currentCredential = getDecryptedPasswordForTiedProfile(userId);
3002                 } catch (Exception e) {
3003                     Slog.e(TAG, "Failed to get work profile credential", e);
3004                     return null;
3005                 }
3006             }
3007             synchronized (mSpManager) {
3008                 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
3009                     Slog.w(TAG, "Synthetic password not enabled");
3010                     return null;
3011                 }
3012                 long handle = getSyntheticPasswordHandleLocked(userId);
3013                 AuthenticationResult auth = mSpManager.unwrapPasswordBasedSyntheticPassword(
3014                         getGateKeeperService(), handle, currentCredential, userId, null);
3015                 if (auth.authToken == null) {
3016                     Slog.w(TAG, "Current credential is incorrect");
3017                     return null;
3018                 }
3019                 return auth.authToken.derivePasswordHashFactor();
3020             }
3021         } finally {
3022             scheduleGc();
3023         }
3024     }
3025 
3026     private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback) {
3027         if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
3028         synchronized (mSpManager) {
3029             // Migrate to synthetic password based credentials if the user has no password,
3030             // the token can then be activated immediately.
3031             AuthenticationToken auth = null;
3032             if (!isUserSecure(userId)) {
3033                 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
3034                     auth = initializeSyntheticPasswordLocked(
3035                             /* credentialHash */ null, LockscreenCredential.createNone(), userId);
3036                 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
3037                     long pwdHandle = getSyntheticPasswordHandleLocked(userId);
3038                     auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
3039                             pwdHandle, LockscreenCredential.createNone(), userId, null).authToken;
3040                 }
3041             }
3042             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
3043                 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
3044                 if (!mSpManager.hasEscrowData(userId)) {
3045                     throw new SecurityException("Escrow token is disabled on the current user");
3046                 }
3047             }
3048             long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId, callback);
3049             if (auth != null) {
3050                 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
3051             }
3052             return handle;
3053         }
3054     }
3055 
3056     private void activateEscrowTokens(AuthenticationToken auth, int userId) {
3057         if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
3058         synchronized (mSpManager) {
3059             disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
3060             for (long handle : mSpManager.getPendingTokensForUser(userId)) {
3061                 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
3062                 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
3063             }
3064         }
3065     }
3066 
3067     private boolean isEscrowTokenActive(long handle, int userId) {
3068         synchronized (mSpManager) {
3069             return mSpManager.existsHandle(handle, userId);
3070         }
3071     }
3072 
3073     @Override
3074     public boolean hasPendingEscrowToken(int userId) {
3075         checkPasswordReadPermission(userId);
3076         synchronized (mSpManager) {
3077             return !mSpManager.getPendingTokensForUser(userId).isEmpty();
3078         }
3079     }
3080 
3081     private boolean removeEscrowToken(long handle, int userId) {
3082         synchronized (mSpManager) {
3083             if (handle == getSyntheticPasswordHandleLocked(userId)) {
3084                 Slog.w(TAG, "Cannot remove password handle");
3085                 return false;
3086             }
3087             if (mSpManager.removePendingToken(handle, userId)) {
3088                 return true;
3089             }
3090             if (mSpManager.existsHandle(handle, userId)) {
3091                 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
3092                 return true;
3093             } else {
3094                 return false;
3095             }
3096         }
3097     }
3098 
3099     private boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
3100             byte[] token, int userId) {
3101         boolean result;
3102         synchronized (mSpManager) {
3103             if (!mSpManager.hasEscrowData(userId)) {
3104                 throw new SecurityException("Escrow token is disabled on the current user");
3105             }
3106             result = setLockCredentialWithTokenInternalLocked(
3107                     credential, tokenHandle, token, userId);
3108         }
3109         if (result) {
3110             synchronized (mSeparateChallengeLock) {
3111                 setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
3112             }
3113             if (credential.isNone()) {
3114                 // If clearing credential, unlock the user manually in order to progress user start
3115                 // Call unlockUser() on a handler thread so no lock is held (either by LSS or by
3116                 // the caller like DPMS), otherwise it can lead to deadlock.
3117                 mHandler.post(() -> unlockUser(userId, null, null));
3118             }
3119             notifyPasswordChanged(userId);
3120             notifySeparateProfileChallengeChanged(userId);
3121         }
3122         return result;
3123     }
3124 
3125     @GuardedBy("mSpManager")
3126     private boolean setLockCredentialWithTokenInternalLocked(LockscreenCredential credential,
3127             long tokenHandle, byte[] token, int userId) {
3128         final AuthenticationResult result;
3129         result = mSpManager.unwrapTokenBasedSyntheticPassword(
3130                 getGateKeeperService(), tokenHandle, token, userId);
3131         if (result.authToken == null) {
3132             Slog.w(TAG, "Invalid escrow token supplied");
3133             return false;
3134         }
3135         if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
3136             // Most likely, an untrusted credential reset happened in the past which
3137             // changed the synthetic password
3138             Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
3139                     + "verification.");
3140             return false;
3141         }
3142         onAuthTokenKnownForUser(userId, result.authToken);
3143         long oldHandle = getSyntheticPasswordHandleLocked(userId);
3144         setLockCredentialWithAuthTokenLocked(credential, result.authToken, userId);
3145         mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
3146         return true;
3147     }
3148 
3149     private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
3150         AuthenticationResult authResult;
3151         synchronized (mSpManager) {
3152             if (!mSpManager.hasEscrowData(userId)) {
3153                 throw new SecurityException("Escrow token is disabled on the current user");
3154             }
3155             authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
3156                     tokenHandle, token, userId);
3157             if (authResult.authToken == null) {
3158                 Slog.w(TAG, "Invalid escrow token supplied");
3159                 return false;
3160             }
3161         }
3162         // TODO: Reset biometrics lockout here. Ideally that should be self-contained inside
3163         // onCredentialVerified(), which will require some refactoring on the current lockout
3164         // reset logic.
3165 
3166         onCredentialVerified(authResult.authToken, CHALLENGE_NONE, 0, null,
3167                 loadPasswordMetrics(authResult.authToken, userId), userId);
3168         return true;
3169     }
3170 
3171     @Override
3172     public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
3173         try (LockscreenCredential cred = mManagedProfilePasswordCache.retrievePassword(userId)) {
3174             if (cred == null) {
3175                 return false;
3176             }
3177             return doVerifyCredential(cred, CHALLENGE_NONE, 0, userId, null /* progressCallback */)
3178                     .getResponseCode() == VerifyCredentialResponse.RESPONSE_OK;
3179         }
3180     }
3181 
3182     @Override
3183     public void removeCachedUnifiedChallenge(int userId) {
3184         mManagedProfilePasswordCache.removePassword(userId);
3185     }
3186 
3187     static String timestampToString(long timestamp) {
3188         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
3189     }
3190 
3191     private static String credentialTypeToString(int credentialType) {
3192         switch (credentialType) {
3193             case CREDENTIAL_TYPE_NONE:
3194                 return "None";
3195             case CREDENTIAL_TYPE_PATTERN:
3196                 return "Pattern";
3197             case CREDENTIAL_TYPE_PIN:
3198                 return "Pin";
3199             case CREDENTIAL_TYPE_PASSWORD:
3200                 return "Password";
3201             default:
3202                 return "Unknown " + credentialType;
3203         }
3204     }
3205 
3206     @Override
3207     protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
3208         if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return;
3209         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
3210 
3211         pw.println("Current lock settings service state:");
3212         pw.println();
3213 
3214         pw.println("User State:");
3215         pw.increaseIndent();
3216         List<UserInfo> users = mUserManager.getUsers();
3217         for (int user = 0; user < users.size(); user++) {
3218             final int userId = users.get(user).id;
3219             pw.println("User " + userId);
3220             pw.increaseIndent();
3221             synchronized (mSpManager) {
3222                 pw.println(String.format("SP Handle: %x",
3223                         getSyntheticPasswordHandleLocked(userId)));
3224                 pw.println(String.format("Last changed: %s (%x)",
3225                         timestampToString(getLong(SYNTHETIC_PASSWORD_UPDATE_TIME_KEY, 0, userId)),
3226                         getLong(PREV_SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId)));
3227             }
3228             try {
3229                 pw.println(String.format("SID: %x",
3230                         getGateKeeperService().getSecureUserId(userId)));
3231             } catch (RemoteException e) {
3232                 // ignore.
3233             }
3234             // It's OK to dump the password type since anyone with physical access can just
3235             // observe it from the keyguard directly.
3236             pw.println("Quality: " + getKeyguardStoredQuality(userId));
3237             pw.println("CredentialType: " + credentialTypeToString(
3238                     getCredentialTypeInternal(userId)));
3239             pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabledInternal(userId));
3240             pw.println(String.format("Metrics: %s",
3241                     getUserPasswordMetrics(userId) != null ? "known" : "unknown"));
3242             pw.decreaseIndent();
3243         }
3244         pw.println();
3245         pw.decreaseIndent();
3246 
3247         pw.println("Storage:");
3248         pw.increaseIndent();
3249         mStorage.dump(pw);
3250         pw.println();
3251         pw.decreaseIndent();
3252 
3253         pw.println("StrongAuth:");
3254         pw.increaseIndent();
3255         mStrongAuth.dump(pw);
3256         pw.println();
3257         pw.decreaseIndent();
3258 
3259         pw.println("RebootEscrow:");
3260         pw.increaseIndent();
3261         mRebootEscrowManager.dump(pw);
3262         pw.println();
3263         pw.decreaseIndent();
3264     }
3265 
3266     /**
3267      * Cryptographically disable escrow token support for the current user, if the user is not
3268      * managed (either user has a profile owner, or if device is managed). Do not disable
3269      * if we are running an automotive build.
3270      */
3271     private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
3272         final UserManagerInternal userManagerInternal = mInjector.getUserManagerInternal();
3273 
3274         // Managed profile should have escrow enabled
3275         if (userManagerInternal.isUserManaged(userId)) {
3276             Slog.i(TAG, "Managed profile can have escrow token");
3277             return;
3278         }
3279 
3280         // Devices with Device Owner should have escrow enabled on all users.
3281         if (userManagerInternal.isDeviceManaged()) {
3282             Slog.i(TAG, "Corp-owned device can have escrow token");
3283             return;
3284         }
3285 
3286         // If the device is yet to be provisioned (still in SUW), there is still
3287         // a chance that Device Owner will be set on the device later, so postpone
3288         // disabling escrow token for now.
3289         if (!mInjector.getDeviceStateCache().isDeviceProvisioned()) {
3290             Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
3291             return;
3292         }
3293 
3294         // Escrow tokens are enabled on automotive builds.
3295         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
3296             return;
3297         }
3298 
3299         // Disable escrow token permanently on all other device/user types.
3300         Slog.i(TAG, "Disabling escrow token on user " + userId);
3301         if (isSyntheticPasswordBasedCredentialLocked(userId)) {
3302             mSpManager.destroyEscrowData(userId);
3303         }
3304     }
3305 
3306     /**
3307      * Schedules garbage collection to sanitize lockscreen credential remnants in memory.
3308      *
3309      * One source of leftover lockscreen credentials is the unmarshalled binder method arguments.
3310      * Since this method will be called within the binder implementation method, a small delay is
3311      * added before the GC operation to allow the enclosing binder proxy code to complete and
3312      * release references to the argument.
3313      */
3314     private void scheduleGc() {
3315         mHandler.postDelayed(() -> {
3316             System.gc();
3317             System.runFinalization();
3318             System.gc();
3319         }, 2000);
3320     }
3321 
3322     private class DeviceProvisionedObserver extends ContentObserver {
3323         private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
3324                 Settings.Global.DEVICE_PROVISIONED);
3325 
3326         private boolean mRegistered;
3327 
3328         public DeviceProvisionedObserver() {
3329             super(null);
3330         }
3331 
3332         @Override
3333         public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
3334             if (mDeviceProvisionedUri.equals(uri)) {
3335                 updateRegistration();
3336 
3337                 if (isProvisioned()) {
3338                     Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
3339                     reportDeviceSetupComplete();
3340                     clearFrpCredentialIfOwnerNotSecure();
3341                 }
3342             }
3343         }
3344 
3345         public void onSystemReady() {
3346             if (frpCredentialEnabled(mContext)) {
3347                 updateRegistration();
3348             } else {
3349                 // If we don't intend to use frpCredentials and we're not provisioned yet, send
3350                 // deviceSetupComplete immediately, so gatekeeper can discard any lingering
3351                 // credentials immediately.
3352                 if (!isProvisioned()) {
3353                     Slog.i(TAG, "FRP credential disabled, reporting device setup complete "
3354                             + "to Gatekeeper immediately");
3355                     reportDeviceSetupComplete();
3356                 }
3357             }
3358         }
3359 
3360         private void reportDeviceSetupComplete() {
3361             try {
3362                 getGateKeeperService().reportDeviceSetupComplete();
3363             } catch (RemoteException e) {
3364                 Slog.e(TAG, "Failure reporting to IGateKeeperService", e);
3365             }
3366         }
3367 
3368         /**
3369          * Clears the FRP credential if the user that controls it does not have a secure
3370          * lockscreen.
3371          */
3372         private void clearFrpCredentialIfOwnerNotSecure() {
3373             List<UserInfo> users = mUserManager.getUsers();
3374             for (UserInfo user : users) {
3375                 if (userOwnsFrpCredential(mContext, user)) {
3376                     if (!isUserSecure(user.id)) {
3377                         mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
3378                                 0, null);
3379                     }
3380                     return;
3381                 }
3382             }
3383         }
3384 
3385         private void updateRegistration() {
3386             boolean register = !isProvisioned();
3387             if (register == mRegistered) {
3388                 return;
3389             }
3390             if (register) {
3391                 mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri,
3392                         false, this);
3393             } else {
3394                 mContext.getContentResolver().unregisterContentObserver(this);
3395             }
3396             mRegistered = register;
3397         }
3398 
3399         private boolean isProvisioned() {
3400             return Settings.Global.getInt(mContext.getContentResolver(),
3401                     Settings.Global.DEVICE_PROVISIONED, 0) != 0;
3402         }
3403     }
3404 
3405     private final class LocalService extends LockSettingsInternal {
3406 
3407         @Override
3408         public long addEscrowToken(byte[] token, int userId,
3409                 EscrowTokenStateChangeCallback callback) {
3410             return LockSettingsService.this.addEscrowToken(token, userId, callback);
3411         }
3412 
3413         @Override
3414         public boolean removeEscrowToken(long handle, int userId) {
3415             return LockSettingsService.this.removeEscrowToken(handle, userId);
3416         }
3417 
3418         @Override
3419         public boolean isEscrowTokenActive(long handle, int userId) {
3420             return LockSettingsService.this.isEscrowTokenActive(handle, userId);
3421         }
3422 
3423         @Override
3424         public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
3425                 byte[] token, int userId) {
3426             if (!mHasSecureLockScreen) {
3427                 throw new UnsupportedOperationException(
3428                         "This operation requires secure lock screen feature.");
3429             }
3430             return LockSettingsService.this.setLockCredentialWithToken(
3431                     credential, tokenHandle, token, userId);
3432         }
3433 
3434         @Override
3435         public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
3436             return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
3437         }
3438 
3439         @Override
3440         public PasswordMetrics getUserPasswordMetrics(int userHandle) {
3441             long identity = Binder.clearCallingIdentity();
3442             try {
3443                 if (isManagedProfileWithUnifiedLock(userHandle)) {
3444                     // A managed profile with unified challenge is supposed to be protected by the
3445                     // parent lockscreen, so asking for its password metrics is not really useful,
3446                     // as this method would just return the metrics of the random profile password
3447                     Slog.w(TAG, "Querying password metrics for unified challenge profile: "
3448                             + userHandle);
3449                 }
3450             } finally {
3451                 Binder.restoreCallingIdentity(identity);
3452             }
3453             return LockSettingsService.this.getUserPasswordMetrics(userHandle);
3454         }
3455 
3456         @Override
3457         public void prepareRebootEscrow() {
3458             if (!mRebootEscrowManager.prepareRebootEscrow()) {
3459                 return;
3460             }
3461             mStrongAuth.requireStrongAuth(STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE, USER_ALL);
3462         }
3463 
3464         @Override
3465         public void setRebootEscrowListener(RebootEscrowListener listener) {
3466             mRebootEscrowManager.setRebootEscrowListener(listener);
3467         }
3468 
3469         @Override
3470         public void clearRebootEscrow() {
3471             if (!mRebootEscrowManager.clearRebootEscrow()) {
3472                 return;
3473             }
3474             mStrongAuth.noLongerRequireStrongAuth(STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE,
3475                     USER_ALL);
3476         }
3477 
3478         @Override
3479         public boolean armRebootEscrow() {
3480             return mRebootEscrowManager.armRebootEscrowIfNeeded();
3481         }
3482 
3483         @Override
3484         public void refreshStrongAuthTimeout(int userId) {
3485             mStrongAuth.refreshStrongAuthTimeout(userId);
3486         }
3487     }
3488 
3489     private class RebootEscrowCallbacks implements RebootEscrowManager.Callbacks {
3490         @Override
3491         public boolean isUserSecure(int userId) {
3492             return LockSettingsService.this.isUserSecure(userId);
3493         }
3494 
3495         @Override
3496         public void onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId) {
3497             SyntheticPasswordManager.AuthenticationToken
3498                     authToken = new SyntheticPasswordManager.AuthenticationToken(spVersion);
3499             authToken.recreateDirectly(syntheticPassword);
3500             onCredentialVerified(authToken, CHALLENGE_NONE, 0, null,
3501                     loadPasswordMetrics(authToken, userId), userId);
3502         }
3503     }
3504 }
3505