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