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