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