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