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