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