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