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