LockSettingsService.java revision 1de89b3bec2f296763f3ecde9a36ecbca2110f3d
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE; 20import static android.Manifest.permission.READ_CONTACTS; 21import static android.content.Context.KEYGUARD_SERVICE; 22import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; 23 24import android.annotation.UserIdInt; 25import android.app.ActivityManager; 26import android.app.KeyguardManager; 27import android.app.Notification; 28import android.app.NotificationManager; 29import android.app.PendingIntent; 30import android.app.admin.DevicePolicyManager; 31import android.app.admin.PasswordMetrics; 32import android.app.backup.BackupManager; 33import android.app.trust.IStrongAuthTracker; 34import android.app.trust.TrustManager; 35import android.content.BroadcastReceiver; 36import android.content.ContentResolver; 37import android.content.Context; 38import android.content.Intent; 39import android.content.IntentFilter; 40import android.content.pm.PackageManager; 41import android.content.pm.UserInfo; 42import android.content.res.Resources; 43import android.database.sqlite.SQLiteDatabase; 44import android.os.Binder; 45import android.os.Bundle; 46import android.os.Handler; 47import android.os.IBinder; 48import android.os.IProgressListener; 49import android.os.Process; 50import android.os.RemoteException; 51import android.os.ResultReceiver; 52import android.os.ServiceManager; 53import android.os.ShellCallback; 54import android.os.StrictMode; 55import android.os.SystemProperties; 56import android.os.UserHandle; 57import android.os.UserManager; 58import android.os.storage.IStorageManager; 59import android.os.storage.StorageManager; 60import android.provider.Settings; 61import android.provider.Settings.Secure; 62import android.provider.Settings.SettingNotFoundException; 63import android.security.KeyStore; 64import android.security.keystore.AndroidKeyStoreProvider; 65import android.security.keystore.KeyProperties; 66import android.security.keystore.KeyProtection; 67import android.service.gatekeeper.GateKeeperResponse; 68import android.service.gatekeeper.IGateKeeperService; 69import android.text.TextUtils; 70import android.util.Log; 71import android.util.Slog; 72 73import com.android.internal.util.ArrayUtils; 74import com.android.internal.widget.ICheckCredentialProgressCallback; 75import com.android.internal.widget.ILockSettings; 76import com.android.internal.widget.LockPatternUtils; 77import com.android.internal.widget.VerifyCredentialResponse; 78import com.android.server.LockSettingsStorage.CredentialHash; 79 80import libcore.util.HexEncoding; 81 82import java.io.ByteArrayOutputStream; 83import java.io.FileDescriptor; 84import java.io.FileNotFoundException; 85import java.io.IOException; 86import java.nio.charset.StandardCharsets; 87import java.security.InvalidAlgorithmParameterException; 88import java.security.InvalidKeyException; 89import java.security.KeyStoreException; 90import java.security.MessageDigest; 91import java.security.NoSuchAlgorithmException; 92import java.security.SecureRandom; 93import java.security.UnrecoverableKeyException; 94import java.security.cert.CertificateException; 95import java.util.Arrays; 96import java.util.List; 97import java.util.concurrent.CountDownLatch; 98import java.util.concurrent.TimeUnit; 99 100import javax.crypto.BadPaddingException; 101import javax.crypto.Cipher; 102import javax.crypto.IllegalBlockSizeException; 103import javax.crypto.KeyGenerator; 104import javax.crypto.NoSuchPaddingException; 105import javax.crypto.SecretKey; 106import javax.crypto.spec.GCMParameterSpec; 107 108/** 109 * Keeps the lock pattern/password data and related settings for each user. Used by 110 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save 111 * lockscreen information for secondary users. 112 * 113 * @hide 114 */ 115public class LockSettingsService extends ILockSettings.Stub { 116 private static final String TAG = "LockSettingsService"; 117 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE; 118 private static final int FBE_ENCRYPTED_NOTIFICATION = 0; 119 private static final boolean DEBUG = false; 120 121 private static final int PROFILE_KEY_IV_SIZE = 12; 122 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; 123 124 private final Object mSeparateChallengeLock = new Object(); 125 126 private final Context mContext; 127 private final Handler mHandler; 128 private final LockSettingsStorage mStorage; 129 private final LockSettingsStrongAuth mStrongAuth; 130 private final SynchronizedStrongAuthTracker mStrongAuthTracker; 131 132 private LockPatternUtils mLockPatternUtils; 133 private boolean mFirstCallToVold; 134 private IGateKeeperService mGateKeeperService; 135 private NotificationManager mNotificationManager; 136 private UserManager mUserManager; 137 138 private final KeyStore mKeyStore = KeyStore.getInstance(); 139 140 /** 141 * The UIDs that are used for system credential storage in keystore. 142 */ 143 private static final int[] SYSTEM_CREDENTIAL_UIDS = { 144 Process.WIFI_UID, Process.VPN_UID, 145 Process.ROOT_UID, Process.SYSTEM_UID }; 146 147 // This class manages life cycle events for encrypted users on File Based Encryption (FBE) 148 // devices. The most basic of these is to show/hide notifications about missing features until 149 // the user unlocks the account and credential-encrypted storage is available. 150 public static final class Lifecycle extends SystemService { 151 private LockSettingsService mLockSettingsService; 152 153 public Lifecycle(Context context) { 154 super(context); 155 } 156 157 @Override 158 public void onStart() { 159 AndroidKeyStoreProvider.install(); 160 mLockSettingsService = new LockSettingsService(getContext()); 161 publishBinderService("lock_settings", mLockSettingsService); 162 } 163 164 @Override 165 public void onStartUser(int userHandle) { 166 mLockSettingsService.onStartUser(userHandle); 167 } 168 169 @Override 170 public void onUnlockUser(int userHandle) { 171 mLockSettingsService.onUnlockUser(userHandle); 172 } 173 174 @Override 175 public void onCleanupUser(int userHandle) { 176 mLockSettingsService.onCleanupUser(userHandle); 177 } 178 } 179 180 private class SynchronizedStrongAuthTracker extends LockPatternUtils.StrongAuthTracker { 181 public SynchronizedStrongAuthTracker(Context context) { 182 super(context); 183 } 184 185 @Override 186 protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) { 187 synchronized (this) { 188 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId); 189 } 190 } 191 192 @Override 193 public int getStrongAuthForUser(int userId) { 194 synchronized (this) { 195 return super.getStrongAuthForUser(userId); 196 } 197 } 198 199 void register() { 200 mStrongAuth.registerStrongAuthTracker(this.mStub); 201 } 202 } 203 204 /** 205 * Tie managed profile to primary profile if it is in unified mode and not tied before. 206 * 207 * @param managedUserId Managed profile user Id 208 * @param managedUserPassword Managed profile original password (when it has separated lock). 209 * NULL when it does not have a separated lock before. 210 */ 211 public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) { 212 if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId); 213 // Only for managed profile 214 if (!UserManager.get(mContext).getUserInfo(managedUserId).isManagedProfile()) { 215 return; 216 } 217 // Do not tie managed profile when work challenge is enabled 218 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) { 219 return; 220 } 221 // Do not tie managed profile to parent when it's done already 222 if (mStorage.hasChildProfileLock(managedUserId)) { 223 return; 224 } 225 // Do not tie it to parent when parent does not have a screen lock 226 final int parentId = mUserManager.getProfileParent(managedUserId).id; 227 if (!mStorage.hasPassword(parentId) && !mStorage.hasPattern(parentId)) { 228 if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock"); 229 return; 230 } 231 // Do not tie when the parent has no SID (but does have a screen lock). 232 // This can only happen during an upgrade path where SID is yet to be 233 // generated when the user unlocks for the first time. 234 try { 235 if (getGateKeeperService().getSecureUserId(parentId) == 0) { 236 return; 237 } 238 } catch (RemoteException e) { 239 Slog.e(TAG, "Failed to talk to GateKeeper service", e); 240 return; 241 } 242 if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!"); 243 byte[] randomLockSeed = new byte[] {}; 244 try { 245 randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40); 246 String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed)); 247 setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 248 managedUserPassword, managedUserId); 249 // We store a private credential for the managed user that's unlocked by the primary 250 // account holder's credential. As such, the user will never be prompted to enter this 251 // password directly, so we always store a password. 252 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 253 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId); 254 tieProfileLockToParent(managedUserId, newPassword); 255 } catch (NoSuchAlgorithmException | RemoteException e) { 256 Slog.e(TAG, "Fail to tie managed profile", e); 257 // Nothing client can do to fix this issue, so we do not throw exception out 258 } 259 } 260 261 public LockSettingsService(Context context) { 262 mContext = context; 263 mHandler = new Handler(); 264 mStrongAuth = new LockSettingsStrongAuth(context); 265 // Open the database 266 267 mLockPatternUtils = new LockPatternUtils(context); 268 mFirstCallToVold = true; 269 270 IntentFilter filter = new IntentFilter(); 271 filter.addAction(Intent.ACTION_USER_ADDED); 272 filter.addAction(Intent.ACTION_USER_STARTING); 273 filter.addAction(Intent.ACTION_USER_REMOVED); 274 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 275 276 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() { 277 @Override 278 public void initialize(SQLiteDatabase db) { 279 // Get the lockscreen default from a system property, if available 280 boolean lockScreenDisable = SystemProperties.getBoolean( 281 "ro.lockscreen.disable.default", false); 282 if (lockScreenDisable) { 283 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0); 284 } 285 } 286 }); 287 mNotificationManager = (NotificationManager) 288 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 289 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 290 mStrongAuthTracker = new SynchronizedStrongAuthTracker(mContext); 291 mStrongAuthTracker.register(); 292 293 } 294 295 /** 296 * If the account is credential-encrypted, show notification requesting the user to unlock the 297 * device. 298 */ 299 private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) { 300 final UserInfo user = mUserManager.getUserInfo(userId); 301 if (!user.isManagedProfile()) { 302 // When the user is locked, we communicate it loud-and-clear 303 // on the lockscreen; we only show a notification below for 304 // locked managed profiles. 305 return; 306 } 307 308 final UserHandle userHandle = user.getUserHandle(); 309 final boolean isSecure = mStorage.hasPassword(userId) || mStorage.hasPattern(userId); 310 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) { 311 UserInfo parent = mUserManager.getProfileParent(userId); 312 if (parent != null && 313 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) && 314 !mUserManager.isQuietModeEnabled(userHandle)) { 315 // Only show notifications for managed profiles once their parent 316 // user is unlocked. 317 showEncryptionNotificationForProfile(userHandle); 318 } 319 } 320 } 321 322 private void showEncryptionNotificationForProfile(UserHandle user) { 323 Resources r = mContext.getResources(); 324 CharSequence title = r.getText( 325 com.android.internal.R.string.user_encrypted_title); 326 CharSequence message = r.getText( 327 com.android.internal.R.string.profile_encrypted_message); 328 CharSequence detail = r.getText( 329 com.android.internal.R.string.profile_encrypted_detail); 330 331 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE); 332 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, 333 user.getIdentifier()); 334 if (unlockIntent == null) { 335 return; 336 } 337 unlockIntent.setFlags( 338 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 339 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent, 340 PendingIntent.FLAG_UPDATE_CURRENT); 341 342 showEncryptionNotification(user, title, message, detail, intent); 343 } 344 345 private void showEncryptionNotification(UserHandle user, CharSequence title, 346 CharSequence message, CharSequence detail, PendingIntent intent) { 347 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier()); 348 349 // Suppress all notifications on non-FBE devices for now 350 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return; 351 352 Notification notification = new Notification.Builder(mContext) 353 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure) 354 .setWhen(0) 355 .setOngoing(true) 356 .setTicker(title) 357 .setDefaults(0) // please be quiet 358 .setPriority(Notification.PRIORITY_MAX) 359 .setColor(mContext.getColor( 360 com.android.internal.R.color.system_notification_accent_color)) 361 .setContentTitle(title) 362 .setContentText(message) 363 .setSubText(detail) 364 .setVisibility(Notification.VISIBILITY_PUBLIC) 365 .setContentIntent(intent) 366 .build(); 367 mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user); 368 } 369 370 private void hideEncryptionNotification(UserHandle userHandle) { 371 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier()); 372 mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle); 373 } 374 375 public void onCleanupUser(int userId) { 376 hideEncryptionNotification(new UserHandle(userId)); 377 } 378 379 public void onStartUser(final int userId) { 380 maybeShowEncryptionNotificationForUser(userId); 381 } 382 383 public void onUnlockUser(final int userId) { 384 // Hide notification first, as tie managed profile lock takes time 385 hideEncryptionNotification(new UserHandle(userId)); 386 387 if (mUserManager.getUserInfo(userId).isManagedProfile()) { 388 // As tieManagedProfileLockIfNecessary() may try to unlock user, we should not do it 389 // in onUnlockUser() synchronously, otherwise it may cause a deadlock 390 mHandler.post(new Runnable() { 391 @Override 392 public void run() { 393 tieManagedProfileLockIfNecessary(userId, null); 394 } 395 }); 396 } 397 398 // Now we have unlocked the parent user we should show notifications 399 // about any profiles that exist. 400 List<UserInfo> profiles = mUserManager.getProfiles(userId); 401 for (int i = 0; i < profiles.size(); i++) { 402 UserInfo profile = profiles.get(i); 403 final boolean isSecure = 404 mStorage.hasPassword(profile.id) || mStorage.hasPattern(profile.id); 405 if (isSecure && profile.isManagedProfile()) { 406 UserHandle userHandle = profile.getUserHandle(); 407 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) && 408 !mUserManager.isQuietModeEnabled(userHandle)) { 409 showEncryptionNotificationForProfile(userHandle); 410 } 411 } 412 } 413 } 414 415 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 416 @Override 417 public void onReceive(Context context, Intent intent) { 418 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { 419 // Notify keystore that a new user was added. 420 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 421 if (userHandle > UserHandle.USER_SYSTEM) { 422 removeUser(userHandle, /* unknownUser= */ true); 423 } 424 final KeyStore ks = KeyStore.getInstance(); 425 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle); 426 final int parentHandle = parentInfo != null ? parentInfo.id : -1; 427 ks.onUserAdded(userHandle, parentHandle); 428 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { 429 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 430 mStorage.prefetchUser(userHandle); 431 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { 432 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 433 if (userHandle > 0) { 434 removeUser(userHandle, /* unknownUser= */ false); 435 } 436 } 437 } 438 }; 439 440 @Override // binder interface 441 public void systemReady() { 442 migrateOldData(); 443 try { 444 getGateKeeperService(); 445 } catch (RemoteException e) { 446 Slog.e(TAG, "Failure retrieving IGateKeeperService", e); 447 } 448 // TODO: maybe skip this for split system user mode. 449 mStorage.prefetchUser(UserHandle.USER_SYSTEM); 450 } 451 452 private void migrateOldData() { 453 try { 454 // These Settings moved before multi-user was enabled, so we only have to do it for the 455 // root user. 456 if (getString("migrated", null, 0) == null) { 457 final ContentResolver cr = mContext.getContentResolver(); 458 for (String validSetting : VALID_SETTINGS) { 459 String value = Settings.Secure.getString(cr, validSetting); 460 if (value != null) { 461 setString(validSetting, value, 0); 462 } 463 } 464 // No need to move the password / pattern files. They're already in the right place. 465 setString("migrated", "true", 0); 466 Slog.i(TAG, "Migrated lock settings to new location"); 467 } 468 469 // These Settings changed after multi-user was enabled, hence need to be moved per user. 470 if (getString("migrated_user_specific", null, 0) == null) { 471 final ContentResolver cr = mContext.getContentResolver(); 472 List<UserInfo> users = mUserManager.getUsers(); 473 for (int user = 0; user < users.size(); user++) { 474 // Migrate owner info 475 final int userId = users.get(user).id; 476 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO; 477 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId); 478 if (!TextUtils.isEmpty(ownerInfo)) { 479 setString(OWNER_INFO, ownerInfo, userId); 480 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId); 481 } 482 483 // Migrate owner info enabled. Note there was a bug where older platforms only 484 // stored this value if the checkbox was toggled at least once. The code detects 485 // this case by handling the exception. 486 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED; 487 boolean enabled; 488 try { 489 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId); 490 enabled = ivalue != 0; 491 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId); 492 } catch (SettingNotFoundException e) { 493 // Setting was never stored. Store it if the string is not empty. 494 if (!TextUtils.isEmpty(ownerInfo)) { 495 setLong(OWNER_INFO_ENABLED, 1, userId); 496 } 497 } 498 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId); 499 } 500 // No need to move the password / pattern files. They're already in the right place. 501 setString("migrated_user_specific", "true", 0); 502 Slog.i(TAG, "Migrated per-user lock settings to new location"); 503 } 504 505 // Migrates biometric weak such that the fallback mechanism becomes the primary. 506 if (getString("migrated_biometric_weak", null, 0) == null) { 507 List<UserInfo> users = mUserManager.getUsers(); 508 for (int i = 0; i < users.size(); i++) { 509 int userId = users.get(i).id; 510 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 511 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 512 userId); 513 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 514 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 515 userId); 516 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) { 517 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 518 alternateType, 519 userId); 520 } 521 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 522 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 523 userId); 524 } 525 setString("migrated_biometric_weak", "true", 0); 526 Slog.i(TAG, "Migrated biometric weak to use the fallback instead"); 527 } 528 529 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one 530 // user was present on the system, so if we're upgrading to M and there is more than one 531 // user we disable the flag to remain consistent. 532 if (getString("migrated_lockscreen_disabled", null, 0) == null) { 533 final List<UserInfo> users = mUserManager.getUsers(); 534 final int userCount = users.size(); 535 int switchableUsers = 0; 536 for (int i = 0; i < userCount; i++) { 537 if (users.get(i).supportsSwitchTo()) { 538 switchableUsers++; 539 } 540 } 541 542 if (switchableUsers > 1) { 543 for (int i = 0; i < userCount; i++) { 544 int id = users.get(i).id; 545 546 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) { 547 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id); 548 } 549 } 550 } 551 552 setString("migrated_lockscreen_disabled", "true", 0); 553 Slog.i(TAG, "Migrated lockscreen disabled flag"); 554 } 555 556 final List<UserInfo> users = mUserManager.getUsers(); 557 for (int i = 0; i < users.size(); i++) { 558 final UserInfo userInfo = users.get(i); 559 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) { 560 // When managed profile has a unified lock, the password quality stored has 2 561 // possibilities only. 562 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are 563 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC. 564 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for 565 // unified lock. 566 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 567 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id); 568 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 569 // Only possible when it's upgraded from nyc dp3 570 Slog.i(TAG, "Migrated tied profile lock type"); 571 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 572 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id); 573 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) { 574 // It should not happen 575 Slog.e(TAG, "Invalid tied profile lock type: " + quality); 576 } 577 } 578 try { 579 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id; 580 java.security.KeyStore keyStore = 581 java.security.KeyStore.getInstance("AndroidKeyStore"); 582 keyStore.load(null); 583 if (keyStore.containsAlias(alias)) { 584 keyStore.deleteEntry(alias); 585 } 586 } catch (KeyStoreException | NoSuchAlgorithmException | 587 CertificateException | IOException e) { 588 Slog.e(TAG, "Unable to remove tied profile key", e); 589 } 590 } 591 592 boolean isWatch = mContext.getPackageManager().hasSystemFeature( 593 PackageManager.FEATURE_WATCH); 594 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts 595 // and device management the lockscreen must be re-enabled now for users that upgrade. 596 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) { 597 final int userCount = users.size(); 598 for (int i = 0; i < userCount; i++) { 599 int id = users.get(i).id; 600 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id); 601 } 602 setString("migrated_wear_lockscreen_disabled", "true", 0); 603 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices"); 604 } 605 } catch (RemoteException re) { 606 Slog.e(TAG, "Unable to migrate old data", re); 607 } 608 } 609 610 private final void checkWritePermission(int userId) { 611 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite"); 612 } 613 614 private final void checkPasswordReadPermission(int userId) { 615 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead"); 616 } 617 618 private final void checkReadPermission(String requestedKey, int userId) { 619 final int callingUid = Binder.getCallingUid(); 620 621 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) { 622 String key = READ_CONTACTS_PROTECTED_SETTINGS[i]; 623 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS) 624 != PackageManager.PERMISSION_GRANTED) { 625 throw new SecurityException("uid=" + callingUid 626 + " needs permission " + READ_CONTACTS + " to read " 627 + requestedKey + " for user " + userId); 628 } 629 } 630 631 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) { 632 String key = READ_PASSWORD_PROTECTED_SETTINGS[i]; 633 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION) 634 != PackageManager.PERMISSION_GRANTED) { 635 throw new SecurityException("uid=" + callingUid 636 + " needs permission " + PERMISSION + " to read " 637 + requestedKey + " for user " + userId); 638 } 639 } 640 } 641 642 @Override 643 public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException { 644 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId); 645 synchronized (mSeparateChallengeLock) { 646 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); 647 } 648 } 649 650 @Override 651 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled, 652 String managedUserPassword) throws RemoteException { 653 checkWritePermission(userId); 654 synchronized (mSeparateChallengeLock) { 655 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId); 656 if (enabled) { 657 mStorage.removeChildProfileLock(userId); 658 removeKeystoreProfileKey(userId); 659 } else { 660 tieManagedProfileLockIfNecessary(userId, managedUserPassword); 661 } 662 } 663 } 664 665 @Override 666 public void setBoolean(String key, boolean value, int userId) throws RemoteException { 667 checkWritePermission(userId); 668 setStringUnchecked(key, userId, value ? "1" : "0"); 669 } 670 671 @Override 672 public void setLong(String key, long value, int userId) throws RemoteException { 673 checkWritePermission(userId); 674 setStringUnchecked(key, userId, Long.toString(value)); 675 } 676 677 @Override 678 public void setString(String key, String value, int userId) throws RemoteException { 679 checkWritePermission(userId); 680 setStringUnchecked(key, userId, value); 681 } 682 683 private void setStringUnchecked(String key, int userId, String value) { 684 mStorage.writeKeyValue(key, value, userId); 685 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) { 686 BackupManager.dataChanged("com.android.providers.settings"); 687 } 688 } 689 690 @Override 691 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { 692 checkReadPermission(key, userId); 693 String value = getStringUnchecked(key, null, userId); 694 return TextUtils.isEmpty(value) ? 695 defaultValue : (value.equals("1") || value.equals("true")); 696 } 697 698 @Override 699 public long getLong(String key, long defaultValue, int userId) throws RemoteException { 700 checkReadPermission(key, userId); 701 String value = getStringUnchecked(key, null, userId); 702 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); 703 } 704 705 @Override 706 public String getString(String key, String defaultValue, int userId) throws RemoteException { 707 checkReadPermission(key, userId); 708 return getStringUnchecked(key, defaultValue, userId); 709 } 710 711 public String getStringUnchecked(String key, String defaultValue, int userId) { 712 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) { 713 long ident = Binder.clearCallingIdentity(); 714 try { 715 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0"; 716 } finally { 717 Binder.restoreCallingIdentity(ident); 718 } 719 } 720 721 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) { 722 key = Settings.Secure.LOCK_PATTERN_ENABLED; 723 } 724 725 return mStorage.readKeyValue(key, defaultValue, userId); 726 } 727 728 @Override 729 public boolean havePassword(int userId) throws RemoteException { 730 // Do we need a permissions check here? 731 return mStorage.hasPassword(userId); 732 } 733 734 @Override 735 public boolean havePattern(int userId) throws RemoteException { 736 // Do we need a permissions check here? 737 return mStorage.hasPattern(userId); 738 } 739 740 private void setKeystorePassword(String password, int userHandle) { 741 final KeyStore ks = KeyStore.getInstance(); 742 ks.onUserPasswordChanged(userHandle, password); 743 } 744 745 private void unlockKeystore(String password, int userHandle) { 746 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); 747 final KeyStore ks = KeyStore.getInstance(); 748 ks.unlock(userHandle, password); 749 } 750 751 private String getDecryptedPasswordForTiedProfile(int userId) 752 throws KeyStoreException, UnrecoverableKeyException, 753 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, 754 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, 755 CertificateException, IOException { 756 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key"); 757 byte[] storedData = mStorage.readChildProfileLock(userId); 758 if (storedData == null) { 759 throw new FileNotFoundException("Child profile lock file not found"); 760 } 761 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE); 762 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE, 763 storedData.length); 764 byte[] decryptionResult; 765 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); 766 keyStore.load(null); 767 SecretKey decryptionKey = (SecretKey) keyStore.getKey( 768 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null); 769 770 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" 771 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); 772 773 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv)); 774 decryptionResult = cipher.doFinal(encryptedPassword); 775 return new String(decryptionResult, StandardCharsets.UTF_8); 776 } 777 778 private void unlockChildProfile(int profileHandle) throws RemoteException { 779 try { 780 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), 781 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 782 false, 0 /* no challenge */, profileHandle, null /* progressCallback */); 783 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 784 | NoSuchAlgorithmException | NoSuchPaddingException 785 | InvalidAlgorithmParameterException | IllegalBlockSizeException 786 | BadPaddingException | CertificateException | IOException e) { 787 if (e instanceof FileNotFoundException) { 788 Slog.i(TAG, "Child profile key not found"); 789 } else { 790 Slog.e(TAG, "Failed to decrypt child profile key", e); 791 } 792 } 793 } 794 795 private void unlockUser(int userId, byte[] token, byte[] secret) { 796 // TODO: make this method fully async so we can update UI with progress strings 797 final CountDownLatch latch = new CountDownLatch(1); 798 final IProgressListener listener = new IProgressListener.Stub() { 799 @Override 800 public void onStarted(int id, Bundle extras) throws RemoteException { 801 Log.d(TAG, "unlockUser started"); 802 } 803 804 @Override 805 public void onProgress(int id, int progress, Bundle extras) throws RemoteException { 806 Log.d(TAG, "unlockUser progress " + progress); 807 } 808 809 @Override 810 public void onFinished(int id, Bundle extras) throws RemoteException { 811 Log.d(TAG, "unlockUser finished"); 812 latch.countDown(); 813 } 814 }; 815 816 try { 817 ActivityManager.getService().unlockUser(userId, token, secret, listener); 818 } catch (RemoteException e) { 819 throw e.rethrowAsRuntimeException(); 820 } 821 822 try { 823 latch.await(15, TimeUnit.SECONDS); 824 } catch (InterruptedException e) { 825 Thread.currentThread().interrupt(); 826 } 827 try { 828 if (!mUserManager.getUserInfo(userId).isManagedProfile()) { 829 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 830 for (UserInfo pi : profiles) { 831 // Unlock managed profile with unified lock 832 if (pi.isManagedProfile() 833 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id) 834 && mStorage.hasChildProfileLock(pi.id)) { 835 unlockChildProfile(pi.id); 836 } 837 } 838 } 839 } catch (RemoteException e) { 840 Log.d(TAG, "Failed to unlock child profile", e); 841 } 842 } 843 844 private byte[] getCurrentHandle(int userId) { 845 CredentialHash credential = mStorage.readCredentialHash(userId); 846 847 // sanity check 848 if (credential.type != LockPatternUtils.CREDENTIAL_TYPE_NONE && credential.hash == null) { 849 Slog.e(TAG, "Stored handle type [" + credential.type + "] but no handle available"); 850 } 851 return credential.hash; 852 } 853 854 private void onUserLockChanged(int userId) throws RemoteException { 855 if (mUserManager.getUserInfo(userId).isManagedProfile()) { 856 return; 857 } 858 final boolean isSecure = mStorage.hasPassword(userId) || mStorage.hasPattern(userId); 859 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 860 final int size = profiles.size(); 861 for (int i = 0; i < size; i++) { 862 final UserInfo profile = profiles.get(i); 863 if (profile.isManagedProfile()) { 864 final int managedUserId = profile.id; 865 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) { 866 continue; 867 } 868 if (isSecure) { 869 tieManagedProfileLockIfNecessary(managedUserId, null); 870 } else { 871 clearUserKeyProtection(managedUserId); 872 getGateKeeperService().clearSecureUserId(managedUserId); 873 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), managedUserId); 874 setKeystorePassword(null, managedUserId); 875 fixateNewestUserKeyAuth(managedUserId); 876 mStorage.removeChildProfileLock(managedUserId); 877 removeKeystoreProfileKey(managedUserId); 878 } 879 } 880 } 881 } 882 883 private boolean isManagedProfileWithUnifiedLock(int userId) { 884 return mUserManager.getUserInfo(userId).isManagedProfile() 885 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId); 886 } 887 888 private boolean isManagedProfileWithSeparatedLock(int userId) { 889 return mUserManager.getUserInfo(userId).isManagedProfile() 890 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId); 891 } 892 893 // This method should be called by LockPatternUtil only, all internal methods in this class 894 // should call setLockCredentialInternal. 895 @Override 896 public void setLockCredential(String credential, int type, String savedCredential, int userId) 897 throws RemoteException { 898 checkWritePermission(userId); 899 synchronized (mSeparateChallengeLock) { 900 setLockCredentialInternal(credential, type, savedCredential, userId); 901 setSeparateProfileChallengeEnabled(userId, true, null); 902 notifyPasswordChanged(userId); 903 } 904 } 905 906 private void setLockCredentialInternal(String credential, int credentialType, 907 String savedCredential, int userId) throws RemoteException { 908 byte[] currentHandle = getCurrentHandle(userId); 909 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { 910 if (credential != null) { 911 Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); 912 } 913 clearUserKeyProtection(userId); 914 getGateKeeperService().clearSecureUserId(userId); 915 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); 916 setKeystorePassword(null, userId); 917 fixateNewestUserKeyAuth(userId); 918 onUserLockChanged(userId); 919 notifyActivePasswordMetricsAvailable(null, userId); 920 return; 921 } 922 if (credential == null) { 923 throw new RemoteException("Null credential with mismatched credential type"); 924 } 925 if (isManagedProfileWithUnifiedLock(userId)) { 926 // get credential from keystore when managed profile has unified lock 927 try { 928 savedCredential = getDecryptedPasswordForTiedProfile(userId); 929 } catch (FileNotFoundException e) { 930 Slog.i(TAG, "Child profile key not found"); 931 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 932 | NoSuchAlgorithmException | NoSuchPaddingException 933 | InvalidAlgorithmParameterException | IllegalBlockSizeException 934 | BadPaddingException | CertificateException | IOException e) { 935 Slog.e(TAG, "Failed to decrypt child profile key", e); 936 } 937 } else { 938 if (currentHandle == null) { 939 if (savedCredential != null) { 940 Slog.w(TAG, "Saved credential provided, but none stored"); 941 } 942 savedCredential = null; 943 } 944 } 945 946 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, credential, 947 userId); 948 if (enrolledHandle != null) { 949 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType); 950 mStorage.writeCredentialHash(willStore, userId); 951 // Refresh the auth token 952 setUserKeyProtection(userId, credential, 953 doVerifyCredential(credential, credentialType, true, 0, userId, 954 null /* progressCallback */)); 955 fixateNewestUserKeyAuth(userId); 956 onUserLockChanged(userId); 957 } else { 958 throw new RemoteException("Failed to enroll " + 959 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password" 960 : "pattern")); 961 } 962 } 963 964 private void tieProfileLockToParent(int userId, String password) { 965 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId); 966 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8); 967 byte[] encryptionResult; 968 byte[] iv; 969 try { 970 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); 971 keyGenerator.init(new SecureRandom()); 972 SecretKey secretKey = keyGenerator.generateKey(); 973 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); 974 keyStore.load(null); 975 try { 976 keyStore.setEntry( 977 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, 978 new java.security.KeyStore.SecretKeyEntry(secretKey), 979 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) 980 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 981 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 982 .build()); 983 keyStore.setEntry( 984 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, 985 new java.security.KeyStore.SecretKeyEntry(secretKey), 986 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) 987 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 988 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 989 .setUserAuthenticationRequired(true) 990 .setUserAuthenticationValidityDurationSeconds(30) 991 .build()); 992 // Key imported, obtain a reference to it. 993 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey( 994 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null); 995 Cipher cipher = Cipher.getInstance( 996 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" 997 + KeyProperties.ENCRYPTION_PADDING_NONE); 998 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey); 999 encryptionResult = cipher.doFinal(randomLockSeed); 1000 iv = cipher.getIV(); 1001 } finally { 1002 // The original key can now be discarded. 1003 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId); 1004 } 1005 } catch (CertificateException | UnrecoverableKeyException 1006 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException 1007 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { 1008 throw new RuntimeException("Failed to encrypt key", e); 1009 } 1010 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 1011 try { 1012 if (iv.length != PROFILE_KEY_IV_SIZE) { 1013 throw new RuntimeException("Invalid iv length: " + iv.length); 1014 } 1015 outputStream.write(iv); 1016 outputStream.write(encryptionResult); 1017 } catch (IOException e) { 1018 throw new RuntimeException("Failed to concatenate byte arrays", e); 1019 } 1020 mStorage.writeChildProfileLock(userId, outputStream.toByteArray()); 1021 } 1022 1023 private byte[] enrollCredential(byte[] enrolledHandle, 1024 String enrolledCredential, String toEnroll, int userId) 1025 throws RemoteException { 1026 checkWritePermission(userId); 1027 byte[] enrolledCredentialBytes = enrolledCredential == null 1028 ? null 1029 : enrolledCredential.getBytes(); 1030 byte[] toEnrollBytes = toEnroll == null 1031 ? null 1032 : toEnroll.getBytes(); 1033 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle, 1034 enrolledCredentialBytes, toEnrollBytes); 1035 1036 if (response == null) { 1037 return null; 1038 } 1039 1040 byte[] hash = response.getPayload(); 1041 if (hash != null) { 1042 setKeystorePassword(toEnroll, userId); 1043 } else { 1044 // Should not happen 1045 Slog.e(TAG, "Throttled while enrolling a password"); 1046 } 1047 return hash; 1048 } 1049 1050 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr) 1051 throws RemoteException { 1052 if (vcr == null) { 1053 throw new RemoteException("Null response verifying a credential we just set"); 1054 } 1055 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { 1056 throw new RemoteException("Non-OK response verifying a credential we just set: " 1057 + vcr.getResponseCode()); 1058 } 1059 byte[] token = vcr.getPayload(); 1060 if (token == null) { 1061 throw new RemoteException("Empty payload verifying a credential we just set"); 1062 } 1063 addUserKeyAuth(userId, token, secretFromCredential(credential)); 1064 } 1065 1066 private void clearUserKeyProtection(int userId) throws RemoteException { 1067 addUserKeyAuth(userId, null, null); 1068 } 1069 1070 private static byte[] secretFromCredential(String credential) throws RemoteException { 1071 try { 1072 MessageDigest digest = MessageDigest.getInstance("SHA-512"); 1073 // Personalize the hash 1074 byte[] personalization = "Android FBE credential hash" 1075 .getBytes(StandardCharsets.UTF_8); 1076 // Pad it to the block size of the hash function 1077 personalization = Arrays.copyOf(personalization, 128); 1078 digest.update(personalization); 1079 digest.update(credential.getBytes(StandardCharsets.UTF_8)); 1080 return digest.digest(); 1081 } catch (NoSuchAlgorithmException e) { 1082 throw new RuntimeException("NoSuchAlgorithmException for SHA-512"); 1083 } 1084 } 1085 1086 private void addUserKeyAuth(int userId, byte[] token, byte[] secret) 1087 throws RemoteException { 1088 final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId); 1089 final IStorageManager storageManager = getStorageManager(); 1090 final long callingId = Binder.clearCallingIdentity(); 1091 try { 1092 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret); 1093 } finally { 1094 Binder.restoreCallingIdentity(callingId); 1095 } 1096 } 1097 1098 private void fixateNewestUserKeyAuth(int userId) 1099 throws RemoteException { 1100 final IStorageManager storageManager = getStorageManager(); 1101 final long callingId = Binder.clearCallingIdentity(); 1102 try { 1103 storageManager.fixateNewestUserKeyAuth(userId); 1104 } finally { 1105 Binder.restoreCallingIdentity(callingId); 1106 } 1107 } 1108 1109 @Override 1110 public void resetKeyStore(int userId) throws RemoteException { 1111 checkWritePermission(userId); 1112 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); 1113 int managedUserId = -1; 1114 String managedUserDecryptedPassword = null; 1115 final List<UserInfo> profiles = mUserManager.getProfiles(userId); 1116 for (UserInfo pi : profiles) { 1117 // Unlock managed profile with unified lock 1118 if (pi.isManagedProfile() 1119 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id) 1120 && mStorage.hasChildProfileLock(pi.id)) { 1121 try { 1122 if (managedUserId == -1) { 1123 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id); 1124 managedUserId = pi.id; 1125 } else { 1126 // Should not happen 1127 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId 1128 + ", uid2:" + pi.id); 1129 } 1130 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 1131 | NoSuchAlgorithmException | NoSuchPaddingException 1132 | InvalidAlgorithmParameterException | IllegalBlockSizeException 1133 | BadPaddingException | CertificateException | IOException e) { 1134 Slog.e(TAG, "Failed to decrypt child profile key", e); 1135 } 1136 } 1137 } 1138 try { 1139 // Clear all the users credentials could have been installed in for this user. 1140 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) { 1141 for (int uid : SYSTEM_CREDENTIAL_UIDS) { 1142 mKeyStore.clearUid(UserHandle.getUid(profileId, uid)); 1143 } 1144 } 1145 } finally { 1146 if (managedUserId != -1 && managedUserDecryptedPassword != null) { 1147 if (DEBUG) Slog.v(TAG, "Restore tied profile lock"); 1148 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); 1149 } 1150 } 1151 } 1152 1153 @Override 1154 public VerifyCredentialResponse checkCredential(String credential, int type, int userId, 1155 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1156 checkPasswordReadPermission(userId); 1157 return doVerifyCredential(credential, type, false, 0, userId, progressCallback); 1158 } 1159 1160 @Override 1161 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge, 1162 int userId) throws RemoteException { 1163 checkPasswordReadPermission(userId); 1164 return doVerifyCredential(credential, type, true, challenge, userId, 1165 null /* progressCallback */); 1166 } 1167 1168 /** 1169 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero 1170 * format. 1171 */ 1172 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType, 1173 boolean hasChallenge, long challenge, int userId, 1174 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1175 if (TextUtils.isEmpty(credential)) { 1176 throw new IllegalArgumentException("Credential can't be null or empty"); 1177 } 1178 1179 CredentialHash storedHash = mStorage.readCredentialHash(userId); 1180 if (storedHash.type != credentialType) { 1181 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??" 1182 + " stored: " + storedHash.type + " passed in: " + credentialType); 1183 return VerifyCredentialResponse.ERROR; 1184 } 1185 1186 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN 1187 && storedHash.isBaseZeroPattern; 1188 1189 String credentialToVerify; 1190 if (shouldReEnrollBaseZero) { 1191 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential); 1192 } else { 1193 credentialToVerify = credential; 1194 } 1195 1196 VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify, 1197 hasChallenge, challenge, progressCallback); 1198 1199 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK 1200 && shouldReEnrollBaseZero) { 1201 setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId); 1202 } 1203 1204 return response; 1205 } 1206 1207 @Override 1208 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, 1209 long challenge, int userId) throws RemoteException { 1210 checkPasswordReadPermission(userId); 1211 if (!isManagedProfileWithUnifiedLock(userId)) { 1212 throw new RemoteException("User id must be managed profile with unified lock"); 1213 } 1214 final int parentProfileId = mUserManager.getProfileParent(userId).id; 1215 // Unlock parent by using parent's challenge 1216 final VerifyCredentialResponse parentResponse = doVerifyCredential( 1217 credential, 1218 type, 1219 true /* hasChallenge */, 1220 challenge, 1221 parentProfileId, 1222 null /* progressCallback */); 1223 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { 1224 // Failed, just return parent's response 1225 return parentResponse; 1226 } 1227 1228 try { 1229 // Unlock work profile, and work profile with unified lock must use password only 1230 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), 1231 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 1232 true, 1233 challenge, 1234 userId, null /* progressCallback */); 1235 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException 1236 | NoSuchAlgorithmException | NoSuchPaddingException 1237 | InvalidAlgorithmParameterException | IllegalBlockSizeException 1238 | BadPaddingException | CertificateException | IOException e) { 1239 Slog.e(TAG, "Failed to decrypt child profile key", e); 1240 throw new RemoteException("Unable to get tied profile token"); 1241 } 1242 } 1243 1244 /** 1245 * Lowest-level credential verification routine that talks to GateKeeper. If verification 1246 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy 1247 * hash to GK. 1248 */ 1249 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, 1250 String credential, boolean hasChallenge, long challenge, 1251 ICheckCredentialProgressCallback progressCallback) throws RemoteException { 1252 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) { 1253 // don't need to pass empty credentials to GateKeeper 1254 return VerifyCredentialResponse.OK; 1255 } 1256 1257 if (TextUtils.isEmpty(credential)) { 1258 return VerifyCredentialResponse.ERROR; 1259 } 1260 1261 // We're potentially going to be doing a bunch of disk I/O below as part 1262 // of unlocking the user, so yell if calling from the main thread. 1263 StrictMode.noteDiskRead(); 1264 1265 if (storedHash.version == CredentialHash.VERSION_LEGACY) { 1266 final byte[] hash; 1267 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { 1268 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential)); 1269 } else { 1270 hash = mLockPatternUtils.passwordToHash(credential, userId); 1271 } 1272 if (Arrays.equals(hash, storedHash.hash)) { 1273 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { 1274 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId); 1275 } else { 1276 unlockKeystore(credential, userId); 1277 } 1278 // Users with legacy credentials don't have credential-backed 1279 // FBE keys, so just pass through a fake token/secret 1280 Slog.i(TAG, "Unlocking user with fake token: " + userId); 1281 final byte[] fakeToken = String.valueOf(userId).getBytes(); 1282 unlockUser(userId, fakeToken, fakeToken); 1283 1284 // migrate credential to GateKeeper 1285 setLockCredentialInternal(credential, storedHash.type, null, userId); 1286 if (!hasChallenge) { 1287 notifyActivePasswordMetricsAvailable(credential, userId); 1288 return VerifyCredentialResponse.OK; 1289 } 1290 // Fall through to get the auth token. Technically this should never happen, 1291 // as a user that had a legacy credential would have to unlock their device 1292 // before getting to a flow with a challenge, but supporting for consistency. 1293 } else { 1294 return VerifyCredentialResponse.ERROR; 1295 } 1296 } 1297 1298 VerifyCredentialResponse response; 1299 boolean shouldReEnroll = false; 1300 GateKeeperResponse gateKeeperResponse = getGateKeeperService() 1301 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes()); 1302 int responseCode = gateKeeperResponse.getResponseCode(); 1303 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { 1304 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout()); 1305 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) { 1306 byte[] token = gateKeeperResponse.getPayload(); 1307 if (token == null) { 1308 // something's wrong if there's no payload with a challenge 1309 Slog.e(TAG, "verifyChallenge response had no associated payload"); 1310 response = VerifyCredentialResponse.ERROR; 1311 } else { 1312 shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); 1313 response = new VerifyCredentialResponse(token); 1314 } 1315 } else { 1316 response = VerifyCredentialResponse.ERROR; 1317 } 1318 1319 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 1320 1321 // credential has matched 1322 1323 if (progressCallback != null) { 1324 progressCallback.onCredentialVerified(); 1325 } 1326 notifyActivePasswordMetricsAvailable(credential, userId); 1327 unlockKeystore(credential, userId); 1328 1329 Slog.i(TAG, "Unlocking user " + userId + 1330 " with token length " + response.getPayload().length); 1331 unlockUser(userId, response.getPayload(), secretFromCredential(credential)); 1332 1333 if (isManagedProfileWithSeparatedLock(userId)) { 1334 TrustManager trustManager = 1335 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); 1336 trustManager.setDeviceLockedForUser(userId, false); 1337 } 1338 if (shouldReEnroll) { 1339 setLockCredentialInternal(credential, storedHash.type, credential, userId); 1340 } 1341 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { 1342 if (response.getTimeout() > 0) { 1343 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId); 1344 } 1345 } 1346 1347 return response; 1348 } 1349 1350 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) { 1351 final PasswordMetrics metrics; 1352 if (password == null) { 1353 metrics = new PasswordMetrics(); 1354 } else { 1355 metrics = PasswordMetrics.computeForPassword(password); 1356 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); 1357 } 1358 1359 // Asynchronous to avoid dead lock 1360 mHandler.post(() -> { 1361 DevicePolicyManager dpm = (DevicePolicyManager) 1362 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 1363 dpm.setActivePasswordState(metrics, userId); 1364 }); 1365 } 1366 1367 /** 1368 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before 1369 * reporting the password changed. 1370 */ 1371 private void notifyPasswordChanged(@UserIdInt int userId) { 1372 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering 1373 mHandler.post(() -> { 1374 DevicePolicyManager dpm = (DevicePolicyManager) 1375 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 1376 dpm.reportPasswordChanged(userId); 1377 }); 1378 } 1379 1380 @Override 1381 public boolean checkVoldPassword(int userId) throws RemoteException { 1382 if (!mFirstCallToVold) { 1383 return false; 1384 } 1385 mFirstCallToVold = false; 1386 1387 checkPasswordReadPermission(userId); 1388 1389 // There's no guarantee that this will safely connect, but if it fails 1390 // we will simply show the lock screen when we shouldn't, so relatively 1391 // benign. There is an outside chance something nasty would happen if 1392 // this service restarted before vold stales out the password in this 1393 // case. The nastiness is limited to not showing the lock screen when 1394 // we should, within the first minute of decrypting the phone if this 1395 // service can't connect to vold, it restarts, and then the new instance 1396 // does successfully connect. 1397 final IStorageManager service = getStorageManager(); 1398 String password; 1399 long identity = Binder.clearCallingIdentity(); 1400 try { 1401 password = service.getPassword(); 1402 service.clearPassword(); 1403 } finally { 1404 Binder.restoreCallingIdentity(identity); 1405 } 1406 if (password == null) { 1407 return false; 1408 } 1409 1410 try { 1411 if (mLockPatternUtils.isLockPatternEnabled(userId)) { 1412 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId, 1413 null /* progressCallback */) 1414 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { 1415 return true; 1416 } 1417 } 1418 } catch (Exception e) { 1419 } 1420 1421 try { 1422 if (mLockPatternUtils.isLockPasswordEnabled(userId)) { 1423 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId, 1424 null /* progressCallback */) 1425 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { 1426 return true; 1427 } 1428 } 1429 } catch (Exception e) { 1430 } 1431 1432 return false; 1433 } 1434 1435 private void removeUser(int userId, boolean unknownUser) { 1436 mStorage.removeUser(userId); 1437 mStrongAuth.removeUser(userId); 1438 1439 final KeyStore ks = KeyStore.getInstance(); 1440 ks.onUserRemoved(userId); 1441 1442 try { 1443 final IGateKeeperService gk = getGateKeeperService(); 1444 if (gk != null) { 1445 gk.clearSecureUserId(userId); 1446 } 1447 } catch (RemoteException ex) { 1448 Slog.w(TAG, "unable to clear GK secure user id"); 1449 } 1450 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) { 1451 removeKeystoreProfileKey(userId); 1452 } 1453 } 1454 1455 private void removeKeystoreProfileKey(int targetUserId) { 1456 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId); 1457 try { 1458 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); 1459 keyStore.load(null); 1460 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId); 1461 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId); 1462 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException 1463 | IOException e) { 1464 // We have tried our best to remove all keys 1465 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e); 1466 } 1467 } 1468 1469 @Override 1470 public void registerStrongAuthTracker(IStrongAuthTracker tracker) { 1471 checkPasswordReadPermission(UserHandle.USER_ALL); 1472 mStrongAuth.registerStrongAuthTracker(tracker); 1473 } 1474 1475 @Override 1476 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) { 1477 checkPasswordReadPermission(UserHandle.USER_ALL); 1478 mStrongAuth.unregisterStrongAuthTracker(tracker); 1479 } 1480 1481 @Override 1482 public void requireStrongAuth(int strongAuthReason, int userId) { 1483 checkWritePermission(userId); 1484 mStrongAuth.requireStrongAuth(strongAuthReason, userId); 1485 } 1486 1487 @Override 1488 public void userPresent(int userId) { 1489 checkWritePermission(userId); 1490 mStrongAuth.reportUnlock(userId); 1491 } 1492 1493 @Override 1494 public int getStrongAuthForUser(int userId) { 1495 checkPasswordReadPermission(userId); 1496 return mStrongAuthTracker.getStrongAuthForUser(userId); 1497 } 1498 1499 private boolean isCallerShell() { 1500 final int callingUid = Binder.getCallingUid(); 1501 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID; 1502 } 1503 1504 private void enforceShell() { 1505 if (!isCallerShell()) { 1506 throw new SecurityException("Caller must be shell"); 1507 } 1508 } 1509 1510 @Override 1511 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1512 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 1513 throws RemoteException { 1514 enforceShell(); 1515 final long origId = Binder.clearCallingIdentity(); 1516 try { 1517 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec( 1518 this, in, out, err, args, callback, resultReceiver); 1519 } finally { 1520 Binder.restoreCallingIdentity(origId); 1521 } 1522 } 1523 1524 private static final String[] VALID_SETTINGS = new String[] { 1525 LockPatternUtils.LOCKOUT_PERMANENT_KEY, 1526 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, 1527 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, 1528 LockPatternUtils.PASSWORD_TYPE_KEY, 1529 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 1530 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 1531 LockPatternUtils.DISABLE_LOCKSCREEN_KEY, 1532 LockPatternUtils.LOCKSCREEN_OPTIONS, 1533 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, 1534 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY, 1535 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, 1536 LockPatternUtils.PASSWORD_HISTORY_KEY, 1537 Secure.LOCK_PATTERN_ENABLED, 1538 Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 1539 Secure.LOCK_PATTERN_VISIBLE, 1540 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED 1541 }; 1542 1543 // Reading these settings needs the contacts permission 1544 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] { 1545 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1546 Secure.LOCK_SCREEN_OWNER_INFO 1547 }; 1548 1549 // Reading these settings needs the same permission as checking the password 1550 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] { 1551 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 1552 LockPatternUtils.PASSWORD_HISTORY_KEY, 1553 LockPatternUtils.PASSWORD_TYPE_KEY, 1554 SEPARATE_PROFILE_CHALLENGE_KEY 1555 }; 1556 1557 private static final String[] SETTINGS_TO_BACKUP = new String[] { 1558 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1559 Secure.LOCK_SCREEN_OWNER_INFO 1560 }; 1561 1562 private IStorageManager getStorageManager() { 1563 final IBinder service = ServiceManager.getService("mount"); 1564 if (service != null) { 1565 return IStorageManager.Stub.asInterface(service); 1566 } 1567 return null; 1568 } 1569 1570 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient { 1571 @Override 1572 public void binderDied() { 1573 mGateKeeperService.asBinder().unlinkToDeath(this, 0); 1574 mGateKeeperService = null; 1575 } 1576 } 1577 1578 private synchronized IGateKeeperService getGateKeeperService() 1579 throws RemoteException { 1580 if (mGateKeeperService != null) { 1581 return mGateKeeperService; 1582 } 1583 1584 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE); 1585 if (service != null) { 1586 service.linkToDeath(new GateKeeperDiedRecipient(), 0); 1587 mGateKeeperService = IGateKeeperService.Stub.asInterface(service); 1588 return mGateKeeperService; 1589 } 1590 1591 Slog.e(TAG, "Unable to acquire GateKeeperService"); 1592 return null; 1593 } 1594} 1595