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