2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server;
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 com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
23 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
24 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
26 import android.annotation.UserIdInt;
27 import android.app.ActivityManager;
28 import android.app.IActivityManager;
29 import android.app.KeyguardManager;
30 import android.app.Notification;
31 import android.app.NotificationManager;
32 import android.app.PendingIntent;
33 import android.app.admin.DevicePolicyManager;
34 import android.app.admin.PasswordMetrics;
35 import android.app.backup.BackupManager;
36 import android.app.trust.IStrongAuthTracker;
37 import android.app.trust.TrustManager;
38 import android.content.BroadcastReceiver;
39 import android.content.ContentResolver;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.content.pm.PackageManager;
44 import android.content.pm.UserInfo;
45 import android.content.res.Resources;
46 import android.database.sqlite.SQLiteDatabase;
47 import android.os.Binder;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.IBinder;
51 import android.os.IProgressListener;
52 import android.os.Process;
53 import android.os.RemoteException;
54 import android.os.ResultReceiver;
55 import android.os.ServiceManager;
56 import android.os.ShellCallback;
57 import android.os.StrictMode;
58 import android.os.SystemProperties;
59 import android.os.UserHandle;
60 import android.os.UserManager;
61 import android.os.storage.IStorageManager;
62 import android.os.storage.StorageManager;
63 import android.provider.Settings;
64 import android.provider.Settings.Secure;
65 import android.provider.Settings.SettingNotFoundException;
66 import android.security.GateKeeper;
67 import android.security.KeyStore;
68 import android.security.keystore.AndroidKeyStoreProvider;
69 import android.security.keystore.KeyProperties;
70 import android.security.keystore.KeyProtection;
71 import android.service.gatekeeper.GateKeeperResponse;
72 import android.service.gatekeeper.IGateKeeperService;
73 import android.text.TextUtils;
74 import android.util.ArrayMap;
75 import android.util.Log;
76 import android.util.Slog;
78 import com.android.internal.annotations.VisibleForTesting;
79 import com.android.internal.notification.SystemNotificationChannels;
80 import com.android.internal.util.ArrayUtils;
81 import com.android.internal.widget.ICheckCredentialProgressCallback;
82 import com.android.internal.widget.ILockSettings;
83 import com.android.internal.widget.LockPatternUtils;
84 import com.android.internal.widget.VerifyCredentialResponse;
85 import com.android.server.LockSettingsStorage.CredentialHash;
86 import com.android.server.SyntheticPasswordManager.AuthenticationResult;
87 import com.android.server.SyntheticPasswordManager.AuthenticationToken;
89 import libcore.util.HexEncoding;
91 import java.io.ByteArrayOutputStream;
92 import java.io.FileDescriptor;
93 import java.io.FileNotFoundException;
94 import java.io.IOException;
95 import java.io.PrintWriter;
96 import java.nio.charset.StandardCharsets;
97 import java.security.InvalidAlgorithmParameterException;
98 import java.security.InvalidKeyException;
99 import java.security.KeyStoreException;
100 import java.security.MessageDigest;
101 import java.security.NoSuchAlgorithmException;
102 import java.security.SecureRandom;
103 import java.security.UnrecoverableKeyException;
104 import java.security.cert.CertificateException;
105 import java.util.ArrayList;
106 import java.util.Arrays;
107 import java.util.List;
108 import java.util.Map;
109 import java.util.concurrent.CountDownLatch;
110 import java.util.concurrent.TimeUnit;
112 import javax.crypto.BadPaddingException;
113 import javax.crypto.Cipher;
114 import javax.crypto.IllegalBlockSizeException;
115 import javax.crypto.KeyGenerator;
116 import javax.crypto.NoSuchPaddingException;
117 import javax.crypto.SecretKey;
118 import javax.crypto.spec.GCMParameterSpec;
121 * Keeps the lock pattern/password data and related settings for each user. Used by
122 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
123 * lockscreen information for secondary users.
127 public class LockSettingsService extends ILockSettings.Stub {
128 private static final String TAG = "LockSettingsService";
129 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
130 private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
131 private static final boolean DEBUG = false;
133 private static final int PROFILE_KEY_IV_SIZE = 12;
134 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
136 private final Object mSeparateChallengeLock = new Object();
138 private final Injector mInjector;
139 private final Context mContext;
140 private final Handler mHandler;
142 protected final LockSettingsStorage mStorage;
143 private final LockSettingsStrongAuth mStrongAuth;
144 private final SynchronizedStrongAuthTracker mStrongAuthTracker;
146 private final LockPatternUtils mLockPatternUtils;
147 private final NotificationManager mNotificationManager;
148 private final UserManager mUserManager;
149 private final DevicePolicyManager mDevicePolicyManager;
150 private final IActivityManager mActivityManager;
152 private final KeyStore mKeyStore;
154 private boolean mFirstCallToVold;
155 protected IGateKeeperService mGateKeeperService;
156 private SyntheticPasswordManager mSpManager;
159 * The UIDs that are used for system credential storage in keystore.
161 private static final int[] SYSTEM_CREDENTIAL_UIDS = {
162 Process.WIFI_UID, Process.VPN_UID,
165 // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
166 // devices. The most basic of these is to show/hide notifications about missing features until
167 // the user unlocks the account and credential-encrypted storage is available.
168 public static final class Lifecycle extends SystemService {
169 private LockSettingsService mLockSettingsService;
171 public Lifecycle(Context context) {
176 public void onStart() {
177 AndroidKeyStoreProvider.install();
178 mLockSettingsService = new LockSettingsService(getContext());
179 publishBinderService("lock_settings", mLockSettingsService);
183 public void onStartUser(int userHandle) {
184 mLockSettingsService.onStartUser(userHandle);
188 public void onUnlockUser(int userHandle) {
189 mLockSettingsService.onUnlockUser(userHandle);
193 public void onCleanupUser(int userHandle) {
194 mLockSettingsService.onCleanupUser(userHandle);
199 protected static class SynchronizedStrongAuthTracker
200 extends LockPatternUtils.StrongAuthTracker {
201 public SynchronizedStrongAuthTracker(Context context) {
206 protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
207 synchronized (this) {
208 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
213 public int getStrongAuthForUser(int userId) {
214 synchronized (this) {
215 return super.getStrongAuthForUser(userId);
219 void register(LockSettingsStrongAuth strongAuth) {
220 strongAuth.registerStrongAuthTracker(this.mStub);
225 * Tie managed profile to primary profile if it is in unified mode and not tied before.
227 * @param managedUserId Managed profile user Id
228 * @param managedUserPassword Managed profile original password (when it has separated lock).
229 * NULL when it does not have a separated lock before.
231 public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
232 if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
233 // Only for managed profile
234 if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
237 // Do not tie managed profile when work challenge is enabled
238 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
241 // Do not tie managed profile to parent when it's done already
242 if (mStorage.hasChildProfileLock(managedUserId)) {
245 // Do not tie it to parent when parent does not have a screen lock
246 final int parentId = mUserManager.getProfileParent(managedUserId).id;
247 if (!isUserSecure(parentId)) {
248 if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
251 // Do not tie when the parent has no SID (but does have a screen lock).
252 // This can only happen during an upgrade path where SID is yet to be
253 // generated when the user unlocks for the first time.
255 if (getGateKeeperService().getSecureUserId(parentId) == 0) {
258 } catch (RemoteException e) {
259 Slog.e(TAG, "Failed to talk to GateKeeper service", e);
262 if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
263 byte[] randomLockSeed = new byte[] {};
265 randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
266 String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
267 setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
268 managedUserPassword, managedUserId);
269 // We store a private credential for the managed user that's unlocked by the primary
270 // account holder's credential. As such, the user will never be prompted to enter this
271 // password directly, so we always store a password.
272 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
273 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId);
274 tieProfileLockToParent(managedUserId, newPassword);
275 } catch (NoSuchAlgorithmException | RemoteException e) {
276 Slog.e(TAG, "Fail to tie managed profile", e);
277 // Nothing client can do to fix this issue, so we do not throw exception out
281 static class Injector {
283 protected Context mContext;
285 public Injector(Context context) {
289 public Context getContext() {
293 public Handler getHandler() {
294 return new Handler();
297 public LockSettingsStorage getStorage() {
298 final LockSettingsStorage storage = new LockSettingsStorage(mContext);
299 storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
301 public void initialize(SQLiteDatabase db) {
302 // Get the lockscreen default from a system property, if available
303 boolean lockScreenDisable = SystemProperties.getBoolean(
304 "ro.lockscreen.disable.default", false);
305 if (lockScreenDisable) {
306 storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
313 public LockSettingsStrongAuth getStrongAuth() {
314 return new LockSettingsStrongAuth(mContext);
317 public SynchronizedStrongAuthTracker getStrongAuthTracker() {
318 return new SynchronizedStrongAuthTracker(mContext);
321 public IActivityManager getActivityManager() {
322 return ActivityManager.getService();
325 public LockPatternUtils getLockPatternUtils() {
326 return new LockPatternUtils(mContext);
329 public NotificationManager getNotificationManager() {
330 return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
333 public UserManager getUserManager() {
334 return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
337 public DevicePolicyManager getDevicePolicyManager() {
338 return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
341 public KeyStore getKeyStore() {
342 return KeyStore.getInstance();
345 public IStorageManager getStorageManager() {
346 final IBinder service = ServiceManager.getService("mount");
347 if (service != null) {
348 return IStorageManager.Stub.asInterface(service);
353 public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
354 return new SyntheticPasswordManager(storage);
357 public int binderGetCallingUid() {
358 return Binder.getCallingUid();
362 public LockSettingsService(Context context) {
363 this(new Injector(context));
367 protected LockSettingsService(Injector injector) {
368 mInjector = injector;
369 mContext = injector.getContext();
370 mKeyStore = injector.getKeyStore();
371 mHandler = injector.getHandler();
372 mStrongAuth = injector.getStrongAuth();
373 mActivityManager = injector.getActivityManager();
375 mLockPatternUtils = injector.getLockPatternUtils();
376 mFirstCallToVold = true;
378 IntentFilter filter = new IntentFilter();
379 filter.addAction(Intent.ACTION_USER_ADDED);
380 filter.addAction(Intent.ACTION_USER_STARTING);
381 filter.addAction(Intent.ACTION_USER_REMOVED);
382 injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
385 mStorage = injector.getStorage();
386 mNotificationManager = injector.getNotificationManager();
387 mUserManager = injector.getUserManager();
388 mDevicePolicyManager = injector.getDevicePolicyManager();
389 mStrongAuthTracker = injector.getStrongAuthTracker();
390 mStrongAuthTracker.register(mStrongAuth);
392 mSpManager = injector.getSyntheticPasswordManager(mStorage);
396 * If the account is credential-encrypted, show notification requesting the user to unlock the
399 private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
400 final UserInfo user = mUserManager.getUserInfo(userId);
401 if (!user.isManagedProfile()) {
402 // When the user is locked, we communicate it loud-and-clear
403 // on the lockscreen; we only show a notification below for
404 // locked managed profiles.
408 final UserHandle userHandle = user.getUserHandle();
409 final boolean isSecure = isUserSecure(userId);
410 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
411 UserInfo parent = mUserManager.getProfileParent(userId);
412 if (parent != null &&
413 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
414 !mUserManager.isQuietModeEnabled(userHandle)) {
415 // Only show notifications for managed profiles once their parent
417 showEncryptionNotificationForProfile(userHandle);
422 private void showEncryptionNotificationForProfile(UserHandle user) {
423 Resources r = mContext.getResources();
424 CharSequence title = r.getText(
425 com.android.internal.R.string.user_encrypted_title);
426 CharSequence message = r.getText(
427 com.android.internal.R.string.profile_encrypted_message);
428 CharSequence detail = r.getText(
429 com.android.internal.R.string.profile_encrypted_detail);
431 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
432 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
433 user.getIdentifier());
434 if (unlockIntent == null) {
437 unlockIntent.setFlags(
438 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
439 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
440 PendingIntent.FLAG_UPDATE_CURRENT);
442 showEncryptionNotification(user, title, message, detail, intent);
445 private void showEncryptionNotification(UserHandle user, CharSequence title,
446 CharSequence message, CharSequence detail, PendingIntent intent) {
447 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
449 // Suppress all notifications on non-FBE devices for now
450 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
452 Notification notification =
453 new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
454 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
458 .setColor(mContext.getColor(
459 com.android.internal.R.color.system_notification_accent_color))
460 .setContentTitle(title)
461 .setContentText(message)
463 .setVisibility(Notification.VISIBILITY_PUBLIC)
464 .setContentIntent(intent)
466 mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
469 private void hideEncryptionNotification(UserHandle userHandle) {
470 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
471 mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
474 public void onCleanupUser(int userId) {
475 hideEncryptionNotification(new UserHandle(userId));
478 public void onStartUser(final int userId) {
479 maybeShowEncryptionNotificationForUser(userId);
482 public void onUnlockUser(final int userId) {
483 // Perform tasks which require locks in LSS on a handler, as we are callbacks from
484 // ActivityManager.unlockUser()
485 mHandler.post(new Runnable() {
488 // Hide notification first, as tie managed profile lock takes time
489 hideEncryptionNotification(new UserHandle(userId));
491 // Now we have unlocked the parent user we should show notifications
492 // about any profiles that exist.
493 List<UserInfo> profiles = mUserManager.getProfiles(userId);
494 for (int i = 0; i < profiles.size(); i++) {
495 UserInfo profile = profiles.get(i);
496 final boolean isSecure = isUserSecure(profile.id);
497 if (isSecure && profile.isManagedProfile()) {
498 UserHandle userHandle = profile.getUserHandle();
499 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
500 !mUserManager.isQuietModeEnabled(userHandle)) {
501 showEncryptionNotificationForProfile(userHandle);
506 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
507 tieManagedProfileLockIfNecessary(userId, null);
513 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
515 public void onReceive(Context context, Intent intent) {
516 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
517 // Notify keystore that a new user was added.
518 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
519 if (userHandle > UserHandle.USER_SYSTEM) {
520 removeUser(userHandle, /* unknownUser= */ true);
522 final KeyStore ks = KeyStore.getInstance();
523 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
524 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
525 ks.onUserAdded(userHandle, parentHandle);
526 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
527 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
528 mStorage.prefetchUser(userHandle);
529 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
530 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
531 if (userHandle > 0) {
532 removeUser(userHandle, /* unknownUser= */ false);
538 @Override // binder interface
539 public void systemReady() {
542 getGateKeeperService();
543 } catch (RemoteException e) {
544 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
546 // TODO: maybe skip this for split system user mode.
547 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
550 private void migrateOldData() {
552 // These Settings moved before multi-user was enabled, so we only have to do it for the
554 if (getString("migrated", null, 0) == null) {
555 final ContentResolver cr = mContext.getContentResolver();
556 for (String validSetting : VALID_SETTINGS) {
557 String value = Settings.Secure.getString(cr, validSetting);
559 setString(validSetting, value, 0);
562 // No need to move the password / pattern files. They're already in the right place.
563 setString("migrated", "true", 0);
564 Slog.i(TAG, "Migrated lock settings to new location");
567 // These Settings changed after multi-user was enabled, hence need to be moved per user.
568 if (getString("migrated_user_specific", null, 0) == null) {
569 final ContentResolver cr = mContext.getContentResolver();
570 List<UserInfo> users = mUserManager.getUsers();
571 for (int user = 0; user < users.size(); user++) {
572 // Migrate owner info
573 final int userId = users.get(user).id;
574 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
575 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
576 if (!TextUtils.isEmpty(ownerInfo)) {
577 setString(OWNER_INFO, ownerInfo, userId);
578 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
581 // Migrate owner info enabled. Note there was a bug where older platforms only
582 // stored this value if the checkbox was toggled at least once. The code detects
583 // this case by handling the exception.
584 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
587 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
588 enabled = ivalue != 0;
589 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
590 } catch (SettingNotFoundException e) {
591 // Setting was never stored. Store it if the string is not empty.
592 if (!TextUtils.isEmpty(ownerInfo)) {
593 setLong(OWNER_INFO_ENABLED, 1, userId);
596 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
598 // No need to move the password / pattern files. They're already in the right place.
599 setString("migrated_user_specific", "true", 0);
600 Slog.i(TAG, "Migrated per-user lock settings to new location");
603 // Migrates biometric weak such that the fallback mechanism becomes the primary.
604 if (getString("migrated_biometric_weak", null, 0) == null) {
605 List<UserInfo> users = mUserManager.getUsers();
606 for (int i = 0; i < users.size(); i++) {
607 int userId = users.get(i).id;
608 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
609 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
611 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
612 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
614 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
615 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
619 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
620 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
623 setString("migrated_biometric_weak", "true", 0);
624 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
627 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
628 // user was present on the system, so if we're upgrading to M and there is more than one
629 // user we disable the flag to remain consistent.
630 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
631 final List<UserInfo> users = mUserManager.getUsers();
632 final int userCount = users.size();
633 int switchableUsers = 0;
634 for (int i = 0; i < userCount; i++) {
635 if (users.get(i).supportsSwitchTo()) {
640 if (switchableUsers > 1) {
641 for (int i = 0; i < userCount; i++) {
642 int id = users.get(i).id;
644 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
645 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
650 setString("migrated_lockscreen_disabled", "true", 0);
651 Slog.i(TAG, "Migrated lockscreen disabled flag");
654 final List<UserInfo> users = mUserManager.getUsers();
655 for (int i = 0; i < users.size(); i++) {
656 final UserInfo userInfo = users.get(i);
657 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
658 // When managed profile has a unified lock, the password quality stored has 2
659 // possibilities only.
660 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
661 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
662 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
664 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
665 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
666 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
667 // Only possible when it's upgraded from nyc dp3
668 Slog.i(TAG, "Migrated tied profile lock type");
669 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
670 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
671 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
672 // It should not happen
673 Slog.e(TAG, "Invalid tied profile lock type: " + quality);
677 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
678 java.security.KeyStore keyStore =
679 java.security.KeyStore.getInstance("AndroidKeyStore");
681 if (keyStore.containsAlias(alias)) {
682 keyStore.deleteEntry(alias);
684 } catch (KeyStoreException | NoSuchAlgorithmException |
685 CertificateException | IOException e) {
686 Slog.e(TAG, "Unable to remove tied profile key", e);
690 boolean isWatch = mContext.getPackageManager().hasSystemFeature(
691 PackageManager.FEATURE_WATCH);
692 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
693 // and device management the lockscreen must be re-enabled now for users that upgrade.
694 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
695 final int userCount = users.size();
696 for (int i = 0; i < userCount; i++) {
697 int id = users.get(i).id;
698 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
700 setString("migrated_wear_lockscreen_disabled", "true", 0);
701 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
703 } catch (RemoteException re) {
704 Slog.e(TAG, "Unable to migrate old data", re);
708 private final void checkWritePermission(int userId) {
709 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
712 private final void checkPasswordReadPermission(int userId) {
713 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
716 private final void checkReadPermission(String requestedKey, int userId) {
717 final int callingUid = Binder.getCallingUid();
719 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
720 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
721 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
722 != PackageManager.PERMISSION_GRANTED) {
723 throw new SecurityException("uid=" + callingUid
724 + " needs permission " + READ_CONTACTS + " to read "
725 + requestedKey + " for user " + userId);
729 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
730 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
731 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
732 != PackageManager.PERMISSION_GRANTED) {
733 throw new SecurityException("uid=" + callingUid
734 + " needs permission " + PERMISSION + " to read "
735 + requestedKey + " for user " + userId);
741 public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
742 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
743 synchronized (mSeparateChallengeLock) {
744 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
749 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
750 String managedUserPassword) throws RemoteException {
751 checkWritePermission(userId);
752 synchronized (mSeparateChallengeLock) {
753 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
755 mStorage.removeChildProfileLock(userId);
756 removeKeystoreProfileKey(userId);
758 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
764 public void setBoolean(String key, boolean value, int userId) throws RemoteException {
765 checkWritePermission(userId);
766 setStringUnchecked(key, userId, value ? "1" : "0");
770 public void setLong(String key, long value, int userId) throws RemoteException {
771 checkWritePermission(userId);
772 setStringUnchecked(key, userId, Long.toString(value));
776 public void setString(String key, String value, int userId) throws RemoteException {
777 checkWritePermission(userId);
778 setStringUnchecked(key, userId, value);
781 private void setStringUnchecked(String key, int userId, String value) {
782 mStorage.writeKeyValue(key, value, userId);
783 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
784 BackupManager.dataChanged("com.android.providers.settings");
789 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
790 checkReadPermission(key, userId);
791 String value = getStringUnchecked(key, null, userId);
792 return TextUtils.isEmpty(value) ?
793 defaultValue : (value.equals("1") || value.equals("true"));
797 public long getLong(String key, long defaultValue, int userId) throws RemoteException {
798 checkReadPermission(key, userId);
799 String value = getStringUnchecked(key, null, userId);
800 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
804 public String getString(String key, String defaultValue, int userId) throws RemoteException {
805 checkReadPermission(key, userId);
806 return getStringUnchecked(key, defaultValue, userId);
809 public String getStringUnchecked(String key, String defaultValue, int userId) {
810 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
811 long ident = Binder.clearCallingIdentity();
813 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
815 Binder.restoreCallingIdentity(ident);
819 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
820 key = Settings.Secure.LOCK_PATTERN_ENABLED;
823 return mStorage.readKeyValue(key, defaultValue, userId);
827 public boolean havePassword(int userId) throws RemoteException {
828 synchronized (mSpManager) {
829 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
830 long handle = getSyntheticPasswordHandleLocked(userId);
831 return mSpManager.getCredentialType(handle, userId) ==
832 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
835 // Do we need a permissions check here?
836 return mStorage.hasPassword(userId);
840 public boolean havePattern(int userId) throws RemoteException {
841 synchronized (mSpManager) {
842 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
843 long handle = getSyntheticPasswordHandleLocked(userId);
844 return mSpManager.getCredentialType(handle, userId) ==
845 LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
848 // Do we need a permissions check here?
849 return mStorage.hasPattern(userId);
852 private boolean isUserSecure(int userId) {
853 synchronized (mSpManager) {
855 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
856 long handle = getSyntheticPasswordHandleLocked(userId);
857 return mSpManager.getCredentialType(handle, userId) !=
858 LockPatternUtils.CREDENTIAL_TYPE_NONE;
860 } catch (RemoteException e) {
864 return mStorage.hasCredential(userId);
867 private void setKeystorePassword(String password, int userHandle) {
868 final KeyStore ks = KeyStore.getInstance();
869 ks.onUserPasswordChanged(userHandle, password);
872 private void unlockKeystore(String password, int userHandle) {
873 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
874 final KeyStore ks = KeyStore.getInstance();
875 ks.unlock(userHandle, password);
879 protected String getDecryptedPasswordForTiedProfile(int userId)
880 throws KeyStoreException, UnrecoverableKeyException,
881 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
882 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
883 CertificateException, IOException {
884 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
885 byte[] storedData = mStorage.readChildProfileLock(userId);
886 if (storedData == null) {
887 throw new FileNotFoundException("Child profile lock file not found");
889 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
890 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
892 byte[] decryptionResult;
893 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
895 SecretKey decryptionKey = (SecretKey) keyStore.getKey(
896 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
898 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
899 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
901 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
902 decryptionResult = cipher.doFinal(encryptedPassword);
903 return new String(decryptionResult, StandardCharsets.UTF_8);
906 private void unlockChildProfile(int profileHandle) throws RemoteException {
908 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
909 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
910 false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
911 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
912 | NoSuchAlgorithmException | NoSuchPaddingException
913 | InvalidAlgorithmParameterException | IllegalBlockSizeException
914 | BadPaddingException | CertificateException | IOException e) {
915 if (e instanceof FileNotFoundException) {
916 Slog.i(TAG, "Child profile key not found");
918 Slog.e(TAG, "Failed to decrypt child profile key", e);
923 private void unlockUser(int userId, byte[] token, byte[] secret) {
924 // TODO: make this method fully async so we can update UI with progress strings
925 final CountDownLatch latch = new CountDownLatch(1);
926 final IProgressListener listener = new IProgressListener.Stub() {
928 public void onStarted(int id, Bundle extras) throws RemoteException {
929 Log.d(TAG, "unlockUser started");
933 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
934 Log.d(TAG, "unlockUser progress " + progress);
938 public void onFinished(int id, Bundle extras) throws RemoteException {
939 Log.d(TAG, "unlockUser finished");
945 mActivityManager.unlockUser(userId, token, secret, listener);
946 } catch (RemoteException e) {
947 throw e.rethrowAsRuntimeException();
951 latch.await(15, TimeUnit.SECONDS);
952 } catch (InterruptedException e) {
953 Thread.currentThread().interrupt();
956 if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
957 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
958 for (UserInfo pi : profiles) {
959 // Unlock managed profile with unified lock
960 if (pi.isManagedProfile()
961 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
962 && mStorage.hasChildProfileLock(pi.id)) {
963 unlockChildProfile(pi.id);
967 } catch (RemoteException e) {
968 Log.d(TAG, "Failed to unlock child profile", e);
972 private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
973 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
976 Map<Integer, String> result = new ArrayMap<Integer, String>();
977 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
978 final int size = profiles.size();
979 for (int i = 0; i < size; i++) {
980 final UserInfo profile = profiles.get(i);
981 if (!profile.isManagedProfile()) {
984 final int managedUserId = profile.id;
985 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
989 result.put(userId, getDecryptedPasswordForTiedProfile(userId));
990 } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
991 | NoSuchPaddingException | InvalidKeyException
992 | InvalidAlgorithmParameterException | IllegalBlockSizeException
993 | BadPaddingException | CertificateException | IOException e) {
1001 * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1002 * depending on the parent user's secure state.
1004 * When clearing tied work challenges, a pre-computed password table for profiles are required,
1005 * since changing password for profiles requires existing password, and existing passwords can
1006 * only be computed before the parent user's password is cleared.
1008 * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1009 * method again on profiles. However the recursion is guaranteed to terminate as this method
1010 * terminates when the user is a managed profile.
1012 private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1013 Map<Integer, String> profilePasswordMap) throws RemoteException {
1014 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1017 final boolean isSecure = isUserSecure(userId);
1018 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1019 final int size = profiles.size();
1020 for (int i = 0; i < size; i++) {
1021 final UserInfo profile = profiles.get(i);
1022 if (profile.isManagedProfile()) {
1023 final int managedUserId = profile.id;
1024 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1028 tieManagedProfileLockIfNecessary(managedUserId, null);
1030 // We use cached work profile password computed before clearing the parent's
1031 // credential, otherwise they get lost
1032 if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
1033 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
1034 profilePasswordMap.get(managedUserId), managedUserId);
1036 Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
1037 // Supplying null here would lead to untrusted credential change
1038 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
1041 mStorage.removeChildProfileLock(managedUserId);
1042 removeKeystoreProfileKey(managedUserId);
1048 private boolean isManagedProfileWithUnifiedLock(int userId) {
1049 return mUserManager.getUserInfo(userId).isManagedProfile()
1050 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1053 private boolean isManagedProfileWithSeparatedLock(int userId) {
1054 return mUserManager.getUserInfo(userId).isManagedProfile()
1055 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1058 // This method should be called by LockPatternUtil only, all internal methods in this class
1059 // should call setLockCredentialInternal.
1061 public void setLockCredential(String credential, int type, String savedCredential, int userId)
1062 throws RemoteException {
1063 checkWritePermission(userId);
1064 synchronized (mSeparateChallengeLock) {
1065 setLockCredentialInternal(credential, type, savedCredential, userId);
1066 setSeparateProfileChallengeEnabled(userId, true, null);
1067 notifyPasswordChanged(userId);
1071 private void setLockCredentialInternal(String credential, int credentialType,
1072 String savedCredential, int userId) throws RemoteException {
1073 // Normalize savedCredential and credential such that empty string is always represented
1075 if (TextUtils.isEmpty(savedCredential)) {
1076 savedCredential = null;
1078 if (TextUtils.isEmpty(credential)) {
1081 synchronized (mSpManager) {
1082 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1083 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
1088 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1089 if (credential != null) {
1090 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
1092 clearUserKeyProtection(userId);
1093 getGateKeeperService().clearSecureUserId(userId);
1094 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
1095 setKeystorePassword(null, userId);
1096 fixateNewestUserKeyAuth(userId);
1097 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1098 notifyActivePasswordMetricsAvailable(null, userId);
1101 if (credential == null) {
1102 throw new RemoteException("Null credential with mismatched credential type");
1105 CredentialHash currentHandle = mStorage.readCredentialHash(userId);
1106 if (isManagedProfileWithUnifiedLock(userId)) {
1107 // get credential from keystore when managed profile has unified lock
1108 if (savedCredential == null) {
1110 savedCredential = getDecryptedPasswordForTiedProfile(userId);
1111 } catch (FileNotFoundException e) {
1112 Slog.i(TAG, "Child profile key not found");
1113 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1114 | NoSuchAlgorithmException | NoSuchPaddingException
1115 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1116 | BadPaddingException | CertificateException | IOException e) {
1117 Slog.e(TAG, "Failed to decrypt child profile key", e);
1121 if (currentHandle.hash == null) {
1122 if (savedCredential != null) {
1123 Slog.w(TAG, "Saved credential provided, but none stored");
1125 savedCredential = null;
1128 synchronized (mSpManager) {
1129 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1130 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
1131 currentHandle.type, userId);
1132 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
1137 if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
1138 byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
1140 if (enrolledHandle != null) {
1141 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
1142 mStorage.writeCredentialHash(willStore, userId);
1143 // push new secret and auth token to vold
1144 GateKeeperResponse gkResponse = getGateKeeperService()
1145 .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
1146 setUserKeyProtection(userId, credential, convertResponse(gkResponse));
1147 fixateNewestUserKeyAuth(userId);
1148 // Refresh the auth token
1149 doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
1150 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1152 throw new RemoteException("Failed to enroll " +
1153 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
1158 private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
1159 VerifyCredentialResponse response;
1160 int responseCode = gateKeeperResponse.getResponseCode();
1161 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1162 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
1163 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1164 byte[] token = gateKeeperResponse.getPayload();
1165 if (token == null) {
1166 // something's wrong if there's no payload with a challenge
1167 Slog.e(TAG, "verifyChallenge response had no associated payload");
1168 response = VerifyCredentialResponse.ERROR;
1170 response = new VerifyCredentialResponse(token);
1173 response = VerifyCredentialResponse.ERROR;
1179 protected void tieProfileLockToParent(int userId, String password) {
1180 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1181 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1182 byte[] encryptionResult;
1185 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1186 keyGenerator.init(new SecureRandom());
1187 SecretKey secretKey = keyGenerator.generateKey();
1188 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1189 keyStore.load(null);
1192 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1193 new java.security.KeyStore.SecretKeyEntry(secretKey),
1194 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1195 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1196 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1199 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1200 new java.security.KeyStore.SecretKeyEntry(secretKey),
1201 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1202 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1203 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1204 .setUserAuthenticationRequired(true)
1205 .setUserAuthenticationValidityDurationSeconds(30)
1207 // Key imported, obtain a reference to it.
1208 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1209 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1210 Cipher cipher = Cipher.getInstance(
1211 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1212 + KeyProperties.ENCRYPTION_PADDING_NONE);
1213 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1214 encryptionResult = cipher.doFinal(randomLockSeed);
1215 iv = cipher.getIV();
1217 // The original key can now be discarded.
1218 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1220 } catch (CertificateException | UnrecoverableKeyException
1221 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
1222 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1223 throw new RuntimeException("Failed to encrypt key", e);
1225 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1227 if (iv.length != PROFILE_KEY_IV_SIZE) {
1228 throw new RuntimeException("Invalid iv length: " + iv.length);
1230 outputStream.write(iv);
1231 outputStream.write(encryptionResult);
1232 } catch (IOException e) {
1233 throw new RuntimeException("Failed to concatenate byte arrays", e);
1235 mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1238 private byte[] enrollCredential(byte[] enrolledHandle,
1239 String enrolledCredential, String toEnroll, int userId)
1240 throws RemoteException {
1241 checkWritePermission(userId);
1242 byte[] enrolledCredentialBytes = enrolledCredential == null
1244 : enrolledCredential.getBytes();
1245 byte[] toEnrollBytes = toEnroll == null
1247 : toEnroll.getBytes();
1248 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1249 enrolledCredentialBytes, toEnrollBytes);
1251 if (response == null) {
1255 byte[] hash = response.getPayload();
1257 setKeystorePassword(toEnroll, userId);
1259 // Should not happen
1260 Slog.e(TAG, "Throttled while enrolling a password");
1265 private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
1266 if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1267 addUserKeyAuth(userId, null, key);
1270 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1271 throws RemoteException {
1272 if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
1274 throw new RemoteException("Null response verifying a credential we just set");
1276 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1277 throw new RemoteException("Non-OK response verifying a credential we just set: "
1278 + vcr.getResponseCode());
1280 byte[] token = vcr.getPayload();
1281 if (token == null) {
1282 throw new RemoteException("Empty payload verifying a credential we just set");
1284 addUserKeyAuth(userId, token, secretFromCredential(credential));
1287 private void clearUserKeyProtection(int userId) throws RemoteException {
1288 if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
1289 addUserKeyAuth(userId, null, null);
1292 private static byte[] secretFromCredential(String credential) throws RemoteException {
1294 MessageDigest digest = MessageDigest.getInstance("SHA-512");
1295 // Personalize the hash
1296 byte[] personalization = "Android FBE credential hash"
1297 .getBytes(StandardCharsets.UTF_8);
1298 // Pad it to the block size of the hash function
1299 personalization = Arrays.copyOf(personalization, 128);
1300 digest.update(personalization);
1301 digest.update(credential.getBytes(StandardCharsets.UTF_8));
1302 return digest.digest();
1303 } catch (NoSuchAlgorithmException e) {
1304 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1308 private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
1309 throws RemoteException {
1310 final UserInfo userInfo = mUserManager.getUserInfo(userId);
1311 final IStorageManager storageManager = mInjector.getStorageManager();
1312 final long callingId = Binder.clearCallingIdentity();
1314 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
1316 Binder.restoreCallingIdentity(callingId);
1320 private void fixateNewestUserKeyAuth(int userId)
1321 throws RemoteException {
1322 if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
1323 final IStorageManager storageManager = mInjector.getStorageManager();
1324 final long callingId = Binder.clearCallingIdentity();
1326 storageManager.fixateNewestUserKeyAuth(userId);
1328 Binder.restoreCallingIdentity(callingId);
1333 public void resetKeyStore(int userId) throws RemoteException {
1334 checkWritePermission(userId);
1335 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1336 int managedUserId = -1;
1337 String managedUserDecryptedPassword = null;
1338 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1339 for (UserInfo pi : profiles) {
1340 // Unlock managed profile with unified lock
1341 if (pi.isManagedProfile()
1342 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1343 && mStorage.hasChildProfileLock(pi.id)) {
1345 if (managedUserId == -1) {
1346 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1347 managedUserId = pi.id;
1349 // Should not happen
1350 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1351 + ", uid2:" + pi.id);
1353 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1354 | NoSuchAlgorithmException | NoSuchPaddingException
1355 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1356 | BadPaddingException | CertificateException | IOException e) {
1357 Slog.e(TAG, "Failed to decrypt child profile key", e);
1362 // Clear all the users credentials could have been installed in for this user.
1363 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1364 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1365 mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1369 if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1370 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
1371 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
1377 public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
1378 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1379 checkPasswordReadPermission(userId);
1380 return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
1384 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
1385 int userId) throws RemoteException {
1386 checkPasswordReadPermission(userId);
1387 return doVerifyCredential(credential, type, true, challenge, userId,
1388 null /* progressCallback */);
1392 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
1395 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
1396 boolean hasChallenge, long challenge, int userId,
1397 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1398 if (TextUtils.isEmpty(credential)) {
1399 throw new IllegalArgumentException("Credential can't be null or empty");
1401 synchronized (mSpManager) {
1402 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1403 VerifyCredentialResponse response = spBasedDoVerifyCredentialLocked(credential,
1404 credentialType, hasChallenge, challenge, userId, progressCallback);
1405 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1406 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1411 CredentialHash storedHash = mStorage.readCredentialHash(userId);
1412 if (storedHash.type != credentialType) {
1413 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
1414 + " stored: " + storedHash.type + " passed in: " + credentialType);
1415 return VerifyCredentialResponse.ERROR;
1418 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1419 && storedHash.isBaseZeroPattern;
1421 String credentialToVerify;
1422 if (shouldReEnrollBaseZero) {
1423 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
1425 credentialToVerify = credential;
1428 VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify,
1429 hasChallenge, challenge, progressCallback);
1431 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1432 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1433 if (shouldReEnrollBaseZero) {
1434 setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
1442 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
1443 long challenge, int userId) throws RemoteException {
1444 checkPasswordReadPermission(userId);
1445 if (!isManagedProfileWithUnifiedLock(userId)) {
1446 throw new RemoteException("User id must be managed profile with unified lock");
1448 final int parentProfileId = mUserManager.getProfileParent(userId).id;
1449 // Unlock parent by using parent's challenge
1450 final VerifyCredentialResponse parentResponse = doVerifyCredential(
1453 true /* hasChallenge */,
1456 null /* progressCallback */);
1457 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1458 // Failed, just return parent's response
1459 return parentResponse;
1463 // Unlock work profile, and work profile with unified lock must use password only
1464 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
1465 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1468 userId, null /* progressCallback */);
1469 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1470 | NoSuchAlgorithmException | NoSuchPaddingException
1471 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1472 | BadPaddingException | CertificateException | IOException e) {
1473 Slog.e(TAG, "Failed to decrypt child profile key", e);
1474 throw new RemoteException("Unable to get tied profile token");
1479 * Lowest-level credential verification routine that talks to GateKeeper. If verification
1480 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
1483 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
1484 String credential, boolean hasChallenge, long challenge,
1485 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1486 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1487 // don't need to pass empty credentials to GateKeeper
1488 return VerifyCredentialResponse.OK;
1491 if (TextUtils.isEmpty(credential)) {
1492 return VerifyCredentialResponse.ERROR;
1495 // We're potentially going to be doing a bunch of disk I/O below as part
1496 // of unlocking the user, so yell if calling from the main thread.
1497 StrictMode.noteDiskRead();
1499 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
1501 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1502 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
1504 hash = mLockPatternUtils.passwordToHash(credential, userId);
1506 if (Arrays.equals(hash, storedHash.hash)) {
1507 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1508 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
1510 unlockKeystore(credential, userId);
1512 // Users with legacy credentials don't have credential-backed
1513 // FBE keys, so just pass through a fake token/secret
1514 Slog.i(TAG, "Unlocking user with fake token: " + userId);
1515 final byte[] fakeToken = String.valueOf(userId).getBytes();
1516 unlockUser(userId, fakeToken, fakeToken);
1518 // migrate credential to GateKeeper
1519 setLockCredentialInternal(credential, storedHash.type, null, userId);
1520 if (!hasChallenge) {
1521 notifyActivePasswordMetricsAvailable(credential, userId);
1522 return VerifyCredentialResponse.OK;
1524 // Fall through to get the auth token. Technically this should never happen,
1525 // as a user that had a legacy credential would have to unlock their device
1526 // before getting to a flow with a challenge, but supporting for consistency.
1528 return VerifyCredentialResponse.ERROR;
1531 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1532 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
1533 VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
1534 boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
1536 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1538 // credential has matched
1540 if (progressCallback != null) {
1541 progressCallback.onCredentialVerified();
1543 notifyActivePasswordMetricsAvailable(credential, userId);
1544 unlockKeystore(credential, userId);
1546 Slog.i(TAG, "Unlocking user " + userId + " with token length "
1547 + response.getPayload().length);
1548 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
1550 if (isManagedProfileWithSeparatedLock(userId)) {
1551 TrustManager trustManager =
1552 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1553 trustManager.setDeviceLockedForUser(userId, false);
1555 if (shouldReEnroll) {
1556 setLockCredentialInternal(credential, storedHash.type, credential, userId);
1558 // Now that we've cleared of all required GK migration, let's do the final
1559 // migration to synthetic password.
1560 synchronized (mSpManager) {
1561 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1562 initializeSyntheticPasswordLocked(storedHash.hash, credential,
1563 storedHash.type, userId);
1567 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1568 if (response.getTimeout() > 0) {
1569 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1576 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
1577 final PasswordMetrics metrics;
1578 if (password == null) {
1579 metrics = new PasswordMetrics();
1581 metrics = PasswordMetrics.computeForPassword(password);
1582 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
1585 // Asynchronous to avoid dead lock
1586 mHandler.post(() -> {
1587 DevicePolicyManager dpm = (DevicePolicyManager)
1588 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1589 dpm.setActivePasswordState(metrics, userId);
1594 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
1595 * reporting the password changed.
1597 private void notifyPasswordChanged(@UserIdInt int userId) {
1598 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
1599 mHandler.post(() -> {
1600 DevicePolicyManager dpm = (DevicePolicyManager)
1601 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1602 dpm.reportPasswordChanged(userId);
1607 public boolean checkVoldPassword(int userId) throws RemoteException {
1608 if (!mFirstCallToVold) {
1611 mFirstCallToVold = false;
1613 checkPasswordReadPermission(userId);
1615 // There's no guarantee that this will safely connect, but if it fails
1616 // we will simply show the lock screen when we shouldn't, so relatively
1617 // benign. There is an outside chance something nasty would happen if
1618 // this service restarted before vold stales out the password in this
1619 // case. The nastiness is limited to not showing the lock screen when
1620 // we should, within the first minute of decrypting the phone if this
1621 // service can't connect to vold, it restarts, and then the new instance
1622 // does successfully connect.
1623 final IStorageManager service = mInjector.getStorageManager();
1625 long identity = Binder.clearCallingIdentity();
1627 password = service.getPassword();
1628 service.clearPassword();
1630 Binder.restoreCallingIdentity(identity);
1632 if (password == null) {
1637 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
1638 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
1639 null /* progressCallback */)
1640 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1644 } catch (Exception e) {
1648 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
1649 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
1650 null /* progressCallback */)
1651 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1655 } catch (Exception e) {
1661 private void removeUser(int userId, boolean unknownUser) {
1662 mStorage.removeUser(userId);
1663 mStrongAuth.removeUser(userId);
1665 final KeyStore ks = KeyStore.getInstance();
1666 ks.onUserRemoved(userId);
1669 final IGateKeeperService gk = getGateKeeperService();
1671 gk.clearSecureUserId(userId);
1673 } catch (RemoteException ex) {
1674 Slog.w(TAG, "unable to clear GK secure user id");
1676 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
1677 removeKeystoreProfileKey(userId);
1681 private void removeKeystoreProfileKey(int targetUserId) {
1682 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1684 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1685 keyStore.load(null);
1686 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1687 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
1688 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1690 // We have tried our best to remove all keys
1691 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1696 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1697 checkPasswordReadPermission(UserHandle.USER_ALL);
1698 mStrongAuth.registerStrongAuthTracker(tracker);
1702 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1703 checkPasswordReadPermission(UserHandle.USER_ALL);
1704 mStrongAuth.unregisterStrongAuthTracker(tracker);
1708 public void requireStrongAuth(int strongAuthReason, int userId) {
1709 checkWritePermission(userId);
1710 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1714 public void userPresent(int userId) {
1715 checkWritePermission(userId);
1716 mStrongAuth.reportUnlock(userId);
1720 public int getStrongAuthForUser(int userId) {
1721 checkPasswordReadPermission(userId);
1722 return mStrongAuthTracker.getStrongAuthForUser(userId);
1725 private boolean isCallerShell() {
1726 final int callingUid = Binder.getCallingUid();
1727 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1730 private void enforceShell() {
1731 if (!isCallerShell()) {
1732 throw new SecurityException("Caller must be shell");
1737 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1738 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1739 throws RemoteException {
1741 final long origId = Binder.clearCallingIdentity();
1743 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
1744 this, in, out, err, args, callback, resultReceiver);
1746 Binder.restoreCallingIdentity(origId);
1750 private static final String[] VALID_SETTINGS = new String[] {
1751 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
1752 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
1753 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
1754 LockPatternUtils.PASSWORD_TYPE_KEY,
1755 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
1756 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1757 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
1758 LockPatternUtils.LOCKSCREEN_OPTIONS,
1759 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
1760 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
1761 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
1762 LockPatternUtils.PASSWORD_HISTORY_KEY,
1763 Secure.LOCK_PATTERN_ENABLED,
1764 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
1765 Secure.LOCK_PATTERN_VISIBLE,
1766 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
1769 // Reading these settings needs the contacts permission
1770 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
1771 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1772 Secure.LOCK_SCREEN_OWNER_INFO
1775 // Reading these settings needs the same permission as checking the password
1776 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
1777 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1778 LockPatternUtils.PASSWORD_HISTORY_KEY,
1779 LockPatternUtils.PASSWORD_TYPE_KEY,
1780 SEPARATE_PROFILE_CHALLENGE_KEY
1783 private static final String[] SETTINGS_TO_BACKUP = new String[] {
1784 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1785 Secure.LOCK_SCREEN_OWNER_INFO
1788 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
1790 public void binderDied() {
1791 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
1792 mGateKeeperService = null;
1796 protected synchronized IGateKeeperService getGateKeeperService()
1797 throws RemoteException {
1798 if (mGateKeeperService != null) {
1799 return mGateKeeperService;
1802 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
1803 if (service != null) {
1804 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
1805 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
1806 return mGateKeeperService;
1809 Slog.e(TAG, "Unable to acquire GateKeeperService");
1814 * Precondition: vold and keystore unlocked.
1816 * Create new synthetic password, set up synthetic password blob protected by the supplied
1817 * user credential, and make the newly-created SP blob active.
1819 * The invariant under a synthetic password is:
1820 * 1. If user credential exists, then both vold and keystore and protected with keys derived
1821 * from the synthetic password.
1822 * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
1823 * make it consistent with current behaviour. It also allows ActivityManager to call
1824 * unlockUser() with empty secret.
1825 * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
1826 * whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
1827 * lockscreen PIN, we still maintain the existing synthetic password in a password blob
1828 * protected by a default PIN. The only exception is when the DPC performs an untrusted
1829 * credential change, in which case we have no way to derive the existing synthetic password
1830 * and has to create a new one.
1831 * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
1832 * clears/re-creates his lockscreen PIN.
1835 * Different cases of calling this method:
1836 * 1. credentialHash != null
1837 * This implies credential != null, a new SP blob will be provisioned, and existing SID
1838 * migrated to associate with the new SP.
1839 * This happens during a normal migration case when the user currently has password.
1841 * 2. credentialhash == null and credential == null
1842 * A new SP blob and a new SID will be created, while the user has no credentials.
1843 * This can happens when we are activating an escrow token on a unsecured device, during
1844 * which we want to create the SP structure with an empty user credential.
1846 * 3. credentialhash == null and credential != null
1847 * This is the untrusted credential reset, OR the user sets a new lockscreen password
1848 * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
1850 private AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
1851 String credential, int credentialType, int userId) throws RemoteException {
1852 Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
1853 AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(getGateKeeperService(),
1854 credentialHash, credential, userId);
1856 Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
1859 long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
1860 credential, credentialType, auth, userId);
1861 if (credential != null) {
1862 if (credentialHash == null) {
1863 // Since when initializing SP, we didn't provide an existing password handle
1864 // for it to migrate SID, we need to create a new SID for the user.
1865 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
1867 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1868 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
1869 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
1871 clearUserKeyProtection(userId);
1872 setKeystorePassword(null, userId);
1873 getGateKeeperService().clearSecureUserId(userId);
1875 fixateNewestUserKeyAuth(userId);
1876 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
1880 private long getSyntheticPasswordHandleLocked(int userId) {
1882 return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId);
1883 } catch (RemoteException e) {
1884 return SyntheticPasswordManager.DEFAULT_HANDLE;
1888 private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
1889 long handle = getSyntheticPasswordHandleLocked(userId);
1890 // This is a global setting
1891 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
1892 return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
1895 private boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
1896 long handle = getSyntheticPasswordHandleLocked(userId);
1897 // This is a global setting
1898 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
1899 return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
1902 private void enableSyntheticPasswordLocked() throws RemoteException {
1903 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
1906 private VerifyCredentialResponse spBasedDoVerifyCredentialLocked(String userCredential, int
1907 credentialType, boolean hasChallenge, long challenge, int userId,
1908 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1909 if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredentialLocked: user=" + userId);
1910 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1911 userCredential = null;
1913 long handle = getSyntheticPasswordHandleLocked(userId);
1914 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
1915 getGateKeeperService(), handle, userCredential, userId);
1917 VerifyCredentialResponse response = authResult.gkResponse;
1918 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1919 // credential has matched
1920 // perform verifyChallenge with synthetic password which generates the real auth
1921 // token for the current user
1922 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
1924 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1925 Slog.wtf(TAG, "verifyChallenge with SP failed.");
1926 return VerifyCredentialResponse.ERROR;
1928 if (progressCallback != null) {
1929 progressCallback.onCredentialVerified();
1931 notifyActivePasswordMetricsAvailable(userCredential, userId);
1932 unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
1934 final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
1935 Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
1936 unlockUser(userId, null, secret);
1938 if (isManagedProfileWithSeparatedLock(userId)) {
1939 TrustManager trustManager =
1940 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1941 trustManager.setDeviceLockedForUser(userId, false);
1943 activateEscrowTokens(authResult.authToken, userId);
1944 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1945 if (response.getTimeout() > 0) {
1946 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1954 * Change the user's lockscreen password by creating a new SP blob and update the handle, based
1955 * on an existing authentication token. Even though a new SP blob is created, the underlying
1956 * synthetic password is never changed.
1958 * When clearing credential, we keep the SP unchanged, but clear its password handle so its
1959 * SID is gone. We also clear password from (software-based) keystore and vold, which will be
1960 * added back when new password is set in future.
1962 private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
1963 AuthenticationToken auth, int userId) throws RemoteException {
1964 if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
1965 long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
1966 credential, credentialType, auth, userId);
1967 final Map<Integer, String> profilePasswords;
1968 if (credential != null) {
1969 // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
1970 profilePasswords = null;
1972 if (mSpManager.hasSidForUser(userId)) {
1973 // We are changing password of a secured device, nothing more needed as
1974 // createPasswordBasedSyntheticPassword has already taken care of maintaining
1975 // the password handle and SID unchanged.
1977 //refresh auth token
1978 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1980 // A new password is set on a previously-unsecured device, we need to generate
1981 // a new SID, and re-add keys to vold and keystore.
1982 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
1983 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1984 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
1985 fixateNewestUserKeyAuth(userId);
1986 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
1989 // Cache all profile password if they use unified work challenge. This will later be
1990 // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
1991 profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
1993 // we are clearing password of a secured device, so need to nuke SID as well.
1994 mSpManager.clearSidForUser(userId);
1995 getGateKeeperService().clearSecureUserId(userId);
1996 // Clear key from vold so ActivityManager can just unlock the user with empty secret
1998 clearUserKeyProtection(userId);
1999 fixateNewestUserKeyAuth(userId);
2000 setKeystorePassword(null, userId);
2002 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
2003 synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
2007 private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
2008 String savedCredential, int userId) throws RemoteException {
2009 if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2010 if (isManagedProfileWithUnifiedLock(userId)) {
2011 // get credential from keystore when managed profile has unified lock
2013 savedCredential = getDecryptedPasswordForTiedProfile(userId);
2014 } catch (FileNotFoundException e) {
2015 Slog.i(TAG, "Child profile key not found");
2016 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2017 | NoSuchAlgorithmException | NoSuchPaddingException
2018 | InvalidAlgorithmParameterException | IllegalBlockSizeException
2019 | BadPaddingException | CertificateException | IOException e) {
2020 Slog.e(TAG, "Failed to decrypt child profile key", e);
2023 long handle = getSyntheticPasswordHandleLocked(userId);
2024 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
2025 getGateKeeperService(), handle, savedCredential, userId);
2026 VerifyCredentialResponse response = authResult.gkResponse;
2027 AuthenticationToken auth = authResult.authToken;
2029 // We are performing a trusted credential change i.e. a correct existing credential
2031 setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId);
2032 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2033 } else if (response != null
2034 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){
2035 // We are performing an untrusted credential change i.e. by DevicePolicyManager.
2036 // So provision a new SP and SID. This would invalidate existing escrow tokens.
2037 // Still support this for now but this flow will be removed in the next release.
2039 Slog.w(TAG, "Untrusted credential change invoked");
2040 initializeSyntheticPasswordLocked(null, credential, credentialType, userId);
2041 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
2042 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2043 } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
2044 Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
2045 (response != null ? "rate limit exceeded" : "failed"));
2048 notifyActivePasswordMetricsAvailable(credential, userId);
2053 public long addEscrowToken(byte[] token, int userId) throws RemoteException {
2054 ensureCallerSystemUid();
2055 if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
2056 synchronized (mSpManager) {
2057 enableSyntheticPasswordLocked();
2058 // Migrate to synthetic password based credentials if the user has no password,
2059 // the token can then be activated immediately.
2060 AuthenticationToken auth = null;
2061 if (!isUserSecure(userId)) {
2062 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2063 auth = initializeSyntheticPasswordLocked(null, null,
2064 LockPatternUtils.CREDENTIAL_TYPE_NONE, userId);
2065 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
2066 long pwdHandle = getSyntheticPasswordHandleLocked(userId);
2067 auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
2068 pwdHandle, null, userId).authToken;
2071 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2072 if (!mSpManager.hasEscrowData(userId)) {
2073 throw new SecurityException("Escrow token is disabled on the current user");
2075 long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
2077 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2083 private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
2084 if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
2085 synchronized (mSpManager) {
2086 for (long handle : mSpManager.getPendingTokensForUser(userId)) {
2087 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
2088 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2094 public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
2095 ensureCallerSystemUid();
2096 synchronized (mSpManager) {
2097 return mSpManager.existsHandle(handle, userId);
2102 public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
2103 ensureCallerSystemUid();
2104 synchronized (mSpManager) {
2105 if (handle == getSyntheticPasswordHandleLocked(userId)) {
2106 Slog.w(TAG, "Cannot remove password handle");
2109 if (mSpManager.removePendingToken(handle, userId)) {
2112 if (mSpManager.existsHandle(handle, userId)) {
2113 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
2122 public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
2123 byte[] token, int userId) throws RemoteException {
2124 ensureCallerSystemUid();
2126 synchronized (mSpManager) {
2127 if (!mSpManager.hasEscrowData(userId)) {
2128 throw new SecurityException("Escrow token is disabled on the current user");
2130 result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
2134 synchronized (mSeparateChallengeLock) {
2135 setSeparateProfileChallengeEnabled(userId, true, null);
2137 notifyPasswordChanged(userId);
2142 private boolean setLockCredentialWithTokenInternal(String credential, int type,
2143 long tokenHandle, byte[] token, int userId) throws RemoteException {
2144 synchronized (mSpManager) {
2145 AuthenticationResult result = mSpManager.unwrapTokenBasedSyntheticPassword(
2146 getGateKeeperService(), tokenHandle, token, userId);
2147 if (result.authToken == null) {
2148 Slog.w(TAG, "Invalid escrow token supplied");
2151 long oldHandle = getSyntheticPasswordHandleLocked(userId);
2152 setLockCredentialWithAuthTokenLocked(credential, type, result.authToken, userId);
2153 mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
2159 public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
2160 throws RemoteException {
2161 ensureCallerSystemUid();
2162 AuthenticationResult authResult;
2163 synchronized (mSpManager) {
2164 if (!mSpManager.hasEscrowData(userId)) {
2165 throw new SecurityException("Escrow token is disabled on the current user");
2167 authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
2168 tokenHandle, token, userId);
2169 if (authResult.authToken == null) {
2170 Slog.w(TAG, "Invalid escrow token supplied");
2174 unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
2178 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
2179 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2180 != PackageManager.PERMISSION_GRANTED) {
2182 pw.println("Permission Denial: can't dump LockSettingsService from from pid="
2183 + Binder.getCallingPid()
2184 + ", uid=" + Binder.getCallingUid());
2188 synchronized (this) {
2189 pw.println("Current lock settings service state:");
2190 pw.println(String.format("SP Enabled = %b",
2191 mLockPatternUtils.isSyntheticPasswordEnabled()));
2193 List<UserInfo> users = mUserManager.getUsers();
2194 for (int user = 0; user < users.size(); user++) {
2195 final int userId = users.get(user).id;
2196 pw.println(" User " + userId);
2197 pw.println(String.format(" SP Handle = %x",
2198 getSyntheticPasswordHandleLocked(userId)));
2200 pw.println(String.format(" SID = %x",
2201 getGateKeeperService().getSecureUserId(userId)));
2202 } catch (RemoteException e) {
2209 private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
2210 long ident = Binder.clearCallingIdentity();
2212 // Managed profile should have escrow enabled
2213 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
2214 Slog.i(TAG, "Managed profile can have escrow token");
2217 // Devices with Device Owner should have escrow enabled on all users.
2218 if (mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser() != null) {
2219 Slog.i(TAG, "Corp-owned device can have escrow token");
2222 // We could also have a profile owner on the given (non-managed) user for unicorn cases
2223 if (mDevicePolicyManager.getProfileOwnerAsUser(userId) != null) {
2224 Slog.i(TAG, "User with profile owner can have escrow token");
2227 // If the device is yet to be provisioned (still in SUW), there is still
2228 // a chance that Device Owner will be set on the device later, so postpone
2229 // disabling escrow token for now.
2230 if (!mDevicePolicyManager.isDeviceProvisioned()) {
2231 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
2235 // Escrow tokens are enabled on automotive builds.
2236 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
2240 // Disable escrow token permanently on all other device/user types.
2241 Slog.i(TAG, "Disabling escrow token on user " + userId);
2242 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2243 mSpManager.destroyEscrowData(userId);
2245 } catch (RemoteException e) {
2246 Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
2248 Binder.restoreCallingIdentity(ident);
2252 private void ensureCallerSystemUid() throws SecurityException {
2253 final int callingUid = mInjector.binderGetCallingUid();
2254 if (callingUid != Process.SYSTEM_UID) {
2255 throw new SecurityException("Only system can call this API.");