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