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