LockSettingsService.java revision 8fc2ec832f765a51c8fcd04cc89428a3ced4b605
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.locksettings; 18 19import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE; 20import static android.Manifest.permission.READ_CONTACTS; 21import static android.content.Context.KEYGUARD_SERVICE; 22import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; 23import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY; 24import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; 25 26import android.annotation.UserIdInt; 27import android.app.ActivityManager; 28import android.app.IActivityManager; 29import android.app.KeyguardManager; 30import android.app.Notification; 31import android.app.NotificationManager; 32import android.app.PendingIntent; 33import android.app.admin.DevicePolicyManager; 34import android.app.admin.PasswordMetrics; 35import android.app.backup.BackupManager; 36import android.app.trust.IStrongAuthTracker; 37import android.app.trust.TrustManager; 38import android.content.BroadcastReceiver; 39import android.content.ContentResolver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.content.pm.UserInfo; 45import android.content.res.Resources; 46import android.database.sqlite.SQLiteDatabase; 47import android.os.Binder; 48import android.os.Bundle; 49import android.os.Handler; 50import android.os.IBinder; 51import android.os.IProgressListener; 52import android.os.Process; 53import android.os.RemoteException; 54import android.os.ResultReceiver; 55import android.os.ServiceManager; 56import android.os.ShellCallback; 57import android.os.StrictMode; 58import android.os.SystemProperties; 59import android.os.UserHandle; 60import android.os.UserManager; 61import android.os.storage.IStorageManager; 62import android.os.storage.StorageManager; 63import android.provider.Settings; 64import android.provider.Settings.Secure; 65import android.provider.Settings.SettingNotFoundException; 66import android.security.GateKeeper; 67import android.security.KeyStore; 68import android.security.keystore.AndroidKeyStoreProvider; 69import android.security.keystore.KeyProperties; 70import android.security.keystore.KeyProtection; 71import android.service.gatekeeper.GateKeeperResponse; 72import android.service.gatekeeper.IGateKeeperService; 73import android.text.TextUtils; 74import android.util.ArrayMap; 75import android.util.Log; 76import android.util.Slog; 77 78import com.android.internal.annotations.VisibleForTesting; 79import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 80import com.android.internal.notification.SystemNotificationChannels; 81import com.android.internal.util.ArrayUtils; 82import com.android.internal.util.DumpUtils; 83import com.android.internal.widget.ICheckCredentialProgressCallback; 84import com.android.internal.widget.ILockSettings; 85import com.android.internal.widget.LockPatternUtils; 86import com.android.internal.widget.VerifyCredentialResponse; 87import com.android.server.SystemService; 88import com.android.server.locksettings.LockSettingsStorage.CredentialHash; 89import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; 90import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken; 91 92import libcore.util.HexEncoding; 93 94import java.io.ByteArrayOutputStream; 95import java.io.FileDescriptor; 96import java.io.FileNotFoundException; 97import java.io.IOException; 98import java.io.PrintWriter; 99import java.nio.charset.StandardCharsets; 100import java.security.InvalidAlgorithmParameterException; 101import java.security.InvalidKeyException; 102import java.security.KeyStoreException; 103import java.security.MessageDigest; 104import java.security.NoSuchAlgorithmException; 105import java.security.SecureRandom; 106import java.security.UnrecoverableKeyException; 107import java.security.cert.CertificateException; 108import java.util.ArrayList; 109import java.util.Arrays; 110import java.util.List; 111import java.util.Map; 112import java.util.concurrent.CountDownLatch; 113import java.util.concurrent.TimeUnit; 114 115import javax.crypto.BadPaddingException; 116import javax.crypto.Cipher; 117import javax.crypto.IllegalBlockSizeException; 118import javax.crypto.KeyGenerator; 119import javax.crypto.NoSuchPaddingException; 120import javax.crypto.SecretKey; 121import javax.crypto.spec.GCMParameterSpec; 122 123/** 124 * Keeps the lock pattern/password data and related settings for each user. Used by 125 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save 126 * lockscreen information for secondary users. 127 * 128 * @hide 129 */ 130public class LockSettingsService extends ILockSettings.Stub { 131 private static final String TAG = "LockSettingsService"; 132 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE; 133 private static final boolean DEBUG = false; 134 135 private static final int PROFILE_KEY_IV_SIZE = 12; 136 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; 137 138 // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this 139 private final Object mSeparateChallengeLock = new Object(); 140 141 private final Injector mInjector; 142 private final Context mContext; 143 private final Handler mHandler; 144 @VisibleForTesting 145 protected final LockSettingsStorage mStorage; 146 private final LockSettingsStrongAuth mStrongAuth; 147 private final SynchronizedStrongAuthTracker mStrongAuthTracker; 148 149 private final LockPatternUtils mLockPatternUtils; 150 private final NotificationManager mNotificationManager; 151 private final UserManager mUserManager; 152 private final IActivityManager mActivityManager; 153 private final SyntheticPasswordManager mSpManager; 154 155 private final KeyStore mKeyStore; 156 157 private boolean mFirstCallToVold; 158 protected IGateKeeperService mGateKeeperService; 159 160 /** 161 * The UIDs that are used for system credential storage in keystore. 162 */ 163 private static final int[] SYSTEM_CREDENTIAL_UIDS = { 164 Process.WIFI_UID, Process.VPN_UID, 165 Process.ROOT_UID }; 166 167 // This class manages life cycle events for encrypted users on File Based Encryption (FBE) 168 // devices. The most basic of these is to show/hide notifications about missing features until 169 // the user unlocks the account and credential-encrypted storage is available. 170 public static final class Lifecycle extends SystemService { 171 private LockSettingsService mLockSettingsService; 172 173 public Lifecycle(Context context) { 174 super(context); 175 } 176 177 @Override 178 public void onStart() { 179 AndroidKeyStoreProvider.install(); 180 mLockSettingsService = new LockSettingsService(getContext()); 181 publishBinderService("lock_settings", mLockSettingsService); 182 } 183 184 @Override 185 public void onStartUser(int userHandle) { 186 mLockSettingsService.onStartUser(userHandle); 187 } 188 189 @Override 190 public void onUnlockUser(int userHandle) { 191 mLockSettingsService.onUnlockUser(userHandle); 192 } 193 194 @Override 195 public void onCleanupUser(int userHandle) { 196 mLockSettingsService.onCleanupUser(userHandle); 197 } 198 } 199 200 @VisibleForTesting 201 protected static class SynchronizedStrongAuthTracker 202 extends LockPatternUtils.StrongAuthTracker { 203 public SynchronizedStrongAuthTracker(Context context) { 204 super(context); 205 } 206 207 @Override 208 protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) { 209 synchronized (this) { 210 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId); 211 } 212 } 213 214 @Override 215 public int getStrongAuthForUser(int userId) { 216 synchronized (this) { 217 return super.getStrongAuthForUser(userId); 218 } 219 } 220 221 void register(LockSettingsStrongAuth strongAuth) { 222 strongAuth.registerStrongAuthTracker(this.mStub); 223 } 224 } 225 226 /** 227 * Tie managed profile to primary profile if it is in unified mode and not tied before. 228 * 229 * @param managedUserId Managed profile user Id 230 * @param managedUserPassword Managed profile original password (when it has separated lock). 231 * NULL when it does not have a separated lock before. 232 */ 233 public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) { 234 if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId); 235 // Only for managed profile 236 if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) { 237 return; 238 } 239 // Do not tie managed profile when work challenge is enabled 240 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) { 241 return; 242 } 243 // Do not tie managed profile to parent when it's done already 244 if (mStorage.hasChildProfileLock(managedUserId)) { 245 return; 246 } 247 // Do not tie it to parent when parent does not have a screen lock 248 final int parentId = mUserManager.getProfileParent(managedUserId).id; 249 if (!isUserSecure(parentId)) { 250 if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock"); 251 return; 252 } 253 // Do not tie when the parent has no SID (but does have a screen lock). 254 // This can only happen during an upgrade path where SID is yet to be 255 // generated when the user unlocks for the first time. 256 try { 257 if (getGateKeeperService().getSecureUserId(parentId) == 0) { 258 return; 259 } 260 } catch (RemoteException e) { 261 Slog.e(TAG, "Failed to talk to GateKeeper service", e); 262 return; 263 } 264 if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!"); 265 byte[] randomLockSeed = new byte[] {}; 266 try { 267 randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40); 268 String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed)); 269 setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 270 managedUserPassword, managedUserId); 271 // We store a private credential for the managed user that's unlocked by the primary 272 // account holder's credential. As such, the user will never be prompted to enter this 273 // password directly, so we always store a password. 274 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 275 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId); 276 tieProfileLockToParent(managedUserId, newPassword); 277 } catch (NoSuchAlgorithmException | RemoteException e) { 278 Slog.e(TAG, "Fail to tie managed profile", e); 279 // Nothing client can do to fix this issue, so we do not throw exception out 280 } 281 } 282 283 static class Injector { 284 285 protected Context mContext; 286 287 public Injector(Context context) { 288 mContext = context; 289 } 290 291 public Context getContext() { 292 return mContext; 293 } 294 295 public Handler getHandler() { 296 return new Handler(); 297 } 298 299 public LockSettingsStorage getStorage() { 300 final LockSettingsStorage storage = new LockSettingsStorage(mContext); 301 storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() { 302 @Override 303 public void initialize(SQLiteDatabase db) { 304 // Get the lockscreen default from a system property, if available 305 boolean lockScreenDisable = SystemProperties.getBoolean( 306 "ro.lockscreen.disable.default", false); 307 if (lockScreenDisable) { 308 storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0); 309 } 310 } 311 }); 312 return storage; 313 } 314 315 public LockSettingsStrongAuth getStrongAuth() { 316 return new LockSettingsStrongAuth(mContext); 317 } 318 319 public SynchronizedStrongAuthTracker getStrongAuthTracker() { 320 return new SynchronizedStrongAuthTracker(mContext); 321 } 322 323 public IActivityManager getActivityManager() { 324 return ActivityManager.getService(); 325 } 326 327 public LockPatternUtils getLockPatternUtils() { 328 return new LockPatternUtils(mContext); 329 } 330 331 public NotificationManager getNotificationManager() { 332 return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 333 } 334 335 public UserManager getUserManager() { 336 return (UserManager) mContext.getSystemService(Context.USER_SERVICE); 337 } 338 339 public DevicePolicyManager getDevicePolicyManager() { 340 return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 341 } 342 343 public KeyStore getKeyStore() { 344 return KeyStore.getInstance(); 345 } 346 347 public IStorageManager getStorageManager() { 348 final IBinder service = ServiceManager.getService("mount"); 349 if (service != null) { 350 return IStorageManager.Stub.asInterface(service); 351 } 352 return null; 353 } 354 355 public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) { 356 return new SyntheticPasswordManager(storage); 357 } 358 359 public int binderGetCallingUid() { 360 return Binder.getCallingUid(); 361 } 362 } 363 364 public LockSettingsService(Context context) { 365 this(new Injector(context)); 366 } 367 368 @VisibleForTesting 369 protected LockSettingsService(Injector injector) { 370 mInjector = injector; 371 mContext = injector.getContext(); 372 mKeyStore = injector.getKeyStore(); 373 mHandler = injector.getHandler(); 374 mStrongAuth = injector.getStrongAuth(); 375 mActivityManager = injector.getActivityManager(); 376 377 mLockPatternUtils = injector.getLockPatternUtils(); 378 mFirstCallToVold = true; 379 380 IntentFilter filter = new IntentFilter(); 381 filter.addAction(Intent.ACTION_USER_ADDED); 382 filter.addAction(Intent.ACTION_USER_STARTING); 383 filter.addAction(Intent.ACTION_USER_REMOVED); 384 injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, 385 null, null); 386 387 mStorage = injector.getStorage(); 388 mNotificationManager = injector.getNotificationManager(); 389 mUserManager = injector.getUserManager(); 390 mStrongAuthTracker = injector.getStrongAuthTracker(); 391 mStrongAuthTracker.register(mStrongAuth); 392 393 mSpManager = injector.getSyntheticPasswordManager(mStorage); 394 } 395 396 /** 397 * If the account is credential-encrypted, show notification requesting the user to unlock the 398 * device. 399 */ 400 private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) { 401 final UserInfo user = mUserManager.getUserInfo(userId); 402 if (!user.isManagedProfile()) { 403 // When the user is locked, we communicate it loud-and-clear 404 // on the lockscreen; we only show a notification below for 405 // locked managed profiles. 406 return; 407 } 408 409 final UserHandle userHandle = user.getUserHandle(); 410 final boolean isSecure = isUserSecure(userId); 411 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) { 412 UserInfo parent = mUserManager.getProfileParent(userId); 413 if (parent != null && 414 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) && 415 !mUserManager.isQuietModeEnabled(userHandle)) { 416 // Only show notifications for managed profiles once their parent 417 // user is unlocked. 418 showEncryptionNotificationForProfile(userHandle); 419 } 420 } 421 } 422 423 private void showEncryptionNotificationForProfile(UserHandle user) { 424 Resources r = mContext.getResources(); 425 CharSequence title = r.getText( 426 com.android.internal.R.string.user_encrypted_title); 427 CharSequence message = r.getText( 428 com.android.internal.R.string.profile_encrypted_message); 429 CharSequence detail = r.getText( 430 com.android.internal.R.string.profile_encrypted_detail); 431 432 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE); 433 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, 434 user.getIdentifier()); 435 if (unlockIntent == null) { 436 return; 437 } 438 unlockIntent.setFlags( 439 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 440 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent, 441 PendingIntent.FLAG_UPDATE_CURRENT); 442 443 showEncryptionNotification(user, title, message, detail, intent); 444 } 445 446 private void showEncryptionNotification(UserHandle user, CharSequence title, 447 CharSequence message, CharSequence detail, PendingIntent intent) { 448 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier()); 449 450 // Suppress all notifications on non-FBE devices for now 451 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return; 452 453 Notification notification = 454 new Notification.Builder(mContext, SystemNotificationChannels.SECURITY) 455 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure) 456 .setWhen(0) 457 .setOngoing(true) 458 .setTicker(title) 459 .setColor(mContext.getColor( 460 com.android.internal.R.color.system_notification_accent_color)) 461 .setContentTitle(title) 462 .setContentText(message) 463 .setSubText(detail) 464 .setVisibility(Notification.VISIBILITY_PUBLIC) 465 .setContentIntent(intent) 466 .build(); 467 mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION, 468 notification, user); 469 } 470 471 private void hideEncryptionNotification(UserHandle userHandle) { 472 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier()); 473 mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION, 474 userHandle); 475 } 476 477 public void onCleanupUser(int userId) { 478 hideEncryptionNotification(new UserHandle(userId)); 479 } 480 481 public void onStartUser(final int userId) { 482 maybeShowEncryptionNotificationForUser(userId); 483 } 484 485 public void onUnlockUser(final int userId) { 486 // Perform tasks which require locks in LSS on a handler, as we are callbacks from 487 // ActivityManager.unlockUser() 488 mHandler.post(new Runnable() { 489 @Override 490 public void run() { 491 // Hide notification first, as tie managed profile lock takes time 492 hideEncryptionNotification(new UserHandle(userId)); 493 494 // Now we have unlocked the parent user we should show notifications 495 // about any profiles that exist. 496 List<UserInfo> profiles = mUserManager.getProfiles(userId); 497 for (int i = 0; i < profiles.size(); i++) { 498 UserInfo profile = profiles.get(i); 499 final boolean isSecure = isUserSecure(profile.id); 500 if (isSecure && profile.isManagedProfile()) { 501 UserHandle userHandle = profile.getUserHandle(); 502 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) && 503 !mUserManager.isQuietModeEnabled(userHandle)) { 504 showEncryptionNotificationForProfile(userHandle); 505 } 506 } 507 } 508 509 if (mUserManager.getUserInfo(userId).isManagedProfile()) { 510 tieManagedProfileLockIfNecessary(userId, null); 511 } 512 } 513 }); 514 } 515 516 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 517 @Override 518 public void onReceive(Context context, Intent intent) { 519 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { 520 // Notify keystore that a new user was added. 521 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 522 if (userHandle > UserHandle.USER_SYSTEM) { 523 removeUser(userHandle, /* unknownUser= */ true); 524 } 525 final KeyStore ks = KeyStore.getInstance(); 526 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle); 527 final int parentHandle = parentInfo != null ? parentInfo.id : -1; 528 ks.onUserAdded(userHandle, parentHandle); 529 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { 530 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 531 mStorage.prefetchUser(userHandle); 532 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { 533 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 534 if (userHandle > 0) { 535 removeUser(userHandle, /* unknownUser= */ false); 536 } 537 } 538 } 539 }; 540 541 @Override // binder interface 542 public void systemReady() { 543 migrateOldData(); 544 try { 545 getGateKeeperService(); 546 mSpManager.initWeaverService(); 547 } catch (RemoteException e) { 548 Slog.e(TAG, "Failure retrieving IGateKeeperService", e); 549 } 550 // TODO: maybe skip this for split system user mode. 551 mStorage.prefetchUser(UserHandle.USER_SYSTEM); 552 } 553 554 private void migrateOldData() { 555 try { 556 // These Settings moved before multi-user was enabled, so we only have to do it for the 557 // root user. 558 if (getString("migrated", null, 0) == null) { 559 final ContentResolver cr = mContext.getContentResolver(); 560 for (String validSetting : VALID_SETTINGS) { 561 String value = Settings.Secure.getString(cr, validSetting); 562 if (value != null) { 563 setString(validSetting, value, 0); 564 } 565 } 566 // No need to move the password / pattern files. They're already in the right place. 567 setString("migrated", "true", 0); 568 Slog.i(TAG, "Migrated lock settings to new location"); 569 } 570 571 // These Settings changed after multi-user was enabled, hence need to be moved per user. 572 if (getString("migrated_user_specific", null, 0) == null) { 573 final ContentResolver cr = mContext.getContentResolver(); 574 List<UserInfo> users = mUserManager.getUsers(); 575 for (int user = 0; user < users.size(); user++) { 576 // Migrate owner info 577 final int userId = users.get(user).id; 578 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO; 579 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId); 580 if (!TextUtils.isEmpty(ownerInfo)) { 581 setString(OWNER_INFO, ownerInfo, userId); 582 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId); 583 } 584 585 // Migrate owner info enabled. Note there was a bug where older platforms only 586 // stored this value if the checkbox was toggled at least once. The code detects 587 // this case by handling the exception. 588 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED; 589 boolean enabled; 590 try { 591 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId); 592 enabled = ivalue != 0; 593 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId); 594 } catch (SettingNotFoundException e) { 595 // Setting was never stored. Store it if the string is not empty. 596 if (!TextUtils.isEmpty(ownerInfo)) { 597 setLong(OWNER_INFO_ENABLED, 1, userId); 598 } 599 } 600 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId); 601 } 602 // No need to move the password / pattern files. They're already in the right place. 603 setString("migrated_user_specific", "true", 0); 604 Slog.i(TAG, "Migrated per-user lock settings to new location"); 605 } 606 607 // Migrates biometric weak such that the fallback mechanism becomes the primary. 608 if (getString("migrated_biometric_weak", null, 0) == null) { 609 List<UserInfo> users = mUserManager.getUsers(); 610 for (int i = 0; i < users.size(); i++) { 611 int userId = users.get(i).id; 612 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 613 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 614 userId); 615 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 616 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 617 userId); 618 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) { 619 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 620 alternateType, 621 userId); 622 } 623 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 624 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 625 userId); 626 } 627 setString("migrated_biometric_weak", "true", 0); 628 Slog.i(TAG, "Migrated biometric weak to use the fallback instead"); 629 } 630 631 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one 632 // user was present on the system, so if we're upgrading to M and there is more than one 633 // user we disable the flag to remain consistent. 634 if (getString("migrated_lockscreen_disabled", null, 0) == null) { 635 final List<UserInfo> users = mUserManager.getUsers(); 636 final int userCount = users.size(); 637 int switchableUsers = 0; 638 for (int i = 0; i < userCount; i++) { 639 if (users.get(i).supportsSwitchTo()) { 640 switchableUsers++; 641 } 642 } 643 644 if (switchableUsers > 1) { 645 for (int i = 0; i < userCount; i++) { 646 int id = users.get(i).id; 647 648 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) { 649 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id); 650 } 651 } 652 } 653 654 setString("migrated_lockscreen_disabled", "true", 0); 655 Slog.i(TAG, "Migrated lockscreen disabled flag"); 656 } 657 658 final List<UserInfo> users = mUserManager.getUsers(); 659 for (int i = 0; i < users.size(); i++) { 660 final UserInfo userInfo = users.get(i); 661 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) { 662 // When managed profile has a unified lock, the password quality stored has 2 663 // possibilities only. 664 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are 665 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC. 666 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for 667 // unified lock. 668 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 669 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id); 670 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 671 // Only possible when it's upgraded from nyc dp3 672 Slog.i(TAG, "Migrated tied profile lock type"); 673 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 674 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id); 675 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) { 676 // It should not happen 677 Slog.e(TAG, "Invalid tied profile lock type: " + quality); 678 } 679 } 680 try { 681 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id; 682 java.security.KeyStore keyStore = 683 java.security.KeyStore.getInstance("AndroidKeyStore"); 684 keyStore.load(null); 685 if (keyStore.containsAlias(alias)) { 686 keyStore.deleteEntry(alias); 687 } 688 } catch (KeyStoreException | NoSuchAlgorithmException | 689 CertificateException | IOException e) { 690 Slog.e(TAG, "Unable to remove tied profile key", e); 691 } 692 } 693 694 boolean isWatch = mContext.getPackageManager().hasSystemFeature( 695 PackageManager.FEATURE_WATCH); 696 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts 697 // and device management the lockscreen must be re-enabled now for users that upgrade. 698 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) { 699 final int userCount = users.size(); 700 for (int i = 0; i < userCount; i++) { 701 int id = users.get(i).id; 702 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id); 703 } 704 setString("migrated_wear_lockscreen_disabled", "true", 0); 705 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices"); 706 } 707 } catch (RemoteException re) { 708 Slog.e(TAG, "Unable to migrate old data", re); 709 } 710 } 711 712 private final void checkWritePermission(int userId) { 713 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite"); 714 } 715 716 private final void checkPasswordReadPermission(int userId) { 717 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead"); 718 } 719 720 private final void checkReadPermission(String requestedKey, int userId) { 721 final int callingUid = Binder.getCallingUid(); 722 723 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) { 724 String key = READ_CONTACTS_PROTECTED_SETTINGS[i]; 725 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS) 726 != PackageManager.PERMISSION_GRANTED) { 727 throw new SecurityException("uid=" + callingUid 728 + " needs permission " + READ_CONTACTS + " to read " 729 + requestedKey + " for user " + userId); 730 } 731 } 732 733 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) { 734 String key = READ_PASSWORD_PROTECTED_SETTINGS[i]; 735 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION) 736 != PackageManager.PERMISSION_GRANTED) { 737 throw new SecurityException("uid=" + callingUid 738 + " needs permission " + PERMISSION + " to read " 739 + requestedKey + " for user " + userId); 740 } 741 } 742 } 743 744 @Override 745 public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException { 746 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId); 747 synchronized (mSeparateChallengeLock) { 748 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); 749 } 750 } 751 752 @Override 753 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled, 754 String managedUserPassword) throws RemoteException { 755 checkWritePermission(userId); 756 synchronized (mSeparateChallengeLock) { 757 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId); 758 if (enabled) { 759 mStorage.removeChildProfileLock(userId); 760 removeKeystoreProfileKey(userId); 761 } else { 762 tieManagedProfileLockIfNecessary(userId, managedUserPassword); 763 } 764 } 765 } 766 767 @Override 768 public void setBoolean(String key, boolean value, int userId) throws RemoteException { 769 checkWritePermission(userId); 770 setStringUnchecked(key, userId, value ? "1" : "0"); 771 } 772 773 @Override 774 public void setLong(String key, long value, int userId) throws RemoteException { 775 checkWritePermission(userId); 776 setStringUnchecked(key, userId, Long.toString(value)); 777 } 778 779 @Override 780 public void setString(String key, String value, int userId) throws RemoteException { 781 checkWritePermission(userId); 782 setStringUnchecked(key, userId, value); 783 } 784 785 private void setStringUnchecked(String key, int userId, String value) { 786 mStorage.writeKeyValue(key, value, userId); 787 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) { 788 BackupManager.dataChanged("com.android.providers.settings"); 789 } 790 } 791 792 @Override 793 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { 794 checkReadPermission(key, userId); 795 String value = getStringUnchecked(key, null, userId); 796 return TextUtils.isEmpty(value) ? 797 defaultValue : (value.equals("1") || value.equals("true")); 798 } 799 800 @Override 801 public long getLong(String key, long defaultValue, int userId) throws RemoteException { 802 checkReadPermission(key, userId); 803 String value = getStringUnchecked(key, null, userId); 804 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); 805 } 806 807 @Override 808 public String getString(String key, String defaultValue, int userId) throws RemoteException { 809 checkReadPermission(key, userId); 810 return getStringUnchecked(key, defaultValue, userId); 811 } 812 813 public String getStringUnchecked(String key, String defaultValue, int userId) { 814 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) { 815 long ident = Binder.clearCallingIdentity(); 816 try { 817 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0"; 818 } finally { 819 Binder.restoreCallingIdentity(ident); 820 } 821 } 822 823 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) { 824 key = Settings.Secure.LOCK_PATTERN_ENABLED; 825 } 826 827 return mStorage.readKeyValue(key, defaultValue, userId); 828 } 829 830 @Override 831 public boolean havePassword(int userId) throws RemoteException { 832 synchronized (mSpManager) { 833 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 834 long handle = getSyntheticPasswordHandleLocked(userId); 835 return mSpManager.getCredentialType(handle, userId) == 836 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; 837 } 838 } 839 // Do we need a permissions check here? 840 return mStorage.hasPassword(userId); 841 } 842 843 @Override 844 public boolean havePattern(int userId) throws RemoteException { 845 synchronized (mSpManager) { 846 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 847 long handle = getSyntheticPasswordHandleLocked(userId); 848 return mSpManager.getCredentialType(handle, userId) == 849 LockPatternUtils.CREDENTIAL_TYPE_PATTERN; 850 } 851 } 852 // Do we need a permissions check here? 853 return mStorage.hasPattern(userId); 854 } 855 856 private boolean isUserSecure(int userId) { 857 synchronized (mSpManager) { 858 try { 859 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 860 long handle = getSyntheticPasswordHandleLocked(userId); 861 return mSpManager.getCredentialType(handle, userId) != 862 LockPatternUtils.CREDENTIAL_TYPE_NONE; 863 } 864 } catch (RemoteException e) { 865 // fall through 866 } 867 } 868 return mStorage.hasCredential(userId); 869 } 870 871 private void setKeystorePassword(String password, int userHandle) { 872 final KeyStore ks = KeyStore.getInstance(); 873 ks.onUserPasswordChanged(userHandle, password); 874 } 875 876 private void unlockKeystore(String password, int userHandle) { 877 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); 878 final KeyStore ks = KeyStore.getInstance(); 879 ks.unlock(userHandle, password); 880 } 881 882 @VisibleForTesting 883 protected String getDecryptedPasswordForTiedProfile(int userId) 884 throws KeyStoreException, UnrecoverableKeyException, 885 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, 886 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, 887 CertificateException, IOException { 888 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key"); 889 byte[] storedData = mStorage.readChildProfileLock(userId); 890 if (storedData == null) { 891 throw new FileNotFoundException("Child profile lock file not found"); 892 } 893 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE); 894 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE, 895 storedData.length); 896 byte[] decryptionResult; 897 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); 898 keyStore.load(null); 899 SecretKey decryptionKey = (SecretKey) keyStore.getKey( 900 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null); 901 902 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" 903 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); 904 905 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv)); 906 decryptionResult = cipher.doFinal(encryptedPassword); 907 return new String(decryptionResult, StandardCharsets.UTF_8); 908 } 909 910 private void unlockChildProfile(int profileHandle) throws RemoteException { 911 try { 912 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), 913 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 914 false, 0 /* no challenge */, profileHandle, null /* progressCallback */); 915 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 916 | NoSuchAlgorithmException | NoSuchPaddingException 917 | InvalidAlgorithmParameterException | IllegalBlockSizeException 918 | BadPaddingException | CertificateException | IOException e) { 919 if (e instanceof FileNotFoundException) { 920 Slog.i(TAG, "Child profile key not found"); 921 } else { 922 Slog.e(TAG, "Failed to decrypt child profile key", e); 923 } 924 } 925 } 926 927 private void unlockUser(int userId, byte[] token, byte[] secret) { 928 // TODO: make this method fully async so we can update UI with progress strings 929 final CountDownLatch latch = new CountDownLatch(1); 930 final IProgressListener listener = new IProgressListener.Stub() { 931 @Override 932 public void onStarted(int id, Bundle extras) throws RemoteException { 933 Log.d(TAG, "unlockUser started"); 934 } 935 936 @Override 937 public void onProgress(int id, int progress, Bundle extras) throws RemoteException { 938 Log.d(TAG, "unlockUser progress " + progress); 939 } 940 941 @Override 942 public void onFinished(int id, Bundle extras) throws RemoteException { 943 Log.d(TAG, "unlockUser finished"); 944 latch.countDown(); 945 } 946 }; 947 948 try { 949 mActivityManager.unlockUser(userId, token, secret, listener); 950 } catch (RemoteException e) { 951 throw e.rethrowAsRuntimeException(); 952 } 953 954 try { 955 latch.await(15, TimeUnit.SECONDS); 956 } catch (InterruptedException e) { 957 Thread.currentThread().interrupt(); 958 } 959 try { 960 if (!mUserManager.getUserInfo(userId).isManagedProfile()) { 961 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 962 for (UserInfo pi : profiles) { 963 // Unlock managed profile with unified lock 964 if (pi.isManagedProfile() 965 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id) 966 && mStorage.hasChildProfileLock(pi.id) 967 && mUserManager.isUserRunning(pi.id)) { 968 unlockChildProfile(pi.id); 969 } 970 } 971 } 972 } catch (RemoteException e) { 973 Log.d(TAG, "Failed to unlock child profile", e); 974 } 975 } 976 977 private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) { 978 if (mUserManager.getUserInfo(userId).isManagedProfile()) { 979 return null; 980 } 981 Map<Integer, String> result = new ArrayMap<Integer, String>(); 982 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 983 final int size = profiles.size(); 984 for (int i = 0; i < size; i++) { 985 final UserInfo profile = profiles.get(i); 986 if (!profile.isManagedProfile()) { 987 continue; 988 } 989 final int managedUserId = profile.id; 990 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) { 991 continue; 992 } 993 try { 994 result.put(userId, getDecryptedPasswordForTiedProfile(userId)); 995 } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException 996 | NoSuchPaddingException | InvalidKeyException 997 | InvalidAlgorithmParameterException | IllegalBlockSizeException 998 | BadPaddingException | CertificateException | IOException e) { 999 // ignore 1000 } 1001 } 1002 return result; 1003 } 1004 1005 /** 1006 * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them 1007 * depending on the parent user's secure state. 1008 * 1009 * When clearing tied work challenges, a pre-computed password table for profiles are required, 1010 * since changing password for profiles requires existing password, and existing passwords can 1011 * only be computed before the parent user's password is cleared. 1012 * 1013 * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this 1014 * method again on profiles. However the recursion is guaranteed to terminate as this method 1015 * terminates when the user is a managed profile. 1016 */ 1017 private void synchronizeUnifiedWorkChallengeForProfiles(int userId, 1018 Map<Integer, String> profilePasswordMap) throws RemoteException { 1019 if (mUserManager.getUserInfo(userId).isManagedProfile()) { 1020 return; 1021 } 1022 final boolean isSecure = isUserSecure(userId); 1023 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 1024 final int size = profiles.size(); 1025 for (int i = 0; i < size; i++) { 1026 final UserInfo profile = profiles.get(i); 1027 if (profile.isManagedProfile()) { 1028 final int managedUserId = profile.id; 1029 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) { 1030 continue; 1031 } 1032 if (isSecure) { 1033 tieManagedProfileLockIfNecessary(managedUserId, null); 1034 } else { 1035 // We use cached work profile password computed before clearing the parent's 1036 // credential, otherwise they get lost 1037 if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) { 1038 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, 1039 profilePasswordMap.get(managedUserId), managedUserId); 1040 } else { 1041 Slog.wtf(TAG, "clear tied profile challenges, but no password supplied."); 1042 // Supplying null here would lead to untrusted credential change 1043 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null, 1044 managedUserId); 1045 } 1046 mStorage.removeChildProfileLock(managedUserId); 1047 removeKeystoreProfileKey(managedUserId); 1048 } 1049 } 1050 } 1051 } 1052 1053 private boolean isManagedProfileWithUnifiedLock(int userId) { 1054 return mUserManager.getUserInfo(userId).isManagedProfile() 1055 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId); 1056 } 1057 1058 private boolean isManagedProfileWithSeparatedLock(int userId) { 1059 return mUserManager.getUserInfo(userId).isManagedProfile() 1060 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId); 1061 } 1062 1063 // This method should be called by LockPatternUtil only, all internal methods in this class 1064 // should call setLockCredentialInternal. 1065 @Override 1066 public void setLockCredential(String credential, int type, String savedCredential, int userId) 1067 throws RemoteException { 1068 checkWritePermission(userId); 1069 synchronized (mSeparateChallengeLock) { 1070 setLockCredentialInternal(credential, type, savedCredential, userId); 1071 setSeparateProfileChallengeEnabled(userId, true, null); 1072 notifyPasswordChanged(userId); 1073 } 1074 } 1075 1076 private void setLockCredentialInternal(String credential, int credentialType, 1077 String savedCredential, int userId) throws RemoteException { 1078 // Normalize savedCredential and credential such that empty string is always represented 1079 // as null. 1080 if (TextUtils.isEmpty(savedCredential)) { 1081 savedCredential = null; 1082 } 1083 if (TextUtils.isEmpty(credential)) { 1084 credential = null; 1085 } 1086 synchronized (mSpManager) { 1087 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 1088 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential, 1089 userId); 1090 return; 1091 } 1092 } 1093 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { 1094 if (credential != null) { 1095 Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); 1096 } 1097 clearUserKeyProtection(userId); 1098 getGateKeeperService().clearSecureUserId(userId); 1099 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); 1100 setKeystorePassword(null, userId); 1101 fixateNewestUserKeyAuth(userId); 1102 synchronizeUnifiedWorkChallengeForProfiles(userId, null); 1103 notifyActivePasswordMetricsAvailable(null, userId); 1104 return; 1105 } 1106 if (credential == null) { 1107 throw new RemoteException("Null credential with mismatched credential type"); 1108 } 1109 1110 CredentialHash currentHandle = mStorage.readCredentialHash(userId); 1111 if (isManagedProfileWithUnifiedLock(userId)) { 1112 // get credential from keystore when managed profile has unified lock 1113 if (savedCredential == null) { 1114 try { 1115 savedCredential = getDecryptedPasswordForTiedProfile(userId); 1116 } catch (FileNotFoundException e) { 1117 Slog.i(TAG, "Child profile key not found"); 1118 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 1119 | NoSuchAlgorithmException | NoSuchPaddingException 1120 | InvalidAlgorithmParameterException | IllegalBlockSizeException 1121 | BadPaddingException | CertificateException | IOException e) { 1122 Slog.e(TAG, "Failed to decrypt child profile key", e); 1123 } 1124 } 1125 } else { 1126 if (currentHandle.hash == null) { 1127 if (savedCredential != null) { 1128 Slog.w(TAG, "Saved credential provided, but none stored"); 1129 } 1130 savedCredential = null; 1131 } 1132 } 1133 synchronized (mSpManager) { 1134 if (shouldMigrateToSyntheticPasswordLocked(userId)) { 1135 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, 1136 currentHandle.type, userId); 1137 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential, 1138 userId); 1139 return; 1140 } 1141 } 1142 if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId); 1143 byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential, 1144 userId); 1145 if (enrolledHandle != null) { 1146 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType); 1147 mStorage.writeCredentialHash(willStore, userId); 1148 // push new secret and auth token to vold 1149 GateKeeperResponse gkResponse = getGateKeeperService() 1150 .verifyChallenge(userId, 0, willStore.hash, credential.getBytes()); 1151 setUserKeyProtection(userId, credential, convertResponse(gkResponse)); 1152 fixateNewestUserKeyAuth(userId); 1153 // Refresh the auth token 1154 doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */); 1155 synchronizeUnifiedWorkChallengeForProfiles(userId, null); 1156 } else { 1157 throw new RemoteException("Failed to enroll " + 1158 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password" 1159 : "pattern")); 1160 } 1161 } 1162 1163 private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) { 1164 VerifyCredentialResponse response; 1165 int responseCode = gateKeeperResponse.getResponseCode(); 1166 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { 1167 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout()); 1168 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) { 1169 byte[] token = gateKeeperResponse.getPayload(); 1170 if (token == null) { 1171 // something's wrong if there's no payload with a challenge 1172 Slog.e(TAG, "verifyChallenge response had no associated payload"); 1173 response = VerifyCredentialResponse.ERROR; 1174 } else { 1175 response = new VerifyCredentialResponse(token); 1176 } 1177 } else { 1178 response = VerifyCredentialResponse.ERROR; 1179 } 1180 return response; 1181 } 1182 1183 @VisibleForTesting 1184 protected void tieProfileLockToParent(int userId, String password) { 1185 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId); 1186 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8); 1187 byte[] encryptionResult; 1188 byte[] iv; 1189 try { 1190 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); 1191 keyGenerator.init(new SecureRandom()); 1192 SecretKey secretKey = keyGenerator.generateKey(); 1193 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); 1194 keyStore.load(null); 1195 try { 1196 keyStore.setEntry( 1197 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, 1198 new java.security.KeyStore.SecretKeyEntry(secretKey), 1199 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) 1200 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 1201 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 1202 .build()); 1203 keyStore.setEntry( 1204 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, 1205 new java.security.KeyStore.SecretKeyEntry(secretKey), 1206 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) 1207 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 1208 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 1209 .setUserAuthenticationRequired(true) 1210 .setUserAuthenticationValidityDurationSeconds(30) 1211 .build()); 1212 // Key imported, obtain a reference to it. 1213 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey( 1214 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null); 1215 Cipher cipher = Cipher.getInstance( 1216 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" 1217 + KeyProperties.ENCRYPTION_PADDING_NONE); 1218 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey); 1219 encryptionResult = cipher.doFinal(randomLockSeed); 1220 iv = cipher.getIV(); 1221 } finally { 1222 // The original key can now be discarded. 1223 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId); 1224 } 1225 } catch (CertificateException | UnrecoverableKeyException 1226 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException 1227 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { 1228 throw new RuntimeException("Failed to encrypt key", e); 1229 } 1230 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 1231 try { 1232 if (iv.length != PROFILE_KEY_IV_SIZE) { 1233 throw new RuntimeException("Invalid iv length: " + iv.length); 1234 } 1235 outputStream.write(iv); 1236 outputStream.write(encryptionResult); 1237 } catch (IOException e) { 1238 throw new RuntimeException("Failed to concatenate byte arrays", e); 1239 } 1240 mStorage.writeChildProfileLock(userId, outputStream.toByteArray()); 1241 } 1242 1243 private byte[] enrollCredential(byte[] enrolledHandle, 1244 String enrolledCredential, String toEnroll, int userId) 1245 throws RemoteException { 1246 checkWritePermission(userId); 1247 byte[] enrolledCredentialBytes = enrolledCredential == null 1248 ? null 1249 : enrolledCredential.getBytes(); 1250 byte[] toEnrollBytes = toEnroll == null 1251 ? null 1252 : toEnroll.getBytes(); 1253 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle, 1254 enrolledCredentialBytes, toEnrollBytes); 1255 1256 if (response == null) { 1257 return null; 1258 } 1259 1260 byte[] hash = response.getPayload(); 1261 if (hash != null) { 1262 setKeystorePassword(toEnroll, userId); 1263 } else { 1264 // Should not happen 1265 Slog.e(TAG, "Throttled while enrolling a password"); 1266 } 1267 return hash; 1268 } 1269 1270 private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException { 1271 if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId); 1272 addUserKeyAuth(userId, null, key); 1273 } 1274 1275 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr) 1276 throws RemoteException { 1277 if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId); 1278 if (vcr == null) { 1279 throw new RemoteException("Null response verifying a credential we just set"); 1280 } 1281 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { 1282 throw new RemoteException("Non-OK response verifying a credential we just set: " 1283 + vcr.getResponseCode()); 1284 } 1285 byte[] token = vcr.getPayload(); 1286 if (token == null) { 1287 throw new RemoteException("Empty payload verifying a credential we just set"); 1288 } 1289 addUserKeyAuth(userId, token, secretFromCredential(credential)); 1290 } 1291 1292 private void clearUserKeyProtection(int userId) throws RemoteException { 1293 if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId); 1294 addUserKeyAuth(userId, null, null); 1295 } 1296 1297 private static byte[] secretFromCredential(String credential) throws RemoteException { 1298 try { 1299 MessageDigest digest = MessageDigest.getInstance("SHA-512"); 1300 // Personalize the hash 1301 byte[] personalization = "Android FBE credential hash" 1302 .getBytes(StandardCharsets.UTF_8); 1303 // Pad it to the block size of the hash function 1304 personalization = Arrays.copyOf(personalization, 128); 1305 digest.update(personalization); 1306 digest.update(credential.getBytes(StandardCharsets.UTF_8)); 1307 return digest.digest(); 1308 } catch (NoSuchAlgorithmException e) { 1309 throw new RuntimeException("NoSuchAlgorithmException for SHA-512"); 1310 } 1311 } 1312 1313 private void addUserKeyAuth(int userId, byte[] token, byte[] secret) 1314 throws RemoteException { 1315 final UserInfo userInfo = mUserManager.getUserInfo(userId); 1316 final IStorageManager storageManager = mInjector.getStorageManager(); 1317 final long callingId = Binder.clearCallingIdentity(); 1318 try { 1319 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret); 1320 } finally { 1321 Binder.restoreCallingIdentity(callingId); 1322 } 1323 } 1324 1325 private void fixateNewestUserKeyAuth(int userId) 1326 throws RemoteException { 1327 if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId); 1328 final IStorageManager storageManager = mInjector.getStorageManager(); 1329 final long callingId = Binder.clearCallingIdentity(); 1330 try { 1331 storageManager.fixateNewestUserKeyAuth(userId); 1332 } finally { 1333 Binder.restoreCallingIdentity(callingId); 1334 } 1335 } 1336 1337 @Override 1338 public void resetKeyStore(int userId) throws RemoteException { 1339 checkWritePermission(userId); 1340 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); 1341 int managedUserId = -1; 1342 String managedUserDecryptedPassword = null; 1343 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 1344 for (UserInfo pi : profiles) { 1345 // Unlock managed profile with unified lock 1346 if (pi.isManagedProfile() 1347 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id) 1348 && mStorage.hasChildProfileLock(pi.id)) { 1349 try { 1350 if (managedUserId == -1) { 1351 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id); 1352 managedUserId = pi.id; 1353 } else { 1354 // Should not happen 1355 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId 1356 + ", uid2:" + pi.id); 1357 } 1358 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 1359 | NoSuchAlgorithmException | NoSuchPaddingException 1360 | InvalidAlgorithmParameterException | IllegalBlockSizeException 1361 | BadPaddingException | CertificateException | IOException e) { 1362 Slog.e(TAG, "Failed to decrypt child profile key", e); 1363 } 1364 } 1365 } 1366 try { 1367 // Clear all the users credentials could have been installed in for this user. 1368 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) { 1369 for (int uid : SYSTEM_CREDENTIAL_UIDS) { 1370 mKeyStore.clearUid(UserHandle.getUid(profileId, uid)); 1371 } 1372 } 1373 } finally { 1374 if (managedUserId != -1 && managedUserDecryptedPassword != null) { 1375 if (DEBUG) Slog.v(TAG, "Restore tied profile lock"); 1376 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); 1377 } 1378 } 1379 } 1380 1381 @Override 1382 public VerifyCredentialResponse checkCredential(String credential, int type, int userId, 1383 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1384 checkPasswordReadPermission(userId); 1385 return doVerifyCredential(credential, type, false, 0, userId, progressCallback); 1386 } 1387 1388 @Override 1389 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge, 1390 int userId) throws RemoteException { 1391 checkPasswordReadPermission(userId); 1392 return doVerifyCredential(credential, type, true, challenge, userId, 1393 null /* progressCallback */); 1394 } 1395 1396 /** 1397 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero 1398 * format. 1399 */ 1400 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType, 1401 boolean hasChallenge, long challenge, int userId, 1402 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1403 if (TextUtils.isEmpty(credential)) { 1404 throw new IllegalArgumentException("Credential can't be null or empty"); 1405 } 1406 synchronized (mSpManager) { 1407 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 1408 VerifyCredentialResponse response = spBasedDoVerifyCredentialLocked(credential, 1409 credentialType, hasChallenge, challenge, userId, progressCallback); 1410 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 1411 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); 1412 } 1413 return response; 1414 } 1415 } 1416 CredentialHash storedHash = mStorage.readCredentialHash(userId); 1417 if (storedHash.type != credentialType) { 1418 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??" 1419 + " stored: " + storedHash.type + " passed in: " + credentialType); 1420 return VerifyCredentialResponse.ERROR; 1421 } 1422 1423 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN 1424 && storedHash.isBaseZeroPattern; 1425 1426 String credentialToVerify; 1427 if (shouldReEnrollBaseZero) { 1428 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential); 1429 } else { 1430 credentialToVerify = credential; 1431 } 1432 1433 VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify, 1434 hasChallenge, challenge, progressCallback); 1435 1436 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 1437 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); 1438 if (shouldReEnrollBaseZero) { 1439 setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId); 1440 } 1441 } 1442 1443 return response; 1444 } 1445 1446 @Override 1447 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, 1448 long challenge, int userId) throws RemoteException { 1449 checkPasswordReadPermission(userId); 1450 if (!isManagedProfileWithUnifiedLock(userId)) { 1451 throw new RemoteException("User id must be managed profile with unified lock"); 1452 } 1453 final int parentProfileId = mUserManager.getProfileParent(userId).id; 1454 // Unlock parent by using parent's challenge 1455 final VerifyCredentialResponse parentResponse = doVerifyCredential( 1456 credential, 1457 type, 1458 true /* hasChallenge */, 1459 challenge, 1460 parentProfileId, 1461 null /* progressCallback */); 1462 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { 1463 // Failed, just return parent's response 1464 return parentResponse; 1465 } 1466 1467 try { 1468 // Unlock work profile, and work profile with unified lock must use password only 1469 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), 1470 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 1471 true, 1472 challenge, 1473 userId, null /* progressCallback */); 1474 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 1475 | NoSuchAlgorithmException | NoSuchPaddingException 1476 | InvalidAlgorithmParameterException | IllegalBlockSizeException 1477 | BadPaddingException | CertificateException | IOException e) { 1478 Slog.e(TAG, "Failed to decrypt child profile key", e); 1479 throw new RemoteException("Unable to get tied profile token"); 1480 } 1481 } 1482 1483 /** 1484 * Lowest-level credential verification routine that talks to GateKeeper. If verification 1485 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy 1486 * hash to GK. 1487 */ 1488 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, 1489 String credential, boolean hasChallenge, long challenge, 1490 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1491 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) { 1492 // don't need to pass empty credentials to GateKeeper 1493 return VerifyCredentialResponse.OK; 1494 } 1495 1496 if (storedHash == null || TextUtils.isEmpty(credential)) { 1497 return VerifyCredentialResponse.ERROR; 1498 } 1499 1500 // We're potentially going to be doing a bunch of disk I/O below as part 1501 // of unlocking the user, so yell if calling from the main thread. 1502 StrictMode.noteDiskRead(); 1503 1504 if (storedHash.version == CredentialHash.VERSION_LEGACY) { 1505 final byte[] hash; 1506 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { 1507 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential)); 1508 } else { 1509 hash = mLockPatternUtils.passwordToHash(credential, userId); 1510 } 1511 if (Arrays.equals(hash, storedHash.hash)) { 1512 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { 1513 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId); 1514 } else { 1515 unlockKeystore(credential, userId); 1516 } 1517 // Users with legacy credentials don't have credential-backed 1518 // FBE keys, so just pass through a fake token/secret 1519 Slog.i(TAG, "Unlocking user with fake token: " + userId); 1520 final byte[] fakeToken = String.valueOf(userId).getBytes(); 1521 unlockUser(userId, fakeToken, fakeToken); 1522 1523 // migrate credential to GateKeeper 1524 setLockCredentialInternal(credential, storedHash.type, null, userId); 1525 if (!hasChallenge) { 1526 notifyActivePasswordMetricsAvailable(credential, userId); 1527 return VerifyCredentialResponse.OK; 1528 } 1529 // Fall through to get the auth token. Technically this should never happen, 1530 // as a user that had a legacy credential would have to unlock their device 1531 // before getting to a flow with a challenge, but supporting for consistency. 1532 } else { 1533 return VerifyCredentialResponse.ERROR; 1534 } 1535 } 1536 GateKeeperResponse gateKeeperResponse = getGateKeeperService() 1537 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes()); 1538 VerifyCredentialResponse response = convertResponse(gateKeeperResponse); 1539 boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); 1540 1541 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 1542 1543 // credential has matched 1544 1545 if (progressCallback != null) { 1546 progressCallback.onCredentialVerified(); 1547 } 1548 notifyActivePasswordMetricsAvailable(credential, userId); 1549 unlockKeystore(credential, userId); 1550 1551 Slog.i(TAG, "Unlocking user " + userId + " with token length " 1552 + response.getPayload().length); 1553 unlockUser(userId, response.getPayload(), secretFromCredential(credential)); 1554 1555 if (isManagedProfileWithSeparatedLock(userId)) { 1556 TrustManager trustManager = 1557 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); 1558 trustManager.setDeviceLockedForUser(userId, false); 1559 } 1560 if (shouldReEnroll) { 1561 setLockCredentialInternal(credential, storedHash.type, credential, userId); 1562 } else { 1563 // Now that we've cleared of all required GK migration, let's do the final 1564 // migration to synthetic password. 1565 synchronized (mSpManager) { 1566 if (shouldMigrateToSyntheticPasswordLocked(userId)) { 1567 AuthenticationToken auth = initializeSyntheticPasswordLocked( 1568 storedHash.hash, credential, storedHash.type, userId); 1569 activateEscrowTokens(auth, userId); 1570 } 1571 } 1572 } 1573 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 1574 if (response.getTimeout() > 0) { 1575 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId); 1576 } 1577 } 1578 1579 return response; 1580 } 1581 1582 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) { 1583 final PasswordMetrics metrics; 1584 if (password == null) { 1585 metrics = new PasswordMetrics(); 1586 } else { 1587 metrics = PasswordMetrics.computeForPassword(password); 1588 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); 1589 } 1590 1591 // Asynchronous to avoid dead lock 1592 mHandler.post(() -> { 1593 DevicePolicyManager dpm = (DevicePolicyManager) 1594 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 1595 dpm.setActivePasswordState(metrics, userId); 1596 }); 1597 } 1598 1599 /** 1600 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before 1601 * reporting the password changed. 1602 */ 1603 private void notifyPasswordChanged(@UserIdInt int userId) { 1604 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering 1605 mHandler.post(() -> { 1606 DevicePolicyManager dpm = (DevicePolicyManager) 1607 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 1608 dpm.reportPasswordChanged(userId); 1609 }); 1610 } 1611 1612 @Override 1613 public boolean checkVoldPassword(int userId) throws RemoteException { 1614 if (!mFirstCallToVold) { 1615 return false; 1616 } 1617 mFirstCallToVold = false; 1618 1619 checkPasswordReadPermission(userId); 1620 1621 // There's no guarantee that this will safely connect, but if it fails 1622 // we will simply show the lock screen when we shouldn't, so relatively 1623 // benign. There is an outside chance something nasty would happen if 1624 // this service restarted before vold stales out the password in this 1625 // case. The nastiness is limited to not showing the lock screen when 1626 // we should, within the first minute of decrypting the phone if this 1627 // service can't connect to vold, it restarts, and then the new instance 1628 // does successfully connect. 1629 final IStorageManager service = mInjector.getStorageManager(); 1630 String password; 1631 long identity = Binder.clearCallingIdentity(); 1632 try { 1633 password = service.getPassword(); 1634 service.clearPassword(); 1635 } finally { 1636 Binder.restoreCallingIdentity(identity); 1637 } 1638 if (password == null) { 1639 return false; 1640 } 1641 1642 try { 1643 if (mLockPatternUtils.isLockPatternEnabled(userId)) { 1644 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId, 1645 null /* progressCallback */) 1646 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { 1647 return true; 1648 } 1649 } 1650 } catch (Exception e) { 1651 } 1652 1653 try { 1654 if (mLockPatternUtils.isLockPasswordEnabled(userId)) { 1655 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId, 1656 null /* progressCallback */) 1657 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { 1658 return true; 1659 } 1660 } 1661 } catch (Exception e) { 1662 } 1663 1664 return false; 1665 } 1666 1667 private void removeUser(int userId, boolean unknownUser) { 1668 mSpManager.removeUser(userId); 1669 mStorage.removeUser(userId); 1670 mStrongAuth.removeUser(userId); 1671 1672 final KeyStore ks = KeyStore.getInstance(); 1673 ks.onUserRemoved(userId); 1674 1675 try { 1676 final IGateKeeperService gk = getGateKeeperService(); 1677 if (gk != null) { 1678 gk.clearSecureUserId(userId); 1679 } 1680 } catch (RemoteException ex) { 1681 Slog.w(TAG, "unable to clear GK secure user id"); 1682 } 1683 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) { 1684 removeKeystoreProfileKey(userId); 1685 } 1686 } 1687 1688 private void removeKeystoreProfileKey(int targetUserId) { 1689 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId); 1690 try { 1691 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); 1692 keyStore.load(null); 1693 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId); 1694 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId); 1695 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException 1696 | IOException e) { 1697 // We have tried our best to remove all keys 1698 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e); 1699 } 1700 } 1701 1702 @Override 1703 public void registerStrongAuthTracker(IStrongAuthTracker tracker) { 1704 checkPasswordReadPermission(UserHandle.USER_ALL); 1705 mStrongAuth.registerStrongAuthTracker(tracker); 1706 } 1707 1708 @Override 1709 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) { 1710 checkPasswordReadPermission(UserHandle.USER_ALL); 1711 mStrongAuth.unregisterStrongAuthTracker(tracker); 1712 } 1713 1714 @Override 1715 public void requireStrongAuth(int strongAuthReason, int userId) { 1716 checkWritePermission(userId); 1717 mStrongAuth.requireStrongAuth(strongAuthReason, userId); 1718 } 1719 1720 @Override 1721 public void userPresent(int userId) { 1722 checkWritePermission(userId); 1723 mStrongAuth.reportUnlock(userId); 1724 } 1725 1726 @Override 1727 public int getStrongAuthForUser(int userId) { 1728 checkPasswordReadPermission(userId); 1729 return mStrongAuthTracker.getStrongAuthForUser(userId); 1730 } 1731 1732 private boolean isCallerShell() { 1733 final int callingUid = Binder.getCallingUid(); 1734 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID; 1735 } 1736 1737 private void enforceShell() { 1738 if (!isCallerShell()) { 1739 throw new SecurityException("Caller must be shell"); 1740 } 1741 } 1742 1743 @Override 1744 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1745 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 1746 throws RemoteException { 1747 enforceShell(); 1748 final long origId = Binder.clearCallingIdentity(); 1749 try { 1750 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec( 1751 this, in, out, err, args, callback, resultReceiver); 1752 } finally { 1753 Binder.restoreCallingIdentity(origId); 1754 } 1755 } 1756 1757 private static final String[] VALID_SETTINGS = new String[] { 1758 LockPatternUtils.LOCKOUT_PERMANENT_KEY, 1759 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, 1760 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, 1761 LockPatternUtils.PASSWORD_TYPE_KEY, 1762 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 1763 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 1764 LockPatternUtils.DISABLE_LOCKSCREEN_KEY, 1765 LockPatternUtils.LOCKSCREEN_OPTIONS, 1766 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, 1767 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY, 1768 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, 1769 LockPatternUtils.PASSWORD_HISTORY_KEY, 1770 Secure.LOCK_PATTERN_ENABLED, 1771 Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 1772 Secure.LOCK_PATTERN_VISIBLE, 1773 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED 1774 }; 1775 1776 // Reading these settings needs the contacts permission 1777 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] { 1778 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1779 Secure.LOCK_SCREEN_OWNER_INFO 1780 }; 1781 1782 // Reading these settings needs the same permission as checking the password 1783 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] { 1784 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 1785 LockPatternUtils.PASSWORD_HISTORY_KEY, 1786 LockPatternUtils.PASSWORD_TYPE_KEY, 1787 SEPARATE_PROFILE_CHALLENGE_KEY 1788 }; 1789 1790 private static final String[] SETTINGS_TO_BACKUP = new String[] { 1791 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1792 Secure.LOCK_SCREEN_OWNER_INFO 1793 }; 1794 1795 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient { 1796 @Override 1797 public void binderDied() { 1798 mGateKeeperService.asBinder().unlinkToDeath(this, 0); 1799 mGateKeeperService = null; 1800 } 1801 } 1802 1803 protected synchronized IGateKeeperService getGateKeeperService() 1804 throws RemoteException { 1805 if (mGateKeeperService != null) { 1806 return mGateKeeperService; 1807 } 1808 1809 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE); 1810 if (service != null) { 1811 service.linkToDeath(new GateKeeperDiedRecipient(), 0); 1812 mGateKeeperService = IGateKeeperService.Stub.asInterface(service); 1813 return mGateKeeperService; 1814 } 1815 1816 Slog.e(TAG, "Unable to acquire GateKeeperService"); 1817 return null; 1818 } 1819 1820 /** 1821 * Precondition: vold and keystore unlocked. 1822 * 1823 * Create new synthetic password, set up synthetic password blob protected by the supplied 1824 * user credential, and make the newly-created SP blob active. 1825 * 1826 * The invariant under a synthetic password is: 1827 * 1. If user credential exists, then both vold and keystore and protected with keys derived 1828 * from the synthetic password. 1829 * 2. If user credential does not exist, vold and keystore protection are cleared. This is to 1830 * make it consistent with current behaviour. It also allows ActivityManager to call 1831 * unlockUser() with empty secret. 1832 * 3. Once a user is migrated to have synthetic password, its value will never change, no matter 1833 * whether the user changes his lockscreen PIN or clear/reset it. When the user clears its 1834 * lockscreen PIN, we still maintain the existing synthetic password in a password blob 1835 * protected by a default PIN. The only exception is when the DPC performs an untrusted 1836 * credential change, in which case we have no way to derive the existing synthetic password 1837 * and has to create a new one. 1838 * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user 1839 * clears/re-creates his lockscreen PIN. 1840 * 1841 * 1842 * Different cases of calling this method: 1843 * 1. credentialHash != null 1844 * This implies credential != null, a new SP blob will be provisioned, and existing SID 1845 * migrated to associate with the new SP. 1846 * This happens during a normal migration case when the user currently has password. 1847 * 1848 * 2. credentialhash == null and credential == null 1849 * A new SP blob and a new SID will be created, while the user has no credentials. 1850 * This can happens when we are activating an escrow token on a unsecured device, during 1851 * which we want to create the SP structure with an empty user credential. 1852 * 1853 * 3. credentialhash == null and credential != null 1854 * This is the untrusted credential reset, OR the user sets a new lockscreen password 1855 * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created 1856 */ 1857 private AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, 1858 String credential, int credentialType, int userId) throws RemoteException { 1859 Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); 1860 AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(getGateKeeperService(), 1861 credentialHash, credential, userId); 1862 if (auth == null) { 1863 Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token"); 1864 return null; 1865 } 1866 long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(), 1867 credential, credentialType, auth, userId); 1868 if (credential != null) { 1869 if (credentialHash == null) { 1870 // Since when initializing SP, we didn't provide an existing password handle 1871 // for it to migrate SID, we need to create a new SID for the user. 1872 mSpManager.newSidForUser(getGateKeeperService(), auth, userId); 1873 } 1874 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId); 1875 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); 1876 setKeystorePassword(auth.deriveKeyStorePassword(), userId); 1877 } else { 1878 clearUserKeyProtection(userId); 1879 setKeystorePassword(null, userId); 1880 getGateKeeperService().clearSecureUserId(userId); 1881 } 1882 fixateNewestUserKeyAuth(userId); 1883 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId); 1884 return auth; 1885 } 1886 1887 private long getSyntheticPasswordHandleLocked(int userId) { 1888 try { 1889 return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId); 1890 } catch (RemoteException e) { 1891 return SyntheticPasswordManager.DEFAULT_HANDLE; 1892 } 1893 } 1894 1895 private boolean isSyntheticPasswordBasedCredentialLocked(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; 1900 } 1901 1902 private boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException { 1903 long handle = getSyntheticPasswordHandleLocked(userId); 1904 // This is a global setting 1905 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM); 1906 return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE; 1907 } 1908 1909 private void enableSyntheticPasswordLocked() throws RemoteException { 1910 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); 1911 } 1912 1913 private VerifyCredentialResponse spBasedDoVerifyCredentialLocked(String userCredential, int 1914 credentialType, boolean hasChallenge, long challenge, int userId, 1915 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1916 if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredentialLocked: user=" + userId); 1917 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { 1918 userCredential = null; 1919 } 1920 long handle = getSyntheticPasswordHandleLocked(userId); 1921 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( 1922 getGateKeeperService(), handle, userCredential, userId); 1923 1924 VerifyCredentialResponse response = authResult.gkResponse; 1925 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 1926 // credential has matched 1927 // perform verifyChallenge with synthetic password which generates the real auth 1928 // token for the current user 1929 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken, 1930 challenge, userId); 1931 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { 1932 Slog.wtf(TAG, "verifyChallenge with SP failed."); 1933 return VerifyCredentialResponse.ERROR; 1934 } 1935 if (progressCallback != null) { 1936 progressCallback.onCredentialVerified(); 1937 } 1938 notifyActivePasswordMetricsAvailable(userCredential, userId); 1939 unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId); 1940 1941 final byte[] secret = authResult.authToken.deriveDiskEncryptionKey(); 1942 Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length); 1943 unlockUser(userId, null, secret); 1944 1945 if (isManagedProfileWithSeparatedLock(userId)) { 1946 TrustManager trustManager = 1947 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); 1948 trustManager.setDeviceLockedForUser(userId, false); 1949 } 1950 activateEscrowTokens(authResult.authToken, userId); 1951 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 1952 if (response.getTimeout() > 0) { 1953 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId); 1954 } 1955 } 1956 1957 return response; 1958 } 1959 1960 /** 1961 * Change the user's lockscreen password by creating a new SP blob and update the handle, based 1962 * on an existing authentication token. Even though a new SP blob is created, the underlying 1963 * synthetic password is never changed. 1964 * 1965 * When clearing credential, we keep the SP unchanged, but clear its password handle so its 1966 * SID is gone. We also clear password from (software-based) keystore and vold, which will be 1967 * added back when new password is set in future. 1968 */ 1969 private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType, 1970 AuthenticationToken auth, int userId) throws RemoteException { 1971 if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId); 1972 long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(), 1973 credential, credentialType, auth, userId); 1974 final Map<Integer, String> profilePasswords; 1975 if (credential != null) { 1976 // // not needed by synchronizeUnifiedWorkChallengeForProfiles() 1977 profilePasswords = null; 1978 1979 if (mSpManager.hasSidForUser(userId)) { 1980 // We are changing password of a secured device, nothing more needed as 1981 // createPasswordBasedSyntheticPassword has already taken care of maintaining 1982 // the password handle and SID unchanged. 1983 1984 //refresh auth token 1985 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId); 1986 } else { 1987 // A new password is set on a previously-unsecured device, we need to generate 1988 // a new SID, and re-add keys to vold and keystore. 1989 mSpManager.newSidForUser(getGateKeeperService(), auth, userId); 1990 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId); 1991 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey()); 1992 fixateNewestUserKeyAuth(userId); 1993 setKeystorePassword(auth.deriveKeyStorePassword(), userId); 1994 } 1995 } else { 1996 // Cache all profile password if they use unified work challenge. This will later be 1997 // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles() 1998 profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId); 1999 2000 // we are clearing password of a secured device, so need to nuke SID as well. 2001 mSpManager.clearSidForUser(userId); 2002 getGateKeeperService().clearSecureUserId(userId); 2003 // Clear key from vold so ActivityManager can just unlock the user with empty secret 2004 // during boot. 2005 clearUserKeyProtection(userId); 2006 fixateNewestUserKeyAuth(userId); 2007 setKeystorePassword(null, userId); 2008 } 2009 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId); 2010 synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); 2011 return newHandle; 2012 } 2013 2014 private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType, 2015 String savedCredential, int userId) throws RemoteException { 2016 if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); 2017 if (isManagedProfileWithUnifiedLock(userId)) { 2018 // get credential from keystore when managed profile has unified lock 2019 try { 2020 savedCredential = getDecryptedPasswordForTiedProfile(userId); 2021 } catch (FileNotFoundException e) { 2022 Slog.i(TAG, "Child profile key not found"); 2023 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 2024 | NoSuchAlgorithmException | NoSuchPaddingException 2025 | InvalidAlgorithmParameterException | IllegalBlockSizeException 2026 | BadPaddingException | CertificateException | IOException e) { 2027 Slog.e(TAG, "Failed to decrypt child profile key", e); 2028 } 2029 } 2030 long handle = getSyntheticPasswordHandleLocked(userId); 2031 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( 2032 getGateKeeperService(), handle, savedCredential, userId); 2033 VerifyCredentialResponse response = authResult.gkResponse; 2034 AuthenticationToken auth = authResult.authToken; 2035 if (auth != null) { 2036 // We are performing a trusted credential change i.e. a correct existing credential 2037 // is provided 2038 setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId); 2039 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); 2040 } else if (response != null 2041 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){ 2042 // We are performing an untrusted credential change i.e. by DevicePolicyManager. 2043 // So provision a new SP and SID. This would invalidate existing escrow tokens. 2044 // Still support this for now but this flow will be removed in the next release. 2045 2046 Slog.w(TAG, "Untrusted credential change invoked"); 2047 initializeSyntheticPasswordLocked(null, credential, credentialType, userId); 2048 synchronizeUnifiedWorkChallengeForProfiles(userId, null); 2049 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); 2050 } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ { 2051 Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " + 2052 (response != null ? "rate limit exceeded" : "failed")); 2053 return; 2054 } 2055 notifyActivePasswordMetricsAvailable(credential, userId); 2056 2057 } 2058 2059 @Override 2060 public long addEscrowToken(byte[] token, int userId) throws RemoteException { 2061 ensureCallerSystemUid(); 2062 if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); 2063 synchronized (mSpManager) { 2064 enableSyntheticPasswordLocked(); 2065 // Migrate to synthetic password based credentials if the user has no password, 2066 // the token can then be activated immediately. 2067 AuthenticationToken auth = null; 2068 if (!isUserSecure(userId)) { 2069 if (shouldMigrateToSyntheticPasswordLocked(userId)) { 2070 auth = initializeSyntheticPasswordLocked(null, null, 2071 LockPatternUtils.CREDENTIAL_TYPE_NONE, userId); 2072 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ { 2073 long pwdHandle = getSyntheticPasswordHandleLocked(userId); 2074 auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(), 2075 pwdHandle, null, userId).authToken; 2076 } 2077 } 2078 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 2079 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); 2080 if (!mSpManager.hasEscrowData(userId)) { 2081 throw new SecurityException("Escrow token is disabled on the current user"); 2082 } 2083 } 2084 long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId); 2085 if (auth != null) { 2086 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId); 2087 } 2088 return handle; 2089 } 2090 } 2091 2092 private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException { 2093 if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId); 2094 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); 2095 synchronized (mSpManager) { 2096 for (long handle : mSpManager.getPendingTokensForUser(userId)) { 2097 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId)); 2098 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId); 2099 } 2100 } 2101 } 2102 2103 @Override 2104 public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException { 2105 ensureCallerSystemUid(); 2106 synchronized (mSpManager) { 2107 return mSpManager.existsHandle(handle, userId); 2108 } 2109 } 2110 2111 @Override 2112 public boolean removeEscrowToken(long handle, int userId) throws RemoteException { 2113 ensureCallerSystemUid(); 2114 synchronized (mSpManager) { 2115 if (handle == getSyntheticPasswordHandleLocked(userId)) { 2116 Slog.w(TAG, "Cannot remove password handle"); 2117 return false; 2118 } 2119 if (mSpManager.removePendingToken(handle, userId)) { 2120 return true; 2121 } 2122 if (mSpManager.existsHandle(handle, userId)) { 2123 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId); 2124 return true; 2125 } else { 2126 return false; 2127 } 2128 } 2129 } 2130 2131 @Override 2132 public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, 2133 byte[] token, int userId) throws RemoteException { 2134 ensureCallerSystemUid(); 2135 boolean result; 2136 synchronized (mSpManager) { 2137 if (!mSpManager.hasEscrowData(userId)) { 2138 throw new SecurityException("Escrow token is disabled on the current user"); 2139 } 2140 result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token, 2141 userId); 2142 } 2143 if (result) { 2144 synchronized (mSeparateChallengeLock) { 2145 setSeparateProfileChallengeEnabled(userId, true, null); 2146 } 2147 notifyPasswordChanged(userId); 2148 } 2149 return result; 2150 } 2151 2152 private boolean setLockCredentialWithTokenInternal(String credential, int type, 2153 long tokenHandle, byte[] token, int userId) throws RemoteException { 2154 synchronized (mSpManager) { 2155 AuthenticationResult result = mSpManager.unwrapTokenBasedSyntheticPassword( 2156 getGateKeeperService(), tokenHandle, token, userId); 2157 if (result.authToken == null) { 2158 Slog.w(TAG, "Invalid escrow token supplied"); 2159 return false; 2160 } 2161 long oldHandle = getSyntheticPasswordHandleLocked(userId); 2162 setLockCredentialWithAuthTokenLocked(credential, type, result.authToken, userId); 2163 mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId); 2164 return true; 2165 } 2166 } 2167 2168 @Override 2169 public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) 2170 throws RemoteException { 2171 ensureCallerSystemUid(); 2172 AuthenticationResult authResult; 2173 synchronized (mSpManager) { 2174 if (!mSpManager.hasEscrowData(userId)) { 2175 throw new SecurityException("Escrow token is disabled on the current user"); 2176 } 2177 authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(), 2178 tokenHandle, token, userId); 2179 if (authResult.authToken == null) { 2180 Slog.w(TAG, "Invalid escrow token supplied"); 2181 return; 2182 } 2183 } 2184 unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey()); 2185 } 2186 2187 @Override 2188 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){ 2189 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 2190 2191 pw.println("Current lock settings service state:"); 2192 pw.println(String.format("SP Enabled = %b", 2193 mLockPatternUtils.isSyntheticPasswordEnabled())); 2194 2195 List<UserInfo> users = mUserManager.getUsers(); 2196 for (int user = 0; user < users.size(); user++) { 2197 final int userId = users.get(user).id; 2198 pw.println(" User " + userId); 2199 synchronized (mSpManager) { 2200 pw.println(String.format(" SP Handle = %x", 2201 getSyntheticPasswordHandleLocked(userId))); 2202 } 2203 try { 2204 pw.println(String.format(" SID = %x", 2205 getGateKeeperService().getSecureUserId(userId))); 2206 } catch (RemoteException e) { 2207 // ignore. 2208 } 2209 } 2210 } 2211 2212 private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) { 2213 long ident = Binder.clearCallingIdentity(); 2214 try { 2215 // Managed profile should have escrow enabled 2216 if (mUserManager.getUserInfo(userId).isManagedProfile()) { 2217 Slog.i(TAG, "Managed profile can have escrow token"); 2218 return; 2219 } 2220 DevicePolicyManager dpm = mInjector.getDevicePolicyManager(); 2221 // Devices with Device Owner should have escrow enabled on all users. 2222 if (dpm.getDeviceOwnerComponentOnAnyUser() != null) { 2223 Slog.i(TAG, "Corp-owned device can have escrow token"); 2224 return; 2225 } 2226 // We could also have a profile owner on the given (non-managed) user for unicorn cases 2227 if (dpm.getProfileOwnerAsUser(userId) != null) { 2228 Slog.i(TAG, "User with profile owner can have escrow token"); 2229 return; 2230 } 2231 // If the device is yet to be provisioned (still in SUW), there is still 2232 // a chance that Device Owner will be set on the device later, so postpone 2233 // disabling escrow token for now. 2234 if (!dpm.isDeviceProvisioned()) { 2235 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned"); 2236 return; 2237 } 2238 2239 // Escrow tokens are enabled on automotive builds. 2240 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { 2241 return; 2242 } 2243 2244 // Disable escrow token permanently on all other device/user types. 2245 Slog.i(TAG, "Disabling escrow token on user " + userId); 2246 if (isSyntheticPasswordBasedCredentialLocked(userId)) { 2247 mSpManager.destroyEscrowData(userId); 2248 } 2249 } catch (RemoteException e) { 2250 Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e); 2251 } finally { 2252 Binder.restoreCallingIdentity(ident); 2253 } 2254 } 2255 2256 private void ensureCallerSystemUid() throws SecurityException { 2257 final int callingUid = mInjector.binderGetCallingUid(); 2258 if (callingUid != Process.SYSTEM_UID) { 2259 throw new SecurityException("Only system can call this API."); 2260 } 2261 } 2262} 2263