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