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.messages.nano.SystemMessageProto.SystemMessage;
80 import com.android.internal.notification.SystemNotificationChannels;
81 import com.android.internal.util.ArrayUtils;
82 import com.android.internal.util.DumpUtils;
83 import com.android.internal.widget.ICheckCredentialProgressCallback;
84 import com.android.internal.widget.ILockSettings;
85 import com.android.internal.widget.LockPatternUtils;
86 import com.android.internal.widget.VerifyCredentialResponse;
87 import com.android.server.LockSettingsStorage.CredentialHash;
88 import com.android.server.SyntheticPasswordManager.AuthenticationResult;
89 import com.android.server.SyntheticPasswordManager.AuthenticationToken;
91 import libcore.util.HexEncoding;
93 import java.io.ByteArrayOutputStream;
94 import java.io.FileDescriptor;
95 import java.io.FileNotFoundException;
96 import java.io.IOException;
97 import java.io.PrintWriter;
98 import java.nio.charset.StandardCharsets;
99 import java.security.InvalidAlgorithmParameterException;
100 import java.security.InvalidKeyException;
101 import java.security.KeyStoreException;
102 import java.security.MessageDigest;
103 import java.security.NoSuchAlgorithmException;
104 import java.security.SecureRandom;
105 import java.security.UnrecoverableKeyException;
106 import java.security.cert.CertificateException;
107 import java.util.ArrayList;
108 import java.util.Arrays;
109 import java.util.List;
110 import java.util.Map;
111 import java.util.concurrent.CountDownLatch;
112 import java.util.concurrent.TimeUnit;
114 import javax.crypto.BadPaddingException;
115 import javax.crypto.Cipher;
116 import javax.crypto.IllegalBlockSizeException;
117 import javax.crypto.KeyGenerator;
118 import javax.crypto.NoSuchPaddingException;
119 import javax.crypto.SecretKey;
120 import javax.crypto.spec.GCMParameterSpec;
123 * Keeps the lock pattern/password data and related settings for each user. Used by
124 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
125 * lockscreen information for secondary users.
129 public class LockSettingsService extends ILockSettings.Stub {
130 private static final String TAG = "LockSettingsService";
131 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
132 private static final boolean DEBUG = false;
134 private static final int PROFILE_KEY_IV_SIZE = 12;
135 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
137 private final Object mSeparateChallengeLock = new Object();
139 private final Injector mInjector;
140 private final Context mContext;
141 private final Handler mHandler;
143 protected final LockSettingsStorage mStorage;
144 private final LockSettingsStrongAuth mStrongAuth;
145 private final SynchronizedStrongAuthTracker mStrongAuthTracker;
147 private final LockPatternUtils mLockPatternUtils;
148 private final NotificationManager mNotificationManager;
149 private final UserManager mUserManager;
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 mStrongAuthTracker = injector.getStrongAuthTracker();
389 mStrongAuthTracker.register(mStrongAuth);
391 mSpManager = injector.getSyntheticPasswordManager(mStorage);
395 * If the account is credential-encrypted, show notification requesting the user to unlock the
398 private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
399 final UserInfo user = mUserManager.getUserInfo(userId);
400 if (!user.isManagedProfile()) {
401 // When the user is locked, we communicate it loud-and-clear
402 // on the lockscreen; we only show a notification below for
403 // locked managed profiles.
407 final UserHandle userHandle = user.getUserHandle();
408 final boolean isSecure = isUserSecure(userId);
409 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
410 UserInfo parent = mUserManager.getProfileParent(userId);
411 if (parent != null &&
412 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
413 !mUserManager.isQuietModeEnabled(userHandle)) {
414 // Only show notifications for managed profiles once their parent
416 showEncryptionNotificationForProfile(userHandle);
421 private void showEncryptionNotificationForProfile(UserHandle user) {
422 Resources r = mContext.getResources();
423 CharSequence title = r.getText(
424 com.android.internal.R.string.user_encrypted_title);
425 CharSequence message = r.getText(
426 com.android.internal.R.string.profile_encrypted_message);
427 CharSequence detail = r.getText(
428 com.android.internal.R.string.profile_encrypted_detail);
430 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
431 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
432 user.getIdentifier());
433 if (unlockIntent == null) {
436 unlockIntent.setFlags(
437 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
438 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
439 PendingIntent.FLAG_UPDATE_CURRENT);
441 showEncryptionNotification(user, title, message, detail, intent);
444 private void showEncryptionNotification(UserHandle user, CharSequence title,
445 CharSequence message, CharSequence detail, PendingIntent intent) {
446 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
448 // Suppress all notifications on non-FBE devices for now
449 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
451 Notification notification =
452 new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
453 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
457 .setColor(mContext.getColor(
458 com.android.internal.R.color.system_notification_accent_color))
459 .setContentTitle(title)
460 .setContentText(message)
462 .setVisibility(Notification.VISIBILITY_PUBLIC)
463 .setContentIntent(intent)
465 mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
469 private void hideEncryptionNotification(UserHandle userHandle) {
470 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
471 mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
475 public void onCleanupUser(int userId) {
476 hideEncryptionNotification(new UserHandle(userId));
479 public void onStartUser(final int userId) {
480 maybeShowEncryptionNotificationForUser(userId);
483 public void onUnlockUser(final int userId) {
484 // Perform tasks which require locks in LSS on a handler, as we are callbacks from
485 // ActivityManager.unlockUser()
486 mHandler.post(new Runnable() {
489 // Hide notification first, as tie managed profile lock takes time
490 hideEncryptionNotification(new UserHandle(userId));
492 // Now we have unlocked the parent user we should show notifications
493 // about any profiles that exist.
494 List<UserInfo> profiles = mUserManager.getProfiles(userId);
495 for (int i = 0; i < profiles.size(); i++) {
496 UserInfo profile = profiles.get(i);
497 final boolean isSecure = isUserSecure(profile.id);
498 if (isSecure && profile.isManagedProfile()) {
499 UserHandle userHandle = profile.getUserHandle();
500 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
501 !mUserManager.isQuietModeEnabled(userHandle)) {
502 showEncryptionNotificationForProfile(userHandle);
507 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
508 tieManagedProfileLockIfNecessary(userId, null);
514 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
516 public void onReceive(Context context, Intent intent) {
517 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
518 // Notify keystore that a new user was added.
519 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
520 if (userHandle > UserHandle.USER_SYSTEM) {
521 removeUser(userHandle, /* unknownUser= */ true);
523 final KeyStore ks = KeyStore.getInstance();
524 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
525 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
526 ks.onUserAdded(userHandle, parentHandle);
527 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
528 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
529 mStorage.prefetchUser(userHandle);
530 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
531 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
532 if (userHandle > 0) {
533 removeUser(userHandle, /* unknownUser= */ false);
539 @Override // binder interface
540 public void systemReady() {
543 getGateKeeperService();
544 } catch (RemoteException e) {
545 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
547 // TODO: maybe skip this for split system user mode.
548 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
551 private void migrateOldData() {
553 // These Settings moved before multi-user was enabled, so we only have to do it for the
555 if (getString("migrated", null, 0) == null) {
556 final ContentResolver cr = mContext.getContentResolver();
557 for (String validSetting : VALID_SETTINGS) {
558 String value = Settings.Secure.getString(cr, validSetting);
560 setString(validSetting, value, 0);
563 // No need to move the password / pattern files. They're already in the right place.
564 setString("migrated", "true", 0);
565 Slog.i(TAG, "Migrated lock settings to new location");
568 // These Settings changed after multi-user was enabled, hence need to be moved per user.
569 if (getString("migrated_user_specific", null, 0) == null) {
570 final ContentResolver cr = mContext.getContentResolver();
571 List<UserInfo> users = mUserManager.getUsers();
572 for (int user = 0; user < users.size(); user++) {
573 // Migrate owner info
574 final int userId = users.get(user).id;
575 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
576 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
577 if (!TextUtils.isEmpty(ownerInfo)) {
578 setString(OWNER_INFO, ownerInfo, userId);
579 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
582 // Migrate owner info enabled. Note there was a bug where older platforms only
583 // stored this value if the checkbox was toggled at least once. The code detects
584 // this case by handling the exception.
585 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
588 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
589 enabled = ivalue != 0;
590 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
591 } catch (SettingNotFoundException e) {
592 // Setting was never stored. Store it if the string is not empty.
593 if (!TextUtils.isEmpty(ownerInfo)) {
594 setLong(OWNER_INFO_ENABLED, 1, userId);
597 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
599 // No need to move the password / pattern files. They're already in the right place.
600 setString("migrated_user_specific", "true", 0);
601 Slog.i(TAG, "Migrated per-user lock settings to new location");
604 // Migrates biometric weak such that the fallback mechanism becomes the primary.
605 if (getString("migrated_biometric_weak", null, 0) == null) {
606 List<UserInfo> users = mUserManager.getUsers();
607 for (int i = 0; i < users.size(); i++) {
608 int userId = users.get(i).id;
609 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
610 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
612 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
613 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
615 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
616 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
620 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
621 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
624 setString("migrated_biometric_weak", "true", 0);
625 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
628 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
629 // user was present on the system, so if we're upgrading to M and there is more than one
630 // user we disable the flag to remain consistent.
631 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
632 final List<UserInfo> users = mUserManager.getUsers();
633 final int userCount = users.size();
634 int switchableUsers = 0;
635 for (int i = 0; i < userCount; i++) {
636 if (users.get(i).supportsSwitchTo()) {
641 if (switchableUsers > 1) {
642 for (int i = 0; i < userCount; i++) {
643 int id = users.get(i).id;
645 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
646 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
651 setString("migrated_lockscreen_disabled", "true", 0);
652 Slog.i(TAG, "Migrated lockscreen disabled flag");
655 final List<UserInfo> users = mUserManager.getUsers();
656 for (int i = 0; i < users.size(); i++) {
657 final UserInfo userInfo = users.get(i);
658 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
659 // When managed profile has a unified lock, the password quality stored has 2
660 // possibilities only.
661 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
662 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
663 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
665 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
666 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
667 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
668 // Only possible when it's upgraded from nyc dp3
669 Slog.i(TAG, "Migrated tied profile lock type");
670 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
671 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
672 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
673 // It should not happen
674 Slog.e(TAG, "Invalid tied profile lock type: " + quality);
678 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
679 java.security.KeyStore keyStore =
680 java.security.KeyStore.getInstance("AndroidKeyStore");
682 if (keyStore.containsAlias(alias)) {
683 keyStore.deleteEntry(alias);
685 } catch (KeyStoreException | NoSuchAlgorithmException |
686 CertificateException | IOException e) {
687 Slog.e(TAG, "Unable to remove tied profile key", e);
691 boolean isWatch = mContext.getPackageManager().hasSystemFeature(
692 PackageManager.FEATURE_WATCH);
693 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
694 // and device management the lockscreen must be re-enabled now for users that upgrade.
695 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
696 final int userCount = users.size();
697 for (int i = 0; i < userCount; i++) {
698 int id = users.get(i).id;
699 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
701 setString("migrated_wear_lockscreen_disabled", "true", 0);
702 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
704 } catch (RemoteException re) {
705 Slog.e(TAG, "Unable to migrate old data", re);
709 private final void checkWritePermission(int userId) {
710 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
713 private final void checkPasswordReadPermission(int userId) {
714 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
717 private final void checkReadPermission(String requestedKey, int userId) {
718 final int callingUid = Binder.getCallingUid();
720 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
721 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
722 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
723 != PackageManager.PERMISSION_GRANTED) {
724 throw new SecurityException("uid=" + callingUid
725 + " needs permission " + READ_CONTACTS + " to read "
726 + requestedKey + " for user " + userId);
730 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
731 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
732 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
733 != PackageManager.PERMISSION_GRANTED) {
734 throw new SecurityException("uid=" + callingUid
735 + " needs permission " + PERMISSION + " to read "
736 + requestedKey + " for user " + userId);
742 public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
743 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
744 synchronized (mSeparateChallengeLock) {
745 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
750 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
751 String managedUserPassword) throws RemoteException {
752 checkWritePermission(userId);
753 synchronized (mSeparateChallengeLock) {
754 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
756 mStorage.removeChildProfileLock(userId);
757 removeKeystoreProfileKey(userId);
759 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
765 public void setBoolean(String key, boolean value, int userId) throws RemoteException {
766 checkWritePermission(userId);
767 setStringUnchecked(key, userId, value ? "1" : "0");
771 public void setLong(String key, long value, int userId) throws RemoteException {
772 checkWritePermission(userId);
773 setStringUnchecked(key, userId, Long.toString(value));
777 public void setString(String key, String value, int userId) throws RemoteException {
778 checkWritePermission(userId);
779 setStringUnchecked(key, userId, value);
782 private void setStringUnchecked(String key, int userId, String value) {
783 mStorage.writeKeyValue(key, value, userId);
784 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
785 BackupManager.dataChanged("com.android.providers.settings");
790 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
791 checkReadPermission(key, userId);
792 String value = getStringUnchecked(key, null, userId);
793 return TextUtils.isEmpty(value) ?
794 defaultValue : (value.equals("1") || value.equals("true"));
798 public long getLong(String key, long defaultValue, int userId) throws RemoteException {
799 checkReadPermission(key, userId);
800 String value = getStringUnchecked(key, null, userId);
801 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
805 public String getString(String key, String defaultValue, int userId) throws RemoteException {
806 checkReadPermission(key, userId);
807 return getStringUnchecked(key, defaultValue, userId);
810 public String getStringUnchecked(String key, String defaultValue, int userId) {
811 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
812 long ident = Binder.clearCallingIdentity();
814 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
816 Binder.restoreCallingIdentity(ident);
820 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
821 key = Settings.Secure.LOCK_PATTERN_ENABLED;
824 return mStorage.readKeyValue(key, defaultValue, userId);
828 public boolean havePassword(int userId) throws RemoteException {
829 synchronized (mSpManager) {
830 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
831 long handle = getSyntheticPasswordHandleLocked(userId);
832 return mSpManager.getCredentialType(handle, userId) ==
833 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
836 // Do we need a permissions check here?
837 return mStorage.hasPassword(userId);
841 public boolean havePattern(int userId) throws RemoteException {
842 synchronized (mSpManager) {
843 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
844 long handle = getSyntheticPasswordHandleLocked(userId);
845 return mSpManager.getCredentialType(handle, userId) ==
846 LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
849 // Do we need a permissions check here?
850 return mStorage.hasPattern(userId);
853 private boolean isUserSecure(int userId) {
854 synchronized (mSpManager) {
856 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
857 long handle = getSyntheticPasswordHandleLocked(userId);
858 return mSpManager.getCredentialType(handle, userId) !=
859 LockPatternUtils.CREDENTIAL_TYPE_NONE;
861 } catch (RemoteException e) {
865 return mStorage.hasCredential(userId);
868 private void setKeystorePassword(String password, int userHandle) {
869 final KeyStore ks = KeyStore.getInstance();
870 ks.onUserPasswordChanged(userHandle, password);
873 private void unlockKeystore(String password, int userHandle) {
874 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
875 final KeyStore ks = KeyStore.getInstance();
876 ks.unlock(userHandle, password);
880 protected String getDecryptedPasswordForTiedProfile(int userId)
881 throws KeyStoreException, UnrecoverableKeyException,
882 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
883 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
884 CertificateException, IOException {
885 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
886 byte[] storedData = mStorage.readChildProfileLock(userId);
887 if (storedData == null) {
888 throw new FileNotFoundException("Child profile lock file not found");
890 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
891 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
893 byte[] decryptionResult;
894 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
896 SecretKey decryptionKey = (SecretKey) keyStore.getKey(
897 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
899 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
900 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
902 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
903 decryptionResult = cipher.doFinal(encryptedPassword);
904 return new String(decryptionResult, StandardCharsets.UTF_8);
907 private void unlockChildProfile(int profileHandle) throws RemoteException {
909 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
910 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
911 false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
912 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
913 | NoSuchAlgorithmException | NoSuchPaddingException
914 | InvalidAlgorithmParameterException | IllegalBlockSizeException
915 | BadPaddingException | CertificateException | IOException e) {
916 if (e instanceof FileNotFoundException) {
917 Slog.i(TAG, "Child profile key not found");
919 Slog.e(TAG, "Failed to decrypt child profile key", e);
924 private void unlockUser(int userId, byte[] token, byte[] secret) {
925 // TODO: make this method fully async so we can update UI with progress strings
926 final CountDownLatch latch = new CountDownLatch(1);
927 final IProgressListener listener = new IProgressListener.Stub() {
929 public void onStarted(int id, Bundle extras) throws RemoteException {
930 Log.d(TAG, "unlockUser started");
934 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
935 Log.d(TAG, "unlockUser progress " + progress);
939 public void onFinished(int id, Bundle extras) throws RemoteException {
940 Log.d(TAG, "unlockUser finished");
946 mActivityManager.unlockUser(userId, token, secret, listener);
947 } catch (RemoteException e) {
948 throw e.rethrowAsRuntimeException();
952 latch.await(15, TimeUnit.SECONDS);
953 } catch (InterruptedException e) {
954 Thread.currentThread().interrupt();
957 if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
958 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
959 for (UserInfo pi : profiles) {
960 // Unlock managed profile with unified lock
961 if (pi.isManagedProfile()
962 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
963 && mStorage.hasChildProfileLock(pi.id)
964 && mUserManager.isUserRunning(pi.id)
965 && !mUserManager.isUserUnlocked(pi.id)) {
966 unlockChildProfile(pi.id);
970 } catch (RemoteException e) {
971 Log.d(TAG, "Failed to unlock child profile", e);
975 private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
976 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
979 Map<Integer, String> result = new ArrayMap<Integer, String>();
980 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
981 final int size = profiles.size();
982 for (int i = 0; i < size; i++) {
983 final UserInfo profile = profiles.get(i);
984 if (!profile.isManagedProfile()) {
987 final int managedUserId = profile.id;
988 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
992 result.put(userId, getDecryptedPasswordForTiedProfile(userId));
993 } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
994 | NoSuchPaddingException | InvalidKeyException
995 | InvalidAlgorithmParameterException | IllegalBlockSizeException
996 | BadPaddingException | CertificateException | IOException e) {
1004 * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1005 * depending on the parent user's secure state.
1007 * When clearing tied work challenges, a pre-computed password table for profiles are required,
1008 * since changing password for profiles requires existing password, and existing passwords can
1009 * only be computed before the parent user's password is cleared.
1011 * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1012 * method again on profiles. However the recursion is guaranteed to terminate as this method
1013 * terminates when the user is a managed profile.
1015 private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1016 Map<Integer, String> profilePasswordMap) throws RemoteException {
1017 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1020 final boolean isSecure = isUserSecure(userId);
1021 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1022 final int size = profiles.size();
1023 for (int i = 0; i < size; i++) {
1024 final UserInfo profile = profiles.get(i);
1025 if (profile.isManagedProfile()) {
1026 final int managedUserId = profile.id;
1027 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1031 tieManagedProfileLockIfNecessary(managedUserId, null);
1033 // We use cached work profile password computed before clearing the parent's
1034 // credential, otherwise they get lost
1035 if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
1036 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
1037 profilePasswordMap.get(managedUserId), managedUserId);
1039 Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
1040 // Supplying null here would lead to untrusted credential change
1041 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
1044 mStorage.removeChildProfileLock(managedUserId);
1045 removeKeystoreProfileKey(managedUserId);
1051 private boolean isManagedProfileWithUnifiedLock(int userId) {
1052 return mUserManager.getUserInfo(userId).isManagedProfile()
1053 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1056 private boolean isManagedProfileWithSeparatedLock(int userId) {
1057 return mUserManager.getUserInfo(userId).isManagedProfile()
1058 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1061 // This method should be called by LockPatternUtil only, all internal methods in this class
1062 // should call setLockCredentialInternal.
1064 public void setLockCredential(String credential, int type, String savedCredential, int userId)
1065 throws RemoteException {
1066 checkWritePermission(userId);
1067 synchronized (mSeparateChallengeLock) {
1068 setLockCredentialInternal(credential, type, savedCredential, userId);
1069 setSeparateProfileChallengeEnabled(userId, true, null);
1070 notifyPasswordChanged(userId);
1074 private void setLockCredentialInternal(String credential, int credentialType,
1075 String savedCredential, int userId) throws RemoteException {
1076 // Normalize savedCredential and credential such that empty string is always represented
1078 if (TextUtils.isEmpty(savedCredential)) {
1079 savedCredential = null;
1081 if (TextUtils.isEmpty(credential)) {
1084 synchronized (mSpManager) {
1085 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1086 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
1091 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1092 if (credential != null) {
1093 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
1095 clearUserKeyProtection(userId);
1096 getGateKeeperService().clearSecureUserId(userId);
1097 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
1098 setKeystorePassword(null, userId);
1099 fixateNewestUserKeyAuth(userId);
1100 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1101 notifyActivePasswordMetricsAvailable(null, userId);
1104 if (credential == null) {
1105 throw new RemoteException("Null credential with mismatched credential type");
1108 CredentialHash currentHandle = mStorage.readCredentialHash(userId);
1109 if (isManagedProfileWithUnifiedLock(userId)) {
1110 // get credential from keystore when managed profile has unified lock
1111 if (savedCredential == null) {
1113 savedCredential = getDecryptedPasswordForTiedProfile(userId);
1114 } catch (FileNotFoundException e) {
1115 Slog.i(TAG, "Child profile key not found");
1116 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1117 | NoSuchAlgorithmException | NoSuchPaddingException
1118 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1119 | BadPaddingException | CertificateException | IOException e) {
1120 Slog.e(TAG, "Failed to decrypt child profile key", e);
1124 if (currentHandle.hash == null) {
1125 if (savedCredential != null) {
1126 Slog.w(TAG, "Saved credential provided, but none stored");
1128 savedCredential = null;
1131 synchronized (mSpManager) {
1132 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1133 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
1134 currentHandle.type, userId);
1135 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
1140 if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
1141 byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
1143 if (enrolledHandle != null) {
1144 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
1145 mStorage.writeCredentialHash(willStore, userId);
1146 // push new secret and auth token to vold
1147 GateKeeperResponse gkResponse = getGateKeeperService()
1148 .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
1149 setUserKeyProtection(userId, credential, convertResponse(gkResponse));
1150 fixateNewestUserKeyAuth(userId);
1151 // Refresh the auth token
1152 doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
1153 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1155 throw new RemoteException("Failed to enroll " +
1156 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
1161 private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
1162 VerifyCredentialResponse response;
1163 int responseCode = gateKeeperResponse.getResponseCode();
1164 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1165 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
1166 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1167 byte[] token = gateKeeperResponse.getPayload();
1168 if (token == null) {
1169 // something's wrong if there's no payload with a challenge
1170 Slog.e(TAG, "verifyChallenge response had no associated payload");
1171 response = VerifyCredentialResponse.ERROR;
1173 response = new VerifyCredentialResponse(token);
1176 response = VerifyCredentialResponse.ERROR;
1182 protected void tieProfileLockToParent(int userId, String password) {
1183 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1184 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1185 byte[] encryptionResult;
1188 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1189 keyGenerator.init(new SecureRandom());
1190 SecretKey secretKey = keyGenerator.generateKey();
1191 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1192 keyStore.load(null);
1195 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1196 new java.security.KeyStore.SecretKeyEntry(secretKey),
1197 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1198 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1199 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1202 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1203 new java.security.KeyStore.SecretKeyEntry(secretKey),
1204 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1205 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1206 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1207 .setUserAuthenticationRequired(true)
1208 .setUserAuthenticationValidityDurationSeconds(30)
1210 // Key imported, obtain a reference to it.
1211 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1212 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1213 Cipher cipher = Cipher.getInstance(
1214 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1215 + KeyProperties.ENCRYPTION_PADDING_NONE);
1216 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1217 encryptionResult = cipher.doFinal(randomLockSeed);
1218 iv = cipher.getIV();
1220 // The original key can now be discarded.
1221 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1223 } catch (CertificateException | UnrecoverableKeyException
1224 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
1225 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1226 throw new RuntimeException("Failed to encrypt key", e);
1228 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1230 if (iv.length != PROFILE_KEY_IV_SIZE) {
1231 throw new RuntimeException("Invalid iv length: " + iv.length);
1233 outputStream.write(iv);
1234 outputStream.write(encryptionResult);
1235 } catch (IOException e) {
1236 throw new RuntimeException("Failed to concatenate byte arrays", e);
1238 mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1241 private byte[] enrollCredential(byte[] enrolledHandle,
1242 String enrolledCredential, String toEnroll, int userId)
1243 throws RemoteException {
1244 checkWritePermission(userId);
1245 byte[] enrolledCredentialBytes = enrolledCredential == null
1247 : enrolledCredential.getBytes();
1248 byte[] toEnrollBytes = toEnroll == null
1250 : toEnroll.getBytes();
1251 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1252 enrolledCredentialBytes, toEnrollBytes);
1254 if (response == null) {
1258 byte[] hash = response.getPayload();
1260 setKeystorePassword(toEnroll, userId);
1262 // Should not happen
1263 Slog.e(TAG, "Throttled while enrolling a password");
1268 private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
1269 if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1270 addUserKeyAuth(userId, null, key);
1273 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1274 throws RemoteException {
1275 if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
1277 throw new RemoteException("Null response verifying a credential we just set");
1279 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1280 throw new RemoteException("Non-OK response verifying a credential we just set: "
1281 + vcr.getResponseCode());
1283 byte[] token = vcr.getPayload();
1284 if (token == null) {
1285 throw new RemoteException("Empty payload verifying a credential we just set");
1287 addUserKeyAuth(userId, token, secretFromCredential(credential));
1290 private void clearUserKeyProtection(int userId) throws RemoteException {
1291 if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
1292 addUserKeyAuth(userId, null, null);
1295 private static byte[] secretFromCredential(String credential) throws RemoteException {
1297 MessageDigest digest = MessageDigest.getInstance("SHA-512");
1298 // Personalize the hash
1299 byte[] personalization = "Android FBE credential hash"
1300 .getBytes(StandardCharsets.UTF_8);
1301 // Pad it to the block size of the hash function
1302 personalization = Arrays.copyOf(personalization, 128);
1303 digest.update(personalization);
1304 digest.update(credential.getBytes(StandardCharsets.UTF_8));
1305 return digest.digest();
1306 } catch (NoSuchAlgorithmException e) {
1307 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1311 private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
1312 throws RemoteException {
1313 final UserInfo userInfo = mUserManager.getUserInfo(userId);
1314 final IStorageManager storageManager = mInjector.getStorageManager();
1315 final long callingId = Binder.clearCallingIdentity();
1317 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
1319 Binder.restoreCallingIdentity(callingId);
1323 private void fixateNewestUserKeyAuth(int userId)
1324 throws RemoteException {
1325 if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
1326 final IStorageManager storageManager = mInjector.getStorageManager();
1327 final long callingId = Binder.clearCallingIdentity();
1329 storageManager.fixateNewestUserKeyAuth(userId);
1331 Binder.restoreCallingIdentity(callingId);
1336 public void resetKeyStore(int userId) throws RemoteException {
1337 checkWritePermission(userId);
1338 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1339 int managedUserId = -1;
1340 String managedUserDecryptedPassword = null;
1341 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1342 for (UserInfo pi : profiles) {
1343 // Unlock managed profile with unified lock
1344 if (pi.isManagedProfile()
1345 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1346 && mStorage.hasChildProfileLock(pi.id)) {
1348 if (managedUserId == -1) {
1349 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1350 managedUserId = pi.id;
1352 // Should not happen
1353 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1354 + ", uid2:" + pi.id);
1356 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1357 | NoSuchAlgorithmException | NoSuchPaddingException
1358 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1359 | BadPaddingException | CertificateException | IOException e) {
1360 Slog.e(TAG, "Failed to decrypt child profile key", e);
1365 // Clear all the users credentials could have been installed in for this user.
1366 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1367 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1368 mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1372 if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1373 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
1374 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
1380 public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
1381 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1382 checkPasswordReadPermission(userId);
1383 return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
1387 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
1388 int userId) throws RemoteException {
1389 checkPasswordReadPermission(userId);
1390 return doVerifyCredential(credential, type, true, challenge, userId,
1391 null /* progressCallback */);
1395 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
1398 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
1399 boolean hasChallenge, long challenge, int userId,
1400 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1401 if (TextUtils.isEmpty(credential)) {
1402 throw new IllegalArgumentException("Credential can't be null or empty");
1404 synchronized (mSpManager) {
1405 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1406 VerifyCredentialResponse response = spBasedDoVerifyCredentialLocked(credential,
1407 credentialType, hasChallenge, challenge, userId, progressCallback);
1408 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1409 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1414 CredentialHash storedHash = mStorage.readCredentialHash(userId);
1415 if (storedHash.type != credentialType) {
1416 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
1417 + " stored: " + storedHash.type + " passed in: " + credentialType);
1418 return VerifyCredentialResponse.ERROR;
1421 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1422 && storedHash.isBaseZeroPattern;
1424 String credentialToVerify;
1425 if (shouldReEnrollBaseZero) {
1426 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
1428 credentialToVerify = credential;
1431 VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify,
1432 hasChallenge, challenge, progressCallback);
1434 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1435 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1436 if (shouldReEnrollBaseZero) {
1437 setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
1445 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
1446 long challenge, int userId) throws RemoteException {
1447 checkPasswordReadPermission(userId);
1448 if (!isManagedProfileWithUnifiedLock(userId)) {
1449 throw new RemoteException("User id must be managed profile with unified lock");
1451 final int parentProfileId = mUserManager.getProfileParent(userId).id;
1452 // Unlock parent by using parent's challenge
1453 final VerifyCredentialResponse parentResponse = doVerifyCredential(
1456 true /* hasChallenge */,
1459 null /* progressCallback */);
1460 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1461 // Failed, just return parent's response
1462 return parentResponse;
1466 // Unlock work profile, and work profile with unified lock must use password only
1467 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
1468 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1471 userId, null /* progressCallback */);
1472 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1473 | NoSuchAlgorithmException | NoSuchPaddingException
1474 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1475 | BadPaddingException | CertificateException | IOException e) {
1476 Slog.e(TAG, "Failed to decrypt child profile key", e);
1477 throw new RemoteException("Unable to get tied profile token");
1482 * Lowest-level credential verification routine that talks to GateKeeper. If verification
1483 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
1486 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
1487 String credential, boolean hasChallenge, long challenge,
1488 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1489 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1490 // don't need to pass empty credentials to GateKeeper
1491 return VerifyCredentialResponse.OK;
1494 if (storedHash == null || TextUtils.isEmpty(credential)) {
1495 return VerifyCredentialResponse.ERROR;
1498 // We're potentially going to be doing a bunch of disk I/O below as part
1499 // of unlocking the user, so yell if calling from the main thread.
1500 StrictMode.noteDiskRead();
1502 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
1504 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1505 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
1507 hash = mLockPatternUtils.passwordToHash(credential, userId);
1509 if (Arrays.equals(hash, storedHash.hash)) {
1510 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1511 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
1513 unlockKeystore(credential, userId);
1515 // Users with legacy credentials don't have credential-backed
1516 // FBE keys, so just pass through a fake token/secret
1517 Slog.i(TAG, "Unlocking user with fake token: " + userId);
1518 final byte[] fakeToken = String.valueOf(userId).getBytes();
1519 unlockUser(userId, fakeToken, fakeToken);
1521 // migrate credential to GateKeeper
1522 setLockCredentialInternal(credential, storedHash.type, null, userId);
1523 if (!hasChallenge) {
1524 notifyActivePasswordMetricsAvailable(credential, userId);
1525 return VerifyCredentialResponse.OK;
1527 // Fall through to get the auth token. Technically this should never happen,
1528 // as a user that had a legacy credential would have to unlock their device
1529 // before getting to a flow with a challenge, but supporting for consistency.
1531 return VerifyCredentialResponse.ERROR;
1534 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1535 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
1536 VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
1537 boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
1539 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1541 // credential has matched
1543 if (progressCallback != null) {
1544 progressCallback.onCredentialVerified();
1546 notifyActivePasswordMetricsAvailable(credential, userId);
1547 unlockKeystore(credential, userId);
1549 Slog.i(TAG, "Unlocking user " + userId + " with token length "
1550 + response.getPayload().length);
1551 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
1553 if (isManagedProfileWithSeparatedLock(userId)) {
1554 TrustManager trustManager =
1555 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1556 trustManager.setDeviceLockedForUser(userId, false);
1558 if (shouldReEnroll) {
1559 setLockCredentialInternal(credential, storedHash.type, credential, userId);
1561 // Now that we've cleared of all required GK migration, let's do the final
1562 // migration to synthetic password.
1563 synchronized (mSpManager) {
1564 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1565 initializeSyntheticPasswordLocked(storedHash.hash, credential,
1566 storedHash.type, userId);
1570 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1571 if (response.getTimeout() > 0) {
1572 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1579 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
1580 final PasswordMetrics metrics;
1581 if (password == null) {
1582 metrics = new PasswordMetrics();
1584 metrics = PasswordMetrics.computeForPassword(password);
1585 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
1588 // Asynchronous to avoid dead lock
1589 mHandler.post(() -> {
1590 DevicePolicyManager dpm = (DevicePolicyManager)
1591 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1592 dpm.setActivePasswordState(metrics, userId);
1597 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
1598 * reporting the password changed.
1600 private void notifyPasswordChanged(@UserIdInt int userId) {
1601 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
1602 mHandler.post(() -> {
1603 DevicePolicyManager dpm = (DevicePolicyManager)
1604 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1605 dpm.reportPasswordChanged(userId);
1610 public boolean checkVoldPassword(int userId) throws RemoteException {
1611 if (!mFirstCallToVold) {
1614 mFirstCallToVold = false;
1616 checkPasswordReadPermission(userId);
1618 // There's no guarantee that this will safely connect, but if it fails
1619 // we will simply show the lock screen when we shouldn't, so relatively
1620 // benign. There is an outside chance something nasty would happen if
1621 // this service restarted before vold stales out the password in this
1622 // case. The nastiness is limited to not showing the lock screen when
1623 // we should, within the first minute of decrypting the phone if this
1624 // service can't connect to vold, it restarts, and then the new instance
1625 // does successfully connect.
1626 final IStorageManager service = mInjector.getStorageManager();
1628 long identity = Binder.clearCallingIdentity();
1630 password = service.getPassword();
1631 service.clearPassword();
1633 Binder.restoreCallingIdentity(identity);
1635 if (password == null) {
1640 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
1641 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
1642 null /* progressCallback */)
1643 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1647 } catch (Exception e) {
1651 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
1652 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
1653 null /* progressCallback */)
1654 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1658 } catch (Exception e) {
1664 private void removeUser(int userId, boolean unknownUser) {
1665 mStorage.removeUser(userId);
1666 mStrongAuth.removeUser(userId);
1668 final KeyStore ks = KeyStore.getInstance();
1669 ks.onUserRemoved(userId);
1672 final IGateKeeperService gk = getGateKeeperService();
1674 gk.clearSecureUserId(userId);
1676 } catch (RemoteException ex) {
1677 Slog.w(TAG, "unable to clear GK secure user id");
1679 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
1680 removeKeystoreProfileKey(userId);
1684 private void removeKeystoreProfileKey(int targetUserId) {
1685 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1687 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1688 keyStore.load(null);
1689 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1690 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
1691 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1693 // We have tried our best to remove all keys
1694 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1699 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1700 checkPasswordReadPermission(UserHandle.USER_ALL);
1701 mStrongAuth.registerStrongAuthTracker(tracker);
1705 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1706 checkPasswordReadPermission(UserHandle.USER_ALL);
1707 mStrongAuth.unregisterStrongAuthTracker(tracker);
1711 public void requireStrongAuth(int strongAuthReason, int userId) {
1712 checkWritePermission(userId);
1713 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1717 public void userPresent(int userId) {
1718 checkWritePermission(userId);
1719 mStrongAuth.reportUnlock(userId);
1723 public int getStrongAuthForUser(int userId) {
1724 checkPasswordReadPermission(userId);
1725 return mStrongAuthTracker.getStrongAuthForUser(userId);
1728 private boolean isCallerShell() {
1729 final int callingUid = Binder.getCallingUid();
1730 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1733 private void enforceShell() {
1734 if (!isCallerShell()) {
1735 throw new SecurityException("Caller must be shell");
1740 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1741 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1742 throws RemoteException {
1744 final long origId = Binder.clearCallingIdentity();
1746 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
1747 this, in, out, err, args, callback, resultReceiver);
1749 Binder.restoreCallingIdentity(origId);
1753 private static final String[] VALID_SETTINGS = new String[] {
1754 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
1755 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
1756 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
1757 LockPatternUtils.PASSWORD_TYPE_KEY,
1758 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
1759 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1760 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
1761 LockPatternUtils.LOCKSCREEN_OPTIONS,
1762 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
1763 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
1764 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
1765 LockPatternUtils.PASSWORD_HISTORY_KEY,
1766 Secure.LOCK_PATTERN_ENABLED,
1767 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
1768 Secure.LOCK_PATTERN_VISIBLE,
1769 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
1772 // Reading these settings needs the contacts permission
1773 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
1774 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1775 Secure.LOCK_SCREEN_OWNER_INFO
1778 // Reading these settings needs the same permission as checking the password
1779 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
1780 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1781 LockPatternUtils.PASSWORD_HISTORY_KEY,
1782 LockPatternUtils.PASSWORD_TYPE_KEY,
1783 SEPARATE_PROFILE_CHALLENGE_KEY
1786 private static final String[] SETTINGS_TO_BACKUP = new String[] {
1787 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1788 Secure.LOCK_SCREEN_OWNER_INFO
1791 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
1793 public void binderDied() {
1794 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
1795 mGateKeeperService = null;
1799 protected synchronized IGateKeeperService getGateKeeperService()
1800 throws RemoteException {
1801 if (mGateKeeperService != null) {
1802 return mGateKeeperService;
1805 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
1806 if (service != null) {
1807 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
1808 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
1809 return mGateKeeperService;
1812 Slog.e(TAG, "Unable to acquire GateKeeperService");
1817 * Precondition: vold and keystore unlocked.
1819 * Create new synthetic password, set up synthetic password blob protected by the supplied
1820 * user credential, and make the newly-created SP blob active.
1822 * The invariant under a synthetic password is:
1823 * 1. If user credential exists, then both vold and keystore and protected with keys derived
1824 * from the synthetic password.
1825 * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
1826 * make it consistent with current behaviour. It also allows ActivityManager to call
1827 * unlockUser() with empty secret.
1828 * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
1829 * whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
1830 * lockscreen PIN, we still maintain the existing synthetic password in a password blob
1831 * protected by a default PIN. The only exception is when the DPC performs an untrusted
1832 * credential change, in which case we have no way to derive the existing synthetic password
1833 * and has to create a new one.
1834 * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
1835 * clears/re-creates his lockscreen PIN.
1838 * Different cases of calling this method:
1839 * 1. credentialHash != null
1840 * This implies credential != null, a new SP blob will be provisioned, and existing SID
1841 * migrated to associate with the new SP.
1842 * This happens during a normal migration case when the user currently has password.
1844 * 2. credentialhash == null and credential == null
1845 * A new SP blob and a new SID will be created, while the user has no credentials.
1846 * This can happens when we are activating an escrow token on a unsecured device, during
1847 * which we want to create the SP structure with an empty user credential.
1849 * 3. credentialhash == null and credential != null
1850 * This is the untrusted credential reset, OR the user sets a new lockscreen password
1851 * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
1853 private AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
1854 String credential, int credentialType, int userId) throws RemoteException {
1855 Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
1856 AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(getGateKeeperService(),
1857 credentialHash, credential, userId);
1859 Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
1862 long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
1863 credential, credentialType, auth, userId);
1864 if (credential != null) {
1865 if (credentialHash == null) {
1866 // Since when initializing SP, we didn't provide an existing password handle
1867 // for it to migrate SID, we need to create a new SID for the user.
1868 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
1870 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1871 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
1872 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
1874 clearUserKeyProtection(userId);
1875 setKeystorePassword(null, userId);
1876 getGateKeeperService().clearSecureUserId(userId);
1878 fixateNewestUserKeyAuth(userId);
1879 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
1883 private long getSyntheticPasswordHandleLocked(int userId) {
1885 return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId);
1886 } catch (RemoteException e) {
1887 return SyntheticPasswordManager.DEFAULT_HANDLE;
1891 private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
1892 long handle = getSyntheticPasswordHandleLocked(userId);
1893 // This is a global setting
1894 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
1895 return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
1898 private boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
1899 long handle = getSyntheticPasswordHandleLocked(userId);
1900 // This is a global setting
1901 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
1902 return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
1905 private void enableSyntheticPasswordLocked() throws RemoteException {
1906 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
1909 private VerifyCredentialResponse spBasedDoVerifyCredentialLocked(String userCredential, int
1910 credentialType, boolean hasChallenge, long challenge, int userId,
1911 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1912 if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredentialLocked: user=" + userId);
1913 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1914 userCredential = null;
1916 long handle = getSyntheticPasswordHandleLocked(userId);
1917 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
1918 getGateKeeperService(), handle, userCredential, userId);
1920 VerifyCredentialResponse response = authResult.gkResponse;
1921 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1922 // credential has matched
1923 // perform verifyChallenge with synthetic password which generates the real auth
1924 // token for the current user
1925 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
1927 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1928 Slog.wtf(TAG, "verifyChallenge with SP failed.");
1929 return VerifyCredentialResponse.ERROR;
1931 if (progressCallback != null) {
1932 progressCallback.onCredentialVerified();
1934 notifyActivePasswordMetricsAvailable(userCredential, userId);
1935 unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
1937 final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
1938 Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
1939 unlockUser(userId, null, secret);
1941 if (isManagedProfileWithSeparatedLock(userId)) {
1942 TrustManager trustManager =
1943 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1944 trustManager.setDeviceLockedForUser(userId, false);
1946 activateEscrowTokens(authResult.authToken, userId);
1947 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1948 if (response.getTimeout() > 0) {
1949 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1957 * Change the user's lockscreen password by creating a new SP blob and update the handle, based
1958 * on an existing authentication token. Even though a new SP blob is created, the underlying
1959 * synthetic password is never changed.
1961 * When clearing credential, we keep the SP unchanged, but clear its password handle so its
1962 * SID is gone. We also clear password from (software-based) keystore and vold, which will be
1963 * added back when new password is set in future.
1965 private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
1966 AuthenticationToken auth, int userId) throws RemoteException {
1967 if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
1968 long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
1969 credential, credentialType, auth, userId);
1970 final Map<Integer, String> profilePasswords;
1971 if (credential != null) {
1972 // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
1973 profilePasswords = null;
1975 if (mSpManager.hasSidForUser(userId)) {
1976 // We are changing password of a secured device, nothing more needed as
1977 // createPasswordBasedSyntheticPassword has already taken care of maintaining
1978 // the password handle and SID unchanged.
1980 //refresh auth token
1981 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1983 // A new password is set on a previously-unsecured device, we need to generate
1984 // a new SID, and re-add keys to vold and keystore.
1985 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
1986 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1987 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
1988 fixateNewestUserKeyAuth(userId);
1989 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
1992 // Cache all profile password if they use unified work challenge. This will later be
1993 // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
1994 profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
1996 // we are clearing password of a secured device, so need to nuke SID as well.
1997 mSpManager.clearSidForUser(userId);
1998 getGateKeeperService().clearSecureUserId(userId);
1999 // Clear key from vold so ActivityManager can just unlock the user with empty secret
2001 clearUserKeyProtection(userId);
2002 fixateNewestUserKeyAuth(userId);
2003 setKeystorePassword(null, userId);
2005 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
2006 synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
2010 private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
2011 String savedCredential, int userId) throws RemoteException {
2012 if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2013 if (isManagedProfileWithUnifiedLock(userId)) {
2014 // get credential from keystore when managed profile has unified lock
2016 savedCredential = getDecryptedPasswordForTiedProfile(userId);
2017 } catch (FileNotFoundException e) {
2018 Slog.i(TAG, "Child profile key not found");
2019 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2020 | NoSuchAlgorithmException | NoSuchPaddingException
2021 | InvalidAlgorithmParameterException | IllegalBlockSizeException
2022 | BadPaddingException | CertificateException | IOException e) {
2023 Slog.e(TAG, "Failed to decrypt child profile key", e);
2026 long handle = getSyntheticPasswordHandleLocked(userId);
2027 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
2028 getGateKeeperService(), handle, savedCredential, userId);
2029 VerifyCredentialResponse response = authResult.gkResponse;
2030 AuthenticationToken auth = authResult.authToken;
2032 // We are performing a trusted credential change i.e. a correct existing credential
2034 setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId);
2035 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2036 } else if (response != null
2037 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){
2038 // We are performing an untrusted credential change i.e. by DevicePolicyManager.
2039 // So provision a new SP and SID. This would invalidate existing escrow tokens.
2040 // Still support this for now but this flow will be removed in the next release.
2042 Slog.w(TAG, "Untrusted credential change invoked");
2043 initializeSyntheticPasswordLocked(null, credential, credentialType, userId);
2044 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
2045 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2046 } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
2047 Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
2048 (response != null ? "rate limit exceeded" : "failed"));
2051 notifyActivePasswordMetricsAvailable(credential, userId);
2056 public long addEscrowToken(byte[] token, int userId) throws RemoteException {
2057 ensureCallerSystemUid();
2058 if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
2059 synchronized (mSpManager) {
2060 enableSyntheticPasswordLocked();
2061 // Migrate to synthetic password based credentials if the user has no password,
2062 // the token can then be activated immediately.
2063 AuthenticationToken auth = null;
2064 if (!isUserSecure(userId)) {
2065 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2066 auth = initializeSyntheticPasswordLocked(null, null,
2067 LockPatternUtils.CREDENTIAL_TYPE_NONE, userId);
2068 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
2069 long pwdHandle = getSyntheticPasswordHandleLocked(userId);
2070 auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
2071 pwdHandle, null, userId).authToken;
2074 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2075 if (!mSpManager.hasEscrowData(userId)) {
2076 throw new SecurityException("Escrow token is disabled on the current user");
2078 long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
2080 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2086 private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
2087 if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
2088 synchronized (mSpManager) {
2089 for (long handle : mSpManager.getPendingTokensForUser(userId)) {
2090 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
2091 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2097 public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
2098 ensureCallerSystemUid();
2099 synchronized (mSpManager) {
2100 return mSpManager.existsHandle(handle, userId);
2105 public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
2106 ensureCallerSystemUid();
2107 synchronized (mSpManager) {
2108 if (handle == getSyntheticPasswordHandleLocked(userId)) {
2109 Slog.w(TAG, "Cannot remove password handle");
2112 if (mSpManager.removePendingToken(handle, userId)) {
2115 if (mSpManager.existsHandle(handle, userId)) {
2116 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
2125 public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
2126 byte[] token, int userId) throws RemoteException {
2127 ensureCallerSystemUid();
2129 synchronized (mSpManager) {
2130 if (!mSpManager.hasEscrowData(userId)) {
2131 throw new SecurityException("Escrow token is disabled on the current user");
2133 result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
2137 synchronized (mSeparateChallengeLock) {
2138 setSeparateProfileChallengeEnabled(userId, true, null);
2140 notifyPasswordChanged(userId);
2145 private boolean setLockCredentialWithTokenInternal(String credential, int type,
2146 long tokenHandle, byte[] token, int userId) throws RemoteException {
2147 synchronized (mSpManager) {
2148 AuthenticationResult result = mSpManager.unwrapTokenBasedSyntheticPassword(
2149 getGateKeeperService(), tokenHandle, token, userId);
2150 if (result.authToken == null) {
2151 Slog.w(TAG, "Invalid escrow token supplied");
2154 long oldHandle = getSyntheticPasswordHandleLocked(userId);
2155 setLockCredentialWithAuthTokenLocked(credential, type, result.authToken, userId);
2156 mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
2162 public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
2163 throws RemoteException {
2164 ensureCallerSystemUid();
2165 AuthenticationResult authResult;
2166 synchronized (mSpManager) {
2167 if (!mSpManager.hasEscrowData(userId)) {
2168 throw new SecurityException("Escrow token is disabled on the current user");
2170 authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
2171 tokenHandle, token, userId);
2172 if (authResult.authToken == null) {
2173 Slog.w(TAG, "Invalid escrow token supplied");
2177 unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
2181 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
2182 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
2184 synchronized (this) {
2185 pw.println("Current lock settings service state:");
2186 pw.println(String.format("SP Enabled = %b",
2187 mLockPatternUtils.isSyntheticPasswordEnabled()));
2189 List<UserInfo> users = mUserManager.getUsers();
2190 for (int user = 0; user < users.size(); user++) {
2191 final int userId = users.get(user).id;
2192 pw.println(" User " + userId);
2193 pw.println(String.format(" SP Handle = %x",
2194 getSyntheticPasswordHandleLocked(userId)));
2196 pw.println(String.format(" SID = %x",
2197 getGateKeeperService().getSecureUserId(userId)));
2198 } catch (RemoteException e) {
2205 private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
2206 long ident = Binder.clearCallingIdentity();
2208 // Managed profile should have escrow enabled
2209 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
2210 Slog.i(TAG, "Managed profile can have escrow token");
2213 DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
2214 // Devices with Device Owner should have escrow enabled on all users.
2215 if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
2216 Slog.i(TAG, "Corp-owned device can have escrow token");
2219 // We could also have a profile owner on the given (non-managed) user for unicorn cases
2220 if (dpm.getProfileOwnerAsUser(userId) != null) {
2221 Slog.i(TAG, "User with profile owner can have escrow token");
2224 // If the device is yet to be provisioned (still in SUW), there is still
2225 // a chance that Device Owner will be set on the device later, so postpone
2226 // disabling escrow token for now.
2227 if (!dpm.isDeviceProvisioned()) {
2228 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
2232 // Escrow tokens are enabled on automotive builds.
2233 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
2237 // Disable escrow token permanently on all other device/user types.
2238 Slog.i(TAG, "Disabling escrow token on user " + userId);
2239 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2240 mSpManager.destroyEscrowData(userId);
2242 } catch (RemoteException e) {
2243 Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
2245 Binder.restoreCallingIdentity(ident);
2249 private void ensureCallerSystemUid() throws SecurityException {
2250 final int callingUid = mInjector.binderGetCallingUid();
2251 if (callingUid != Process.SYSTEM_UID) {
2252 throw new SecurityException("Only system can call this API.");