Home | History | Annotate | Download | only in server
      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.ILockSettings;
     73 import com.android.internal.widget.LockPatternUtils;
     74 import com.android.internal.widget.VerifyCredentialResponse;
     75 import com.android.server.LockSettingsStorage.CredentialHash;
     76 
     77 import libcore.util.HexEncoding;
     78 
     79 import java.io.ByteArrayOutputStream;
     80 import java.io.FileNotFoundException;
     81 import java.io.IOException;
     82 import java.nio.charset.StandardCharsets;
     83 import java.security.InvalidAlgorithmParameterException;
     84 import java.security.InvalidKeyException;
     85 import java.security.KeyStoreException;
     86 import java.security.MessageDigest;
     87 import java.security.NoSuchAlgorithmException;
     88 import java.security.SecureRandom;
     89 import java.security.UnrecoverableKeyException;
     90 import java.security.cert.CertificateException;
     91 import java.util.Arrays;
     92 import java.util.List;
     93 import java.util.concurrent.CountDownLatch;
     94 import java.util.concurrent.TimeUnit;
     95 
     96 import javax.crypto.BadPaddingException;
     97 import javax.crypto.Cipher;
     98 import javax.crypto.IllegalBlockSizeException;
     99 import javax.crypto.KeyGenerator;
    100 import javax.crypto.NoSuchPaddingException;
    101 import javax.crypto.SecretKey;
    102 import 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  */
    110 public 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