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