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