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