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