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