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