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