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