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