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