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