blob: 6deff3652944652c0e7bc77aec7a006ae9d3598c [file] [log] [blame]
Amith Yamasani52c489c2012-03-28 11:42:42 -07001/*
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
Andrew Scull507d11c2017-05-03 17:19:01 +010017package com.android.server.locksettings;
Amith Yamasani52c489c2012-03-28 11:42:42 -070018
Rubin Xu1de89b32016-11-30 20:03:13 +000019import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
20import static android.Manifest.permission.READ_CONTACTS;
21import static android.content.Context.KEYGUARD_SERVICE;
Adrian Roosb953e182017-08-17 17:58:26 +020022import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Adrian Roos7374d3a2017-03-31 14:14:53 -070023
Rubin Xu1de89b32016-11-30 20:03:13 +000024import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
Rubin Xu3bf722a2016-12-15 16:07:38 +000025import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
26import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
Adrian Roos7374d3a2017-03-31 14:14:53 -070027import static com.android.internal.widget.LockPatternUtils.USER_FRP;
28import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
Adrian Roos454f53f2017-08-08 14:56:42 +020029import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
Rubin Xu1de89b32016-11-30 20:03:13 +000030
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080031import android.annotation.NonNull;
32import android.annotation.Nullable;
Andrew Scull5daf2732016-11-14 15:02:45 +000033import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080034import android.app.ActivityManager;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000035import android.app.IActivityManager;
Kenny Guyb1b30262016-02-09 16:02:35 +000036import android.app.KeyguardManager;
Jim Miller4f93c582016-01-27 19:05:43 -080037import android.app.Notification;
38import android.app.NotificationManager;
39import android.app.PendingIntent;
Adrian Roos230635e2015-01-07 20:50:29 +010040import android.app.admin.DevicePolicyManager;
Pavel Grafov28939982017-10-03 15:11:52 +010041import android.app.admin.DevicePolicyManagerInternal;
Andrew Scull5daf2732016-11-14 15:02:45 +000042import android.app.admin.PasswordMetrics;
Amith Yamasani072543f2015-02-13 11:09:45 -080043import android.app.backup.BackupManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070044import android.app.trust.IStrongAuthTracker;
Clara Bayarri56878a92015-10-29 15:43:55 +000045import android.app.trust.TrustManager;
Robin Leef0246a82014-08-13 09:50:25 +010046import android.content.BroadcastReceiver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070047import android.content.ContentResolver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070048import android.content.Context;
Robin Leef0246a82014-08-13 09:50:25 +010049import android.content.Intent;
50import android.content.IntentFilter;
Jim Miller158fe192013-04-17 15:23:55 -070051import android.content.pm.PackageManager;
Jim Miller187ec582013-04-15 18:27:54 -070052import android.content.pm.UserInfo;
Jim Miller4f93c582016-01-27 19:05:43 -080053import android.content.res.Resources;
Adrian Roos7374d3a2017-03-31 14:14:53 -070054import android.database.ContentObserver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070055import android.database.sqlite.SQLiteDatabase;
Andrew Sculle6527c12018-01-05 18:33:58 +000056import android.hardware.authsecret.V1_0.IAuthSecret;
Adrian Roos7374d3a2017-03-31 14:14:53 -070057import android.net.Uri;
Amith Yamasani52c489c2012-03-28 11:42:42 -070058import android.os.Binder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060059import android.os.Bundle;
Ricky Waib0cdf382016-05-16 17:28:04 +010060import android.os.Handler;
Paul Lawrence945490c2014-03-27 16:37:28 +000061import android.os.IBinder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060062import android.os.IProgressListener;
Ricky Wai4613fe42016-05-24 11:11:42 +010063import android.os.Process;
Amith Yamasani52c489c2012-03-28 11:42:42 -070064import android.os.RemoteException;
Jorim Jaggi2fef6f72016-11-01 19:06:25 -070065import android.os.ResultReceiver;
Paul Lawrence945490c2014-03-27 16:37:28 +000066import android.os.ServiceManager;
Rubin Xu1de89b32016-11-30 20:03:13 +000067import android.os.ShellCallback;
Jeff Sharkeyeddf5182016-08-09 16:36:08 -060068import android.os.StrictMode;
Amith Yamasanid1645f82012-06-12 11:53:26 -070069import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070070import android.os.UserHandle;
Jim Miller187ec582013-04-15 18:27:54 -070071import android.os.UserManager;
Rubin Xu1de89b32016-11-30 20:03:13 +000072import android.os.storage.IStorageManager;
73import android.os.storage.StorageManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -070074import android.provider.Settings;
75import android.provider.Settings.Secure;
Jim Miller187ec582013-04-15 18:27:54 -070076import android.provider.Settings.SettingNotFoundException;
Jim Millerde1af082013-09-11 14:58:26 -070077import android.security.KeyStore;
Ricky Waidc283a82016-03-24 19:55:08 +000078import android.security.keystore.AndroidKeyStoreProvider;
79import android.security.keystore.KeyProperties;
80import android.security.keystore.KeyProtection;
Pavel Grafov0acc4bf2017-08-23 12:20:54 +010081import android.security.keystore.UserNotAuthenticatedException;
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -080082import android.security.keystore.recovery.KeyChainProtectionParams;
Robert Berry81ee34b2018-01-23 11:59:59 +000083import android.security.keystore.recovery.WrappedApplicationKey;
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -080084import android.security.keystore.recovery.KeyChainSnapshot;
Andres Morales23974272015-05-14 22:42:26 -070085import android.service.gatekeeper.GateKeeperResponse;
Andres Morales8fa56652015-03-31 09:19:50 -070086import android.service.gatekeeper.IGateKeeperService;
Amith Yamasani52c489c2012-03-28 11:42:42 -070087import android.text.TextUtils;
Rubin Xua55b1682017-01-31 10:06:56 +000088import android.util.ArrayMap;
Adrian Roosb953e182017-08-17 17:58:26 +020089import android.util.EventLog;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060090import android.util.Log;
Amith Yamasani52c489c2012-03-28 11:42:42 -070091import android.util.Slog;
Andrew Scull1416bd02018-01-05 18:33:58 +000092import android.util.SparseArray;
Amith Yamasani52c489c2012-03-28 11:42:42 -070093
Pavel Grafov28939982017-10-03 15:11:52 +010094import com.android.internal.annotations.GuardedBy;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000095import com.android.internal.annotations.VisibleForTesting;
Chris Wren282cfef2017-03-27 15:01:44 -040096import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050097import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani072543f2015-02-13 11:09:45 -080098import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060099import com.android.internal.util.DumpUtils;
Adrian Roos7374d3a2017-03-31 14:14:53 -0700100import com.android.internal.util.Preconditions;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700101import com.android.internal.widget.ICheckCredentialProgressCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800102import com.android.internal.widget.ILockSettings;
103import com.android.internal.widget.LockPatternUtils;
Andres Morales23974272015-05-14 22:42:26 -0700104import com.android.internal.widget.VerifyCredentialResponse;
Pavel Grafov28939982017-10-03 15:11:52 +0100105import com.android.server.LocalServices;
Andrew Scull507d11c2017-05-03 17:19:01 +0100106import com.android.server.SystemService;
107import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800108import com.android.server.locksettings.LockSettingsStorage.PersistentData;
109import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
Andrew Scull507d11c2017-05-03 17:19:01 +0100110import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
111import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800112
Ricky Waidc283a82016-03-24 19:55:08 +0000113import libcore.util.HexEncoding;
114
115import java.io.ByteArrayOutputStream;
Jorim Jaggi2fef6f72016-11-01 19:06:25 -0700116import java.io.FileDescriptor;
Ricky Waidc283a82016-03-24 19:55:08 +0000117import java.io.FileNotFoundException;
118import java.io.IOException;
Rubin Xu3bf722a2016-12-15 16:07:38 +0000119import java.io.PrintWriter;
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000120import java.nio.charset.StandardCharsets;
Ricky Waidc283a82016-03-24 19:55:08 +0000121import java.security.InvalidAlgorithmParameterException;
122import java.security.InvalidKeyException;
123import java.security.KeyStoreException;
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000124import java.security.MessageDigest;
125import java.security.NoSuchAlgorithmException;
Ricky Waidc283a82016-03-24 19:55:08 +0000126import java.security.SecureRandom;
127import java.security.UnrecoverableKeyException;
128import java.security.cert.CertificateException;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700129import java.util.Arrays;
Andrew Sculle6527c12018-01-05 18:33:58 +0000130import java.util.ArrayList;
Jim Miller187ec582013-04-15 18:27:54 -0700131import java.util.List;
Rubin Xua55b1682017-01-31 10:06:56 +0000132import java.util.Map;
Andrew Sculle6527c12018-01-05 18:33:58 +0000133import java.util.NoSuchElementException;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600134import java.util.concurrent.CountDownLatch;
135import java.util.concurrent.TimeUnit;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700136
Ricky Waidc283a82016-03-24 19:55:08 +0000137import javax.crypto.BadPaddingException;
138import javax.crypto.Cipher;
139import javax.crypto.IllegalBlockSizeException;
140import javax.crypto.KeyGenerator;
141import javax.crypto.NoSuchPaddingException;
142import javax.crypto.SecretKey;
143import javax.crypto.spec.GCMParameterSpec;
144
Amith Yamasani52c489c2012-03-28 11:42:42 -0700145/**
Rubin Xu1de89b32016-11-30 20:03:13 +0000146 * Keeps the lock pattern/password data and related settings for each user. Used by
147 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
148 * lockscreen information for secondary users.
149 *
Amith Yamasani52c489c2012-03-28 11:42:42 -0700150 * @hide
151 */
152public class LockSettingsService extends ILockSettings.Stub {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700153 private static final String TAG = "LockSettingsService";
Jim Miller4f93c582016-01-27 19:05:43 -0800154 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
Jim Miller4f93c582016-01-27 19:05:43 -0800155 private static final boolean DEBUG = false;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700156
Ricky Waidc283a82016-03-24 19:55:08 +0000157 private static final int PROFILE_KEY_IV_SIZE = 12;
158 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
Paul Crowley7a0cc0a2017-05-31 22:12:57 +0000159 private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
Rubin Xu1de89b32016-11-30 20:03:13 +0000160
Rubin Xua0a0d352017-05-15 16:18:01 +0000161 // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
Rubin Xue94a7702017-06-20 17:29:57 +0100162 // Do not call into ActivityManager while holding mSpManager lock.
Ricky Waidc283a82016-03-24 19:55:08 +0000163 private final Object mSeparateChallengeLock = new Object();
164
Adrian Roos7374d3a2017-03-31 14:14:53 -0700165 private final DeviceProvisionedObserver mDeviceProvisionedObserver =
166 new DeviceProvisionedObserver();
167
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000168 private final Injector mInjector;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700169 private final Context mContext;
Rubin Xu7cf45092017-08-28 11:47:35 +0100170 @VisibleForTesting
171 protected final Handler mHandler;
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000172 @VisibleForTesting
173 protected final LockSettingsStorage mStorage;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -0800174 private final LockSettingsStrongAuth mStrongAuth;
Victor Changa0940d32016-05-16 19:36:08 +0100175 private final SynchronizedStrongAuthTracker mStrongAuthTracker;
Adrian Roos261d5ab2014-10-29 14:42:38 +0100176
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000177 private final LockPatternUtils mLockPatternUtils;
178 private final NotificationManager mNotificationManager;
179 private final UserManager mUserManager;
180 private final IActivityManager mActivityManager;
Andrew Scull8fc2ec82017-05-19 10:50:36 +0100181 private final SyntheticPasswordManager mSpManager;
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000182
183 private final KeyStore mKeyStore;
184
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800185 private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
186
Paul Lawrence945490c2014-03-27 16:37:28 +0000187 private boolean mFirstCallToVold;
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000188 protected IGateKeeperService mGateKeeperService;
Andrew Sculle6527c12018-01-05 18:33:58 +0000189 protected IAuthSecret mAuthSecretService;
Rubin Xu3bf722a2016-12-15 16:07:38 +0000190
Ricky Wai4613fe42016-05-24 11:11:42 +0100191 /**
192 * The UIDs that are used for system credential storage in keystore.
193 */
Rubin Xu1de89b32016-11-30 20:03:13 +0000194 private static final int[] SYSTEM_CREDENTIAL_UIDS = {
195 Process.WIFI_UID, Process.VPN_UID,
Rubin Xu24b89b12017-04-26 19:44:16 +0100196 Process.ROOT_UID, Process.SYSTEM_UID };
Andres Morales23974272015-05-14 22:42:26 -0700197
Jim Miller4f93c582016-01-27 19:05:43 -0800198 // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
199 // devices. The most basic of these is to show/hide notifications about missing features until
200 // the user unlocks the account and credential-encrypted storage is available.
201 public static final class Lifecycle extends SystemService {
202 private LockSettingsService mLockSettingsService;
203
204 public Lifecycle(Context context) {
205 super(context);
206 }
207
208 @Override
209 public void onStart() {
Ricky Waidc283a82016-03-24 19:55:08 +0000210 AndroidKeyStoreProvider.install();
Jim Miller4f93c582016-01-27 19:05:43 -0800211 mLockSettingsService = new LockSettingsService(getContext());
212 publishBinderService("lock_settings", mLockSettingsService);
213 }
214
215 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200216 public void onBootPhase(int phase) {
217 super.onBootPhase(phase);
218 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
219 mLockSettingsService.migrateOldDataAfterSystemReady();
220 }
221 }
222
223 @Override
Andrew Scull85a63bc2016-10-24 13:47:47 +0100224 public void onStartUser(int userHandle) {
225 mLockSettingsService.onStartUser(userHandle);
Jim Miller4f93c582016-01-27 19:05:43 -0800226 }
227
228 @Override
229 public void onUnlockUser(int userHandle) {
230 mLockSettingsService.onUnlockUser(userHandle);
231 }
232
233 @Override
234 public void onCleanupUser(int userHandle) {
235 mLockSettingsService.onCleanupUser(userHandle);
236 }
237 }
238
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000239 @VisibleForTesting
240 protected static class SynchronizedStrongAuthTracker
241 extends LockPatternUtils.StrongAuthTracker {
Victor Changa0940d32016-05-16 19:36:08 +0100242 public SynchronizedStrongAuthTracker(Context context) {
243 super(context);
244 }
245
246 @Override
247 protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
248 synchronized (this) {
249 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
250 }
251 }
252
253 @Override
254 public int getStrongAuthForUser(int userId) {
255 synchronized (this) {
256 return super.getStrongAuthForUser(userId);
257 }
258 }
259
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000260 void register(LockSettingsStrongAuth strongAuth) {
261 strongAuth.registerStrongAuthTracker(this.mStub);
Victor Changa0940d32016-05-16 19:36:08 +0100262 }
263 }
264
Ricky Waidc283a82016-03-24 19:55:08 +0000265 /**
266 * Tie managed profile to primary profile if it is in unified mode and not tied before.
267 *
268 * @param managedUserId Managed profile user Id
269 * @param managedUserPassword Managed profile original password (when it has separated lock).
270 * NULL when it does not have a separated lock before.
271 */
272 public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
273 if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
274 // Only for managed profile
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000275 if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
Ricky Waidc283a82016-03-24 19:55:08 +0000276 return;
277 }
278 // Do not tie managed profile when work challenge is enabled
279 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
280 return;
281 }
282 // Do not tie managed profile to parent when it's done already
283 if (mStorage.hasChildProfileLock(managedUserId)) {
284 return;
285 }
286 // Do not tie it to parent when parent does not have a screen lock
287 final int parentId = mUserManager.getProfileParent(managedUserId).id;
Rubin Xua55b1682017-01-31 10:06:56 +0000288 if (!isUserSecure(parentId)) {
Ricky Waidc283a82016-03-24 19:55:08 +0000289 if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
290 return;
291 }
Rubin Xubfc7faaf2016-11-22 15:18:32 +0000292 // Do not tie when the parent has no SID (but does have a screen lock).
293 // This can only happen during an upgrade path where SID is yet to be
294 // generated when the user unlocks for the first time.
295 try {
296 if (getGateKeeperService().getSecureUserId(parentId) == 0) {
297 return;
298 }
299 } catch (RemoteException e) {
300 Slog.e(TAG, "Failed to talk to GateKeeper service", e);
301 return;
302 }
Ricky Waidc283a82016-03-24 19:55:08 +0000303 if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
304 byte[] randomLockSeed = new byte[] {};
305 try {
306 randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
307 String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
Adrian Roos7374d3a2017-03-31 14:14:53 -0700308 final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Rubin Xu1de89b32016-11-30 20:03:13 +0000309 setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
Adrian Roos7374d3a2017-03-31 14:14:53 -0700310 managedUserPassword, quality, managedUserId);
Ricky Wai7b9eb412016-05-12 17:29:12 +0100311 // We store a private credential for the managed user that's unlocked by the primary
312 // account holder's credential. As such, the user will never be prompted to enter this
313 // password directly, so we always store a password.
Adrian Roos7374d3a2017-03-31 14:14:53 -0700314 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
Zach Jange61672a2016-11-22 17:47:18 +0000315 tieProfileLockToParent(managedUserId, newPassword);
Ricky Waidc283a82016-03-24 19:55:08 +0000316 } catch (NoSuchAlgorithmException | RemoteException e) {
317 Slog.e(TAG, "Fail to tie managed profile", e);
318 // Nothing client can do to fix this issue, so we do not throw exception out
319 }
320 }
321
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000322 static class Injector {
Jim Millerde1af082013-09-11 14:58:26 -0700323
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000324 protected Context mContext;
325
326 public Injector(Context context) {
327 mContext = context;
328 }
329
330 public Context getContext() {
331 return mContext;
332 }
333
334 public Handler getHandler() {
335 return new Handler();
336 }
337
338 public LockSettingsStorage getStorage() {
339 final LockSettingsStorage storage = new LockSettingsStorage(mContext);
340 storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
341 @Override
342 public void initialize(SQLiteDatabase db) {
343 // Get the lockscreen default from a system property, if available
344 boolean lockScreenDisable = SystemProperties.getBoolean(
345 "ro.lockscreen.disable.default", false);
346 if (lockScreenDisable) {
347 storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
348 }
349 }
350 });
351 return storage;
352 }
353
354 public LockSettingsStrongAuth getStrongAuth() {
355 return new LockSettingsStrongAuth(mContext);
356 }
357
358 public SynchronizedStrongAuthTracker getStrongAuthTracker() {
359 return new SynchronizedStrongAuthTracker(mContext);
360 }
361
362 public IActivityManager getActivityManager() {
363 return ActivityManager.getService();
364 }
365
366 public LockPatternUtils getLockPatternUtils() {
367 return new LockPatternUtils(mContext);
368 }
369
370 public NotificationManager getNotificationManager() {
371 return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
372 }
373
374 public UserManager getUserManager() {
375 return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
376 }
377
Rubin Xu8b30ec32017-03-05 00:47:09 +0000378 public DevicePolicyManager getDevicePolicyManager() {
379 return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
380 }
381
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000382 public KeyStore getKeyStore() {
383 return KeyStore.getInstance();
384 }
385
Dmitry Dementyev29b9de52018-01-31 16:09:32 -0800386 public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
387 return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800388 }
389
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000390 public IStorageManager getStorageManager() {
391 final IBinder service = ServiceManager.getService("mount");
392 if (service != null) {
393 return IStorageManager.Stub.asInterface(service);
394 }
395 return null;
396 }
Rubin Xu3bf722a2016-12-15 16:07:38 +0000397
398 public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200399 return new SyntheticPasswordManager(getContext(), storage, getUserManager());
Rubin Xu3bf722a2016-12-15 16:07:38 +0000400 }
401
402 public int binderGetCallingUid() {
403 return Binder.getCallingUid();
404 }
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000405 }
406
407 public LockSettingsService(Context context) {
408 this(new Injector(context));
409 }
410
411 @VisibleForTesting
412 protected LockSettingsService(Injector injector) {
413 mInjector = injector;
414 mContext = injector.getContext();
415 mKeyStore = injector.getKeyStore();
Dmitry Dementyev29b9de52018-01-31 16:09:32 -0800416 mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000417 mHandler = injector.getHandler();
418 mStrongAuth = injector.getStrongAuth();
419 mActivityManager = injector.getActivityManager();
420
421 mLockPatternUtils = injector.getLockPatternUtils();
Paul Lawrence945490c2014-03-27 16:37:28 +0000422 mFirstCallToVold = true;
Robin Leef0246a82014-08-13 09:50:25 +0100423
424 IntentFilter filter = new IntentFilter();
425 filter.addAction(Intent.ACTION_USER_ADDED);
Adrian Roos3dcae682014-10-29 14:43:56 +0100426 filter.addAction(Intent.ACTION_USER_STARTING);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100427 filter.addAction(Intent.ACTION_USER_REMOVED);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000428 injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
429 null, null);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100430
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000431 mStorage = injector.getStorage();
432 mNotificationManager = injector.getNotificationManager();
433 mUserManager = injector.getUserManager();
434 mStrongAuthTracker = injector.getStrongAuthTracker();
435 mStrongAuthTracker.register(mStrongAuth);
Rubin Xu3bf722a2016-12-15 16:07:38 +0000436
437 mSpManager = injector.getSyntheticPasswordManager(mStorage);
Jim Miller4f93c582016-01-27 19:05:43 -0800438 }
439
440 /**
Rubin Xu1de89b32016-11-30 20:03:13 +0000441 * If the account is credential-encrypted, show notification requesting the user to unlock the
442 * device.
Jim Miller4f93c582016-01-27 19:05:43 -0800443 */
Andrew Scull85a63bc2016-10-24 13:47:47 +0100444 private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
445 final UserInfo user = mUserManager.getUserInfo(userId);
446 if (!user.isManagedProfile()) {
447 // When the user is locked, we communicate it loud-and-clear
448 // on the lockscreen; we only show a notification below for
449 // locked managed profiles.
450 return;
451 }
452
453 final UserHandle userHandle = user.getUserHandle();
Rubin Xua55b1682017-01-31 10:06:56 +0000454 final boolean isSecure = isUserSecure(userId);
Andrew Scull85a63bc2016-10-24 13:47:47 +0100455 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
456 UserInfo parent = mUserManager.getProfileParent(userId);
457 if (parent != null &&
458 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
459 !mUserManager.isQuietModeEnabled(userHandle)) {
460 // Only show notifications for managed profiles once their parent
461 // user is unlocked.
462 showEncryptionNotificationForProfile(userHandle);
Jim Miller4f93c582016-01-27 19:05:43 -0800463 }
Jim Miller4f93c582016-01-27 19:05:43 -0800464 }
465 }
466
Kenny Guyb1b30262016-02-09 16:02:35 +0000467 private void showEncryptionNotificationForProfile(UserHandle user) {
468 Resources r = mContext.getResources();
469 CharSequence title = r.getText(
470 com.android.internal.R.string.user_encrypted_title);
471 CharSequence message = r.getText(
472 com.android.internal.R.string.profile_encrypted_message);
473 CharSequence detail = r.getText(
474 com.android.internal.R.string.profile_encrypted_detail);
475
476 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
Rubin Xu1de89b32016-11-30 20:03:13 +0000477 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
478 user.getIdentifier());
Kenny Guyb1b30262016-02-09 16:02:35 +0000479 if (unlockIntent == null) {
480 return;
481 }
Rubin Xu1de89b32016-11-30 20:03:13 +0000482 unlockIntent.setFlags(
483 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Kenny Guyb1b30262016-02-09 16:02:35 +0000484 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
485 PendingIntent.FLAG_UPDATE_CURRENT);
486
487 showEncryptionNotification(user, title, message, detail, intent);
488 }
489
Rubin Xu1de89b32016-11-30 20:03:13 +0000490 private void showEncryptionNotification(UserHandle user, CharSequence title,
491 CharSequence message, CharSequence detail, PendingIntent intent) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000492 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Jeff Sharkey4a399362016-05-26 09:47:43 -0600493
494 // Suppress all notifications on non-FBE devices for now
495 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
496
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500497 Notification notification =
498 new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
499 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
500 .setWhen(0)
501 .setOngoing(true)
502 .setTicker(title)
503 .setColor(mContext.getColor(
504 com.android.internal.R.color.system_notification_accent_color))
505 .setContentTitle(title)
506 .setContentText(message)
507 .setSubText(detail)
508 .setVisibility(Notification.VISIBILITY_PUBLIC)
509 .setContentIntent(intent)
510 .build();
Chris Wren282cfef2017-03-27 15:01:44 -0400511 mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
512 notification, user);
Jim Miller4f93c582016-01-27 19:05:43 -0800513 }
514
Andrew Scull85a63bc2016-10-24 13:47:47 +0100515 private void hideEncryptionNotification(UserHandle userHandle) {
Rubin Xu1de89b32016-11-30 20:03:13 +0000516 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
Chris Wren282cfef2017-03-27 15:01:44 -0400517 mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
518 userHandle);
Jim Miller4f93c582016-01-27 19:05:43 -0800519 }
520
521 public void onCleanupUser(int userId) {
522 hideEncryptionNotification(new UserHandle(userId));
523 }
524
Andrew Scull85a63bc2016-10-24 13:47:47 +0100525 public void onStartUser(final int userId) {
526 maybeShowEncryptionNotificationForUser(userId);
527 }
528
Pavel Grafov0acc4bf2017-08-23 12:20:54 +0100529 /**
530 * Check if profile got unlocked but the keystore is still locked. This happens on full disk
531 * encryption devices since the profile may not yet be running when we consider unlocking it
532 * during the normal flow. In this case unlock the keystore for the profile.
533 */
534 private void ensureProfileKeystoreUnlocked(int userId) {
535 final KeyStore ks = KeyStore.getInstance();
536 if (ks.state(userId) == KeyStore.State.LOCKED
537 && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
538 Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
539 try {
540 // If boot took too long and the password in vold got expired, parent keystore will
541 // be still locked, we ignore this case since the user will be prompted to unlock
542 // the device after boot.
543 unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
544 } catch (RemoteException e) {
545 Slog.e(TAG, "Failed to unlock child profile");
546 }
547 }
548 }
549
Ricky Waib0cdf382016-05-16 17:28:04 +0100550 public void onUnlockUser(final int userId) {
Rubin Xua55b1682017-01-31 10:06:56 +0000551 // Perform tasks which require locks in LSS on a handler, as we are callbacks from
552 // ActivityManager.unlockUser()
553 mHandler.post(new Runnable() {
554 @Override
555 public void run() {
Pavel Grafov0acc4bf2017-08-23 12:20:54 +0100556 ensureProfileKeystoreUnlocked(userId);
Rubin Xua55b1682017-01-31 10:06:56 +0000557 // Hide notification first, as tie managed profile lock takes time
558 hideEncryptionNotification(new UserHandle(userId));
Ricky Waib0cdf382016-05-16 17:28:04 +0100559
Rubin Xua55b1682017-01-31 10:06:56 +0000560 // Now we have unlocked the parent user we should show notifications
561 // about any profiles that exist.
562 List<UserInfo> profiles = mUserManager.getProfiles(userId);
563 for (int i = 0; i < profiles.size(); i++) {
564 UserInfo profile = profiles.get(i);
565 final boolean isSecure = isUserSecure(profile.id);
566 if (isSecure && profile.isManagedProfile()) {
567 UserHandle userHandle = profile.getUserHandle();
568 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
569 !mUserManager.isQuietModeEnabled(userHandle)) {
570 showEncryptionNotificationForProfile(userHandle);
571 }
572 }
573 }
574
575 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
Ricky Waib0cdf382016-05-16 17:28:04 +0100576 tieManagedProfileLockIfNecessary(userId, null);
577 }
Kenny Guyb1b30262016-02-09 16:02:35 +0000578 }
Rubin Xua55b1682017-01-31 10:06:56 +0000579 });
Amith Yamasani52c489c2012-03-28 11:42:42 -0700580 }
581
Robin Leef0246a82014-08-13 09:50:25 +0100582 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
583 @Override
584 public void onReceive(Context context, Intent intent) {
Robin Lee1096cf82014-09-01 16:52:47 +0100585 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
Chad Brubaker83ce0952015-05-12 13:00:02 -0700586 // Notify keystore that a new user was added.
Robin Leef0246a82014-08-13 09:50:25 +0100587 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Amith Yamasanif11a5742016-06-16 08:20:07 -0700588 if (userHandle > UserHandle.USER_SYSTEM) {
589 removeUser(userHandle, /* unknownUser= */ true);
590 }
Robin Lee49d810c2014-09-23 13:50:22 +0100591 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +0000592 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
Chad Brubaker83ce0952015-05-12 13:00:02 -0700593 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
594 ks.onUserAdded(userHandle, parentHandle);
Adrian Roos3dcae682014-10-29 14:43:56 +0100595 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
596 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
597 mStorage.prefetchUser(userHandle);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100598 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
599 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
600 if (userHandle > 0) {
Amith Yamasanif11a5742016-06-16 08:20:07 -0700601 removeUser(userHandle, /* unknownUser= */ false);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100602 }
Robin Leef0246a82014-08-13 09:50:25 +0100603 }
604 }
605 };
606
Jim Miller4f93c582016-01-27 19:05:43 -0800607 @Override // binder interface
Amith Yamasani52c489c2012-03-28 11:42:42 -0700608 public void systemReady() {
Adrian Roosb953e182017-08-17 17:58:26 +0200609 if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
610 EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
611 }
612 checkWritePermission(UserHandle.USER_SYSTEM);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700613 migrateOldData();
Andres Morales301ea442015-04-17 09:15:47 -0700614 try {
615 getGateKeeperService();
Rubin Xu7b7424b2017-03-31 18:03:20 +0100616 mSpManager.initWeaverService();
Andres Morales301ea442015-04-17 09:15:47 -0700617 } catch (RemoteException e) {
618 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
619 }
Andrew Sculle6527c12018-01-05 18:33:58 +0000620 // Find the AuthSecret HAL
621 try {
622 mAuthSecretService = IAuthSecret.getService();
623 } catch (NoSuchElementException e) {
624 Slog.i(TAG, "Device doesn't implement AuthSecret HAL");
625 } catch (RemoteException e) {
626 Slog.w(TAG, "Failed to get AuthSecret HAL", e);
627 }
Adrian Roos7374d3a2017-03-31 14:14:53 -0700628 mDeviceProvisionedObserver.onSystemReady();
Xiaohui Chen7c696362015-09-16 09:56:14 -0700629 // TODO: maybe skip this for split system user mode.
630 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
Kevin Chyn4dc098a2017-08-08 15:06:28 -0700631 mStrongAuth.systemReady();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700632 }
633
634 private void migrateOldData() {
Rubin Xufe354472017-11-21 12:05:06 +0000635 // These Settings moved before multi-user was enabled, so we only have to do it for the
636 // root user.
637 if (getString("migrated", null, 0) == null) {
638 final ContentResolver cr = mContext.getContentResolver();
639 for (String validSetting : VALID_SETTINGS) {
640 String value = Settings.Secure.getString(cr, validSetting);
641 if (value != null) {
642 setString(validSetting, value, 0);
Jim Miller187ec582013-04-15 18:27:54 -0700643 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700644 }
Rubin Xufe354472017-11-21 12:05:06 +0000645 // No need to move the password / pattern files. They're already in the right place.
646 setString("migrated", "true", 0);
647 Slog.i(TAG, "Migrated lock settings to new location");
648 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700649
Rubin Xufe354472017-11-21 12:05:06 +0000650 // These Settings changed after multi-user was enabled, hence need to be moved per user.
651 if (getString("migrated_user_specific", null, 0) == null) {
652 final ContentResolver cr = mContext.getContentResolver();
653 List<UserInfo> users = mUserManager.getUsers();
654 for (int user = 0; user < users.size(); user++) {
655 // Migrate owner info
656 final int userId = users.get(user).id;
657 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
658 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
659 if (!TextUtils.isEmpty(ownerInfo)) {
660 setString(OWNER_INFO, ownerInfo, userId);
661 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
Adrian Roos43830582015-04-21 16:04:43 -0700662 }
663
Rubin Xufe354472017-11-21 12:05:06 +0000664 // Migrate owner info enabled. Note there was a bug where older platforms only
665 // stored this value if the checkbox was toggled at least once. The code detects
666 // this case by handling the exception.
667 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
668 boolean enabled;
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100669 try {
Rubin Xufe354472017-11-21 12:05:06 +0000670 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
671 enabled = ivalue != 0;
672 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
673 } catch (SettingNotFoundException e) {
674 // Setting was never stored. Store it if the string is not empty.
675 if (!TextUtils.isEmpty(ownerInfo)) {
676 setLong(OWNER_INFO_ENABLED, 1, userId);
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100677 }
Rubin Xufe354472017-11-21 12:05:06 +0000678 }
679 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
680 }
681 // No need to move the password / pattern files. They're already in the right place.
682 setString("migrated_user_specific", "true", 0);
683 Slog.i(TAG, "Migrated per-user lock settings to new location");
684 }
685
686 // Migrates biometric weak such that the fallback mechanism becomes the primary.
687 if (getString("migrated_biometric_weak", null, 0) == null) {
688 List<UserInfo> users = mUserManager.getUsers();
689 for (int i = 0; i < users.size(); i++) {
690 int userId = users.get(i).id;
691 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
692 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
693 userId);
694 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
695 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
696 userId);
697 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
698 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
699 alternateType,
700 userId);
701 }
702 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
703 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
704 userId);
705 }
706 setString("migrated_biometric_weak", "true", 0);
707 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
708 }
709
710 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
711 // user was present on the system, so if we're upgrading to M and there is more than one
712 // user we disable the flag to remain consistent.
713 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
714 final List<UserInfo> users = mUserManager.getUsers();
715 final int userCount = users.size();
716 int switchableUsers = 0;
717 for (int i = 0; i < userCount; i++) {
718 if (users.get(i).supportsSwitchTo()) {
719 switchableUsers++;
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100720 }
Ricky Wai7b9eb412016-05-12 17:29:12 +0100721 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400722
Rubin Xufe354472017-11-21 12:05:06 +0000723 if (switchableUsers > 1) {
Greg Plesureb2e4532016-11-02 17:10:27 -0400724 for (int i = 0; i < userCount; i++) {
725 int id = users.get(i).id;
Rubin Xufe354472017-11-21 12:05:06 +0000726
727 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
728 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
729 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400730 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400731 }
Rubin Xufe354472017-11-21 12:05:06 +0000732
733 setString("migrated_lockscreen_disabled", "true", 0);
734 Slog.i(TAG, "Migrated lockscreen disabled flag");
735 }
736
737 final List<UserInfo> users = mUserManager.getUsers();
738 for (int i = 0; i < users.size(); i++) {
739 final UserInfo userInfo = users.get(i);
740 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
741 // When managed profile has a unified lock, the password quality stored has 2
742 // possibilities only.
743 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
744 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
745 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
746 // unified lock.
747 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
748 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
749 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
750 // Only possible when it's upgraded from nyc dp3
751 Slog.i(TAG, "Migrated tied profile lock type");
752 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
753 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
754 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
755 // It should not happen
756 Slog.e(TAG, "Invalid tied profile lock type: " + quality);
757 }
758 }
759 try {
760 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
761 java.security.KeyStore keyStore =
762 java.security.KeyStore.getInstance("AndroidKeyStore");
763 keyStore.load(null);
764 if (keyStore.containsAlias(alias)) {
765 keyStore.deleteEntry(alias);
766 }
767 } catch (KeyStoreException | NoSuchAlgorithmException |
768 CertificateException | IOException e) {
769 Slog.e(TAG, "Unable to remove tied profile key", e);
770 }
771 }
772
773 boolean isWatch = mContext.getPackageManager().hasSystemFeature(
774 PackageManager.FEATURE_WATCH);
775 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
776 // and device management the lockscreen must be re-enabled now for users that upgrade.
777 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
778 final int userCount = users.size();
779 for (int i = 0; i < userCount; i++) {
780 int id = users.get(i).id;
781 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
782 }
783 setString("migrated_wear_lockscreen_disabled", "true", 0);
784 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700785 }
786 }
787
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200788 private void migrateOldDataAfterSystemReady() {
789 try {
790 // Migrate the FRP credential to the persistent data block
Adrian Roos2adc2632017-09-05 17:01:42 +0200791 if (LockPatternUtils.frpCredentialEnabled(mContext)
792 && !getBoolean("migrated_frp", false, 0)) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200793 migrateFrpCredential();
794 setBoolean("migrated_frp", true, 0);
795 Slog.i(TAG, "Migrated migrated_frp.");
796 }
797 } catch (RemoteException e) {
798 Slog.e(TAG, "Unable to migrateOldDataAfterSystemReady", e);
799 }
800 }
801
802 /**
803 * Migrate the credential for the FRP credential owner user if the following are satisfied:
804 * - the user has a secure credential
805 * - the FRP credential is not set up
806 * - the credential is based on a synthetic password.
807 */
808 private void migrateFrpCredential() throws RemoteException {
809 if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
810 return;
811 }
812 for (UserInfo userInfo : mUserManager.getUsers()) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200813 if (userOwnsFrpCredential(mContext, userInfo) && isUserSecure(userInfo.id)) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200814 synchronized (mSpManager) {
815 if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) {
816 int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
817 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
818
819 mSpManager.migrateFrpPasswordLocked(
820 getSyntheticPasswordHandleLocked(userInfo.id),
821 userInfo,
822 redactActualQualityToMostLenientEquivalentQuality(actualQuality));
823 }
824 }
825 return;
826 }
827 }
828 }
829
830 /**
831 * Returns the lowest password quality that still presents the same UI for entering it.
832 *
833 * For the FRP credential, we do not want to leak the actual quality of the password, only what
834 * kind of UI it requires. However, when migrating, we only know the actual quality, not the
835 * originally requested quality; since this is only used to determine what input variant to
836 * present to the user, we just assume the lowest possible quality was requested.
837 */
838 private int redactActualQualityToMostLenientEquivalentQuality(int quality) {
839 switch (quality) {
840 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
841 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
842 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
843 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
844 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
845 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
846 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
847 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
848 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
849 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
850 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
851 default:
852 return quality;
853 }
854 }
855
Jim Miller5ecd8112013-01-09 18:50:26 -0800856 private final void checkWritePermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800857 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700858 }
859
Jim Miller5ecd8112013-01-09 18:50:26 -0800860 private final void checkPasswordReadPermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800861 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700862 }
863
Adrian Roosb953e182017-08-17 17:58:26 +0200864 private final void checkPasswordHavePermission(int userId) {
865 if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
866 EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
867 }
868 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
869 }
870
Jim Miller158fe192013-04-17 15:23:55 -0700871 private final void checkReadPermission(String requestedKey, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700872 final int callingUid = Binder.getCallingUid();
Adrian Roos001b00d2015-02-24 17:08:48 +0100873
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000874 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
875 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
876 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
Jim Miller158fe192013-04-17 15:23:55 -0700877 != PackageManager.PERMISSION_GRANTED) {
878 throw new SecurityException("uid=" + callingUid
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000879 + " needs permission " + READ_CONTACTS + " to read "
Jim Miller158fe192013-04-17 15:23:55 -0700880 + requestedKey + " for user " + userId);
881 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700882 }
Adrian Roos001b00d2015-02-24 17:08:48 +0100883
884 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
885 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
886 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
887 != PackageManager.PERMISSION_GRANTED) {
888 throw new SecurityException("uid=" + callingUid
889 + " needs permission " + PERMISSION + " to read "
890 + requestedKey + " for user " + userId);
891 }
892 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700893 }
894
895 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000896 public boolean getSeparateProfileChallengeEnabled(int userId) {
Ricky Wai7f405f12016-05-31 12:05:05 +0100897 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000898 synchronized (mSeparateChallengeLock) {
899 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
900 }
901 }
902
903 @Override
904 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
Rubin Xufe354472017-11-21 12:05:06 +0000905 String managedUserPassword) {
Ricky Wai7f405f12016-05-31 12:05:05 +0100906 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000907 synchronized (mSeparateChallengeLock) {
Pavel Grafov28939982017-10-03 15:11:52 +0100908 setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword);
Ricky Waidc283a82016-03-24 19:55:08 +0000909 }
Pavel Grafov28939982017-10-03 15:11:52 +0100910 notifySeparateProfileChallengeChanged(userId);
911 }
912
913 @GuardedBy("mSeparateChallengeLock")
914 private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
915 String managedUserPassword) {
916 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
917 if (enabled) {
918 mStorage.removeChildProfileLock(userId);
919 removeKeystoreProfileKey(userId);
920 } else {
921 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
922 }
923 }
924
925 private void notifySeparateProfileChallengeChanged(int userId) {
Andrew Scull7f4ff4c2018-01-05 18:33:58 +0000926 final DevicePolicyManagerInternal dpmi = LocalServices.getService(
927 DevicePolicyManagerInternal.class);
928 if (dpmi != null) {
929 dpmi.reportSeparateProfileChallengeChanged(userId);
930 }
Ricky Waidc283a82016-03-24 19:55:08 +0000931 }
932
933 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000934 public void setBoolean(String key, boolean value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700935 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100936 setStringUnchecked(key, userId, value ? "1" : "0");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700937 }
938
939 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000940 public void setLong(String key, long value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700941 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100942 setStringUnchecked(key, userId, Long.toString(value));
Amith Yamasani52c489c2012-03-28 11:42:42 -0700943 }
944
945 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000946 public void setString(String key, String value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700947 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100948 setStringUnchecked(key, userId, value);
949 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700950
Adrian Roos261d5ab2014-10-29 14:42:38 +0100951 private void setStringUnchecked(String key, int userId, String value) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700952 Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
953
Adrian Roos261d5ab2014-10-29 14:42:38 +0100954 mStorage.writeKeyValue(key, value, userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800955 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
956 BackupManager.dataChanged("com.android.providers.settings");
957 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700958 }
959
960 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200961 public boolean getBoolean(String key, boolean defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -0700962 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100963 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700964 return TextUtils.isEmpty(value) ?
965 defaultValue : (value.equals("1") || value.equals("true"));
966 }
967
968 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200969 public long getLong(String key, long defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -0700970 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100971 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700972 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
973 }
974
975 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200976 public String getString(String key, String defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -0700977 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100978 return getStringUnchecked(key, defaultValue, userId);
979 }
980
981 public String getStringUnchecked(String key, String defaultValue, int userId) {
982 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
Adrian Roos7811d9f2015-07-27 15:10:13 -0700983 long ident = Binder.clearCallingIdentity();
984 try {
985 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
986 } finally {
987 Binder.restoreCallingIdentity(ident);
988 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100989 }
990
Adrian Roos7374d3a2017-03-31 14:14:53 -0700991 if (userId == USER_FRP) {
992 return getFrpStringUnchecked(key);
993 }
994
Bryce Lee46145962015-12-14 14:39:10 -0800995 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
996 key = Settings.Secure.LOCK_PATTERN_ENABLED;
997 }
998
Adrian Roos261d5ab2014-10-29 14:42:38 +0100999 return mStorage.readKeyValue(key, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001000 }
1001
Adrian Roos7374d3a2017-03-31 14:14:53 -07001002 private String getFrpStringUnchecked(String key) {
1003 if (LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
1004 return String.valueOf(readFrpPasswordQuality());
1005 }
1006 return null;
1007 }
1008
1009 private int readFrpPasswordQuality() {
1010 return mStorage.readPersistentDataBlock().qualityForUi;
1011 }
1012
Adrian Roos4f788452014-05-22 20:45:59 +02001013 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -07001014 public boolean havePassword(int userId) throws RemoteException {
Adrian Roosb953e182017-08-17 17:58:26 +02001015 checkPasswordHavePermission(userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001016 synchronized (mSpManager) {
1017 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1018 long handle = getSyntheticPasswordHandleLocked(userId);
1019 return mSpManager.getCredentialType(handle, userId) ==
1020 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
1021 }
1022 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001023 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +01001024 return mStorage.hasPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001025 }
1026
1027 @Override
1028 public boolean havePattern(int userId) throws RemoteException {
Adrian Roosb953e182017-08-17 17:58:26 +02001029 checkPasswordHavePermission(userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001030 synchronized (mSpManager) {
1031 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1032 long handle = getSyntheticPasswordHandleLocked(userId);
1033 return mSpManager.getCredentialType(handle, userId) ==
1034 LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
1035 }
1036 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001037 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +01001038 return mStorage.hasPattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001039 }
1040
Rubin Xua55b1682017-01-31 10:06:56 +00001041 private boolean isUserSecure(int userId) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00001042 synchronized (mSpManager) {
1043 try {
1044 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1045 long handle = getSyntheticPasswordHandleLocked(userId);
1046 return mSpManager.getCredentialType(handle, userId) !=
1047 LockPatternUtils.CREDENTIAL_TYPE_NONE;
1048 }
1049 } catch (RemoteException e) {
1050 // fall through
1051 }
1052 }
Rubin Xua55b1682017-01-31 10:06:56 +00001053 return mStorage.hasCredential(userId);
1054 }
1055
Chad Brubakera91a8502015-05-07 10:02:22 -07001056 private void setKeystorePassword(String password, int userHandle) {
Robin Leef0246a82014-08-13 09:50:25 +01001057 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +00001058 ks.onUserPasswordChanged(userHandle, password);
Chad Brubakera91a8502015-05-07 10:02:22 -07001059 }
1060
1061 private void unlockKeystore(String password, int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +00001062 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
Chad Brubakera91a8502015-05-07 10:02:22 -07001063 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +00001064 ks.unlock(userHandle, password);
1065 }
Chad Brubakera91a8502015-05-07 10:02:22 -07001066
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001067 @VisibleForTesting
1068 protected String getDecryptedPasswordForTiedProfile(int userId)
Ricky Waidc283a82016-03-24 19:55:08 +00001069 throws KeyStoreException, UnrecoverableKeyException,
1070 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
1071 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
1072 CertificateException, IOException {
Ricky Wai4613fe42016-05-24 11:11:42 +01001073 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
Ricky Waidc283a82016-03-24 19:55:08 +00001074 byte[] storedData = mStorage.readChildProfileLock(userId);
1075 if (storedData == null) {
1076 throw new FileNotFoundException("Child profile lock file not found");
1077 }
1078 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
1079 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
1080 storedData.length);
1081 byte[] decryptionResult;
1082 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1083 keyStore.load(null);
1084 SecretKey decryptionKey = (SecretKey) keyStore.getKey(
Ricky Waid3982442016-05-24 19:27:08 +01001085 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
Ricky Waidc283a82016-03-24 19:55:08 +00001086
1087 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
1088 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
1089
1090 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
1091 decryptionResult = cipher.doFinal(encryptedPassword);
1092 return new String(decryptionResult, StandardCharsets.UTF_8);
1093 }
1094
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001095 private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
1096 throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001097 try {
Rubin Xu1de89b32016-11-30 20:03:13 +00001098 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
1099 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1100 false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
Ricky Waidc283a82016-03-24 19:55:08 +00001101 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1102 | NoSuchAlgorithmException | NoSuchPaddingException
1103 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1104 | BadPaddingException | CertificateException | IOException e) {
1105 if (e instanceof FileNotFoundException) {
1106 Slog.i(TAG, "Child profile key not found");
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001107 } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
1108 Slog.i(TAG, "Parent keystore seems locked, ignoring");
Clara Bayarri0a587d22016-02-23 14:49:41 -08001109 } else {
Ricky Waidc283a82016-03-24 19:55:08 +00001110 Slog.e(TAG, "Failed to decrypt child profile key", e);
Clara Bayarri0a587d22016-02-23 14:49:41 -08001111 }
Jim Millerde1af082013-09-11 14:58:26 -07001112 }
1113 }
1114
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001115 private void unlockUser(int userId, byte[] token, byte[] secret) {
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001116 // TODO: make this method fully async so we can update UI with progress strings
1117 final CountDownLatch latch = new CountDownLatch(1);
1118 final IProgressListener listener = new IProgressListener.Stub() {
1119 @Override
1120 public void onStarted(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001121 Log.d(TAG, "unlockUser started");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001122 }
1123
1124 @Override
1125 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001126 Log.d(TAG, "unlockUser progress " + progress);
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001127 }
1128
1129 @Override
1130 public void onFinished(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001131 Log.d(TAG, "unlockUser finished");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001132 latch.countDown();
1133 }
1134 };
1135
Jeff Sharkey8924e872015-11-30 12:52:10 -07001136 try {
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001137 mActivityManager.unlockUser(userId, token, secret, listener);
Jeff Sharkey8924e872015-11-30 12:52:10 -07001138 } catch (RemoteException e) {
1139 throw e.rethrowAsRuntimeException();
1140 }
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001141
1142 try {
1143 latch.await(15, TimeUnit.SECONDS);
1144 } catch (InterruptedException e) {
1145 Thread.currentThread().interrupt();
1146 }
Ricky Waidc283a82016-03-24 19:55:08 +00001147 try {
1148 if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
1149 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1150 for (UserInfo pi : profiles) {
1151 // Unlock managed profile with unified lock
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001152 if (tiedManagedProfileReadyToUnlock(pi)) {
1153 unlockChildProfile(pi.id, false /* ignoreUserNotAuthenticated */);
Ricky Waidc283a82016-03-24 19:55:08 +00001154 }
1155 }
1156 }
1157 } catch (RemoteException e) {
1158 Log.d(TAG, "Failed to unlock child profile", e);
1159 }
Jeff Sharkey8924e872015-11-30 12:52:10 -07001160 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001161
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001162 private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
1163 return userInfo.isManagedProfile()
1164 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id)
1165 && mStorage.hasChildProfileLock(userInfo.id)
1166 && mUserManager.isUserRunning(userInfo.id);
1167 }
1168
Rubin Xua55b1682017-01-31 10:06:56 +00001169 private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
1170 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1171 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001172 }
Rubin Xua55b1682017-01-31 10:06:56 +00001173 Map<Integer, String> result = new ArrayMap<Integer, String>();
1174 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1175 final int size = profiles.size();
1176 for (int i = 0; i < size; i++) {
1177 final UserInfo profile = profiles.get(i);
1178 if (!profile.isManagedProfile()) {
1179 continue;
1180 }
1181 final int managedUserId = profile.id;
1182 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1183 continue;
1184 }
1185 try {
Rubin Xu4f988c92017-09-12 16:25:26 +01001186 result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId));
Rubin Xua55b1682017-01-31 10:06:56 +00001187 } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
1188 | NoSuchPaddingException | InvalidKeyException
1189 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1190 | BadPaddingException | CertificateException | IOException e) {
Rubin Xu4f988c92017-09-12 16:25:26 +01001191 Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " +
1192 managedUserId, e);
Rubin Xua55b1682017-01-31 10:06:56 +00001193 }
1194 }
1195 return result;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001196 }
1197
Rubin Xua55b1682017-01-31 10:06:56 +00001198 /**
1199 * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1200 * depending on the parent user's secure state.
1201 *
1202 * When clearing tied work challenges, a pre-computed password table for profiles are required,
1203 * since changing password for profiles requires existing password, and existing passwords can
1204 * only be computed before the parent user's password is cleared.
1205 *
1206 * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1207 * method again on profiles. However the recursion is guaranteed to terminate as this method
1208 * terminates when the user is a managed profile.
1209 */
1210 private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1211 Map<Integer, String> profilePasswordMap) throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001212 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1213 return;
1214 }
Rubin Xua55b1682017-01-31 10:06:56 +00001215 final boolean isSecure = isUserSecure(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001216 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1217 final int size = profiles.size();
1218 for (int i = 0; i < size; i++) {
1219 final UserInfo profile = profiles.get(i);
1220 if (profile.isManagedProfile()) {
1221 final int managedUserId = profile.id;
1222 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1223 continue;
1224 }
1225 if (isSecure) {
1226 tieManagedProfileLockIfNecessary(managedUserId, null);
1227 } else {
Rubin Xua55b1682017-01-31 10:06:56 +00001228 // We use cached work profile password computed before clearing the parent's
1229 // credential, otherwise they get lost
1230 if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
1231 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001232 profilePasswordMap.get(managedUserId),
1233 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
Rubin Xua55b1682017-01-31 10:06:56 +00001234 } else {
1235 Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
1236 // Supplying null here would lead to untrusted credential change
1237 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001238 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
Rubin Xua55b1682017-01-31 10:06:56 +00001239 }
Ricky Waidc283a82016-03-24 19:55:08 +00001240 mStorage.removeChildProfileLock(managedUserId);
1241 removeKeystoreProfileKey(managedUserId);
1242 }
1243 }
1244 }
1245 }
Andres Morales8fa56652015-03-31 09:19:50 -07001246
Ricky Waidc283a82016-03-24 19:55:08 +00001247 private boolean isManagedProfileWithUnifiedLock(int userId) {
1248 return mUserManager.getUserInfo(userId).isManagedProfile()
1249 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1250 }
1251
1252 private boolean isManagedProfileWithSeparatedLock(int userId) {
1253 return mUserManager.getUserInfo(userId).isManagedProfile()
1254 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1255 }
1256
1257 // This method should be called by LockPatternUtil only, all internal methods in this class
Rubin Xu1de89b32016-11-30 20:03:13 +00001258 // should call setLockCredentialInternal.
Amith Yamasani52c489c2012-03-28 11:42:42 -07001259 @Override
Adrian Roos7374d3a2017-03-31 14:14:53 -07001260 public void setLockCredential(String credential, int type, String savedCredential,
1261 int requestedQuality, int userId)
Andres Morales8fa56652015-03-31 09:19:50 -07001262 throws RemoteException {
Jim Millere484eaf2016-04-13 16:35:36 -07001263 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001264 synchronized (mSeparateChallengeLock) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001265 setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
Pavel Grafov28939982017-10-03 15:11:52 +01001266 setSeparateProfileChallengeEnabledLocked(userId, true, null);
Andrew Scull5daf2732016-11-14 15:02:45 +00001267 notifyPasswordChanged(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001268 }
Pavel Grafov28939982017-10-03 15:11:52 +01001269 notifySeparateProfileChallengeChanged(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001270 }
1271
Rubin Xu1de89b32016-11-30 20:03:13 +00001272 private void setLockCredentialInternal(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001273 String savedCredential, int requestedQuality, int userId) throws RemoteException {
Rubin Xudf406d82017-02-16 16:49:43 +00001274 // Normalize savedCredential and credential such that empty string is always represented
1275 // as null.
1276 if (TextUtils.isEmpty(savedCredential)) {
1277 savedCredential = null;
1278 }
1279 if (TextUtils.isEmpty(credential)) {
1280 credential = null;
1281 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001282 synchronized (mSpManager) {
1283 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1284 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001285 requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001286 return;
1287 }
1288 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001289
Rubin Xu1de89b32016-11-30 20:03:13 +00001290 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1291 if (credential != null) {
1292 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
1293 }
Paul Crowleycc701552016-05-17 14:18:49 -07001294 clearUserKeyProtection(userId);
Andres Moralescfb61602015-04-16 16:31:15 -07001295 getGateKeeperService().clearSecureUserId(userId);
Rubin Xu1de89b32016-11-30 20:03:13 +00001296 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
Chad Brubakera91a8502015-05-07 10:02:22 -07001297 setKeystorePassword(null, userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001298 fixateNewestUserKeyAuth(userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001299 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
Andrew Scull5daf2732016-11-14 15:02:45 +00001300 notifyActivePasswordMetricsAvailable(null, userId);
Dmitry Dementyev77183ef2018-01-05 15:46:00 -08001301 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001302 return;
1303 }
Rubin Xu1de89b32016-11-30 20:03:13 +00001304 if (credential == null) {
1305 throw new RemoteException("Null credential with mismatched credential type");
Andres Morales8fa56652015-03-31 09:19:50 -07001306 }
Rubin Xua55b1682017-01-31 10:06:56 +00001307
1308 CredentialHash currentHandle = mStorage.readCredentialHash(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001309 if (isManagedProfileWithUnifiedLock(userId)) {
1310 // get credential from keystore when managed profile has unified lock
Rubin Xua55b1682017-01-31 10:06:56 +00001311 if (savedCredential == null) {
1312 try {
1313 savedCredential = getDecryptedPasswordForTiedProfile(userId);
1314 } catch (FileNotFoundException e) {
1315 Slog.i(TAG, "Child profile key not found");
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 }
Andres Morales8fa56652015-03-31 09:19:50 -07001322 }
Ricky Waidc283a82016-03-24 19:55:08 +00001323 } else {
Rubin Xua55b1682017-01-31 10:06:56 +00001324 if (currentHandle.hash == null) {
Ricky Waidc283a82016-03-24 19:55:08 +00001325 if (savedCredential != null) {
1326 Slog.w(TAG, "Saved credential provided, but none stored");
1327 }
1328 savedCredential = null;
1329 }
Andres Morales8fa56652015-03-31 09:19:50 -07001330 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001331 synchronized (mSpManager) {
1332 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1333 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001334 currentHandle.type, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001335 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001336 requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001337 return;
1338 }
1339 }
1340 if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001341 byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
Rubin Xu1de89b32016-11-30 20:03:13 +00001342 userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001343 if (enrolledHandle != null) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001344 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
1345 mStorage.writeCredentialHash(willStore, userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001346 // push new secret and auth token to vold
1347 GateKeeperResponse gkResponse = getGateKeeperService()
1348 .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
1349 setUserKeyProtection(userId, credential, convertResponse(gkResponse));
Paul Crowleycc701552016-05-17 14:18:49 -07001350 fixateNewestUserKeyAuth(userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001351 // Refresh the auth token
1352 doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
1353 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
Dmitry Dementyev6e167242018-01-25 15:29:50 -08001354 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential,
1355 userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001356 } else {
Rubin Xu1de89b32016-11-30 20:03:13 +00001357 throw new RemoteException("Failed to enroll " +
1358 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
1359 : "pattern"));
Andres Morales8fa56652015-03-31 09:19:50 -07001360 }
1361 }
1362
Rubin Xua55b1682017-01-31 10:06:56 +00001363 private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001364 return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
Rubin Xua55b1682017-01-31 10:06:56 +00001365 }
1366
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001367 @VisibleForTesting
1368 protected void tieProfileLockToParent(int userId, String password) {
Ricky Waidc283a82016-03-24 19:55:08 +00001369 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1370 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1371 byte[] encryptionResult;
1372 byte[] iv;
1373 try {
1374 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1375 keyGenerator.init(new SecureRandom());
1376 SecretKey secretKey = keyGenerator.generateKey();
Ricky Waidc283a82016-03-24 19:55:08 +00001377 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1378 keyStore.load(null);
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001379 try {
1380 keyStore.setEntry(
1381 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1382 new java.security.KeyStore.SecretKeyEntry(secretKey),
1383 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1384 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1385 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1386 .build());
1387 keyStore.setEntry(
1388 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1389 new java.security.KeyStore.SecretKeyEntry(secretKey),
1390 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1391 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1392 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1393 .setUserAuthenticationRequired(true)
1394 .setUserAuthenticationValidityDurationSeconds(30)
Pavel Grafove053c1e2017-08-08 16:53:32 +01001395 .setCriticalToDeviceEncryption(true)
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001396 .build());
1397 // Key imported, obtain a reference to it.
1398 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1399 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1400 Cipher cipher = Cipher.getInstance(
1401 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1402 + KeyProperties.ENCRYPTION_PADDING_NONE);
1403 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1404 encryptionResult = cipher.doFinal(randomLockSeed);
1405 iv = cipher.getIV();
1406 } finally {
1407 // The original key can now be discarded.
1408 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1409 }
Ricky Waidc283a82016-03-24 19:55:08 +00001410 } catch (CertificateException | UnrecoverableKeyException
Zach Jange61672a2016-11-22 17:47:18 +00001411 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
Ricky Waidc283a82016-03-24 19:55:08 +00001412 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1413 throw new RuntimeException("Failed to encrypt key", e);
1414 }
1415 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1416 try {
1417 if (iv.length != PROFILE_KEY_IV_SIZE) {
1418 throw new RuntimeException("Invalid iv length: " + iv.length);
1419 }
1420 outputStream.write(iv);
1421 outputStream.write(encryptionResult);
1422 } catch (IOException e) {
1423 throw new RuntimeException("Failed to concatenate byte arrays", e);
1424 }
1425 mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1426 }
1427
Andres Morales8fa56652015-03-31 09:19:50 -07001428 private byte[] enrollCredential(byte[] enrolledHandle,
1429 String enrolledCredential, String toEnroll, int userId)
1430 throws RemoteException {
Jim Millerde1af082013-09-11 14:58:26 -07001431 checkWritePermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001432 byte[] enrolledCredentialBytes = enrolledCredential == null
1433 ? null
1434 : enrolledCredential.getBytes();
1435 byte[] toEnrollBytes = toEnroll == null
1436 ? null
1437 : toEnroll.getBytes();
Andres Morales23974272015-05-14 22:42:26 -07001438 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1439 enrolledCredentialBytes, toEnrollBytes);
Jim Millerde1af082013-09-11 14:58:26 -07001440
Andres Morales23974272015-05-14 22:42:26 -07001441 if (response == null) {
1442 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001443 }
Jim Millerde1af082013-09-11 14:58:26 -07001444
Andres Morales23974272015-05-14 22:42:26 -07001445 byte[] hash = response.getPayload();
1446 if (hash != null) {
1447 setKeystorePassword(toEnroll, userId);
1448 } else {
1449 // Should not happen
1450 Slog.e(TAG, "Throttled while enrolling a password");
1451 }
Andres Morales8fa56652015-03-31 09:19:50 -07001452 return hash;
Jim Millerde1af082013-09-11 14:58:26 -07001453 }
1454
Rubin Xu3bf722a2016-12-15 16:07:38 +00001455 private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
1456 if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1457 addUserKeyAuth(userId, null, key);
1458 }
1459
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001460 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1461 throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001462 if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001463 if (vcr == null) {
1464 throw new RemoteException("Null response verifying a credential we just set");
1465 }
1466 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1467 throw new RemoteException("Non-OK response verifying a credential we just set: "
Rubin Xu1de89b32016-11-30 20:03:13 +00001468 + vcr.getResponseCode());
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001469 }
1470 byte[] token = vcr.getPayload();
1471 if (token == null) {
1472 throw new RemoteException("Empty payload verifying a credential we just set");
1473 }
Paul Crowleycc701552016-05-17 14:18:49 -07001474 addUserKeyAuth(userId, token, secretFromCredential(credential));
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001475 }
1476
1477 private void clearUserKeyProtection(int userId) throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001478 if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001479 addUserKeyAuth(userId, null, null);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001480 }
1481
1482 private static byte[] secretFromCredential(String credential) throws RemoteException {
1483 try {
1484 MessageDigest digest = MessageDigest.getInstance("SHA-512");
1485 // Personalize the hash
1486 byte[] personalization = "Android FBE credential hash"
1487 .getBytes(StandardCharsets.UTF_8);
1488 // Pad it to the block size of the hash function
1489 personalization = Arrays.copyOf(personalization, 128);
1490 digest.update(personalization);
1491 digest.update(credential.getBytes(StandardCharsets.UTF_8));
1492 return digest.digest();
1493 } catch (NoSuchAlgorithmException e) {
1494 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1495 }
1496 }
1497
Paul Crowleycc701552016-05-17 14:18:49 -07001498 private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001499 throws RemoteException {
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001500 final UserInfo userInfo = mUserManager.getUserInfo(userId);
1501 final IStorageManager storageManager = mInjector.getStorageManager();
Paul Crowley815036f2016-03-29 14:14:48 -07001502 final long callingId = Binder.clearCallingIdentity();
1503 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001504 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
Paul Crowley815036f2016-03-29 14:14:48 -07001505 } finally {
1506 Binder.restoreCallingIdentity(callingId);
1507 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001508 }
1509
Paul Crowleycc701552016-05-17 14:18:49 -07001510 private void fixateNewestUserKeyAuth(int userId)
1511 throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001512 if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001513 final IStorageManager storageManager = mInjector.getStorageManager();
Toni Barzic6c818722016-05-27 09:18:39 -07001514 final long callingId = Binder.clearCallingIdentity();
1515 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001516 storageManager.fixateNewestUserKeyAuth(userId);
Toni Barzic6c818722016-05-27 09:18:39 -07001517 } finally {
1518 Binder.restoreCallingIdentity(callingId);
1519 }
Paul Crowleycc701552016-05-17 14:18:49 -07001520 }
1521
Jim Millerde1af082013-09-11 14:58:26 -07001522 @Override
Ricky Wai4613fe42016-05-24 11:11:42 +01001523 public void resetKeyStore(int userId) throws RemoteException {
Ricky Wai7f405f12016-05-31 12:05:05 +01001524 checkWritePermission(userId);
Ricky Wai4613fe42016-05-24 11:11:42 +01001525 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1526 int managedUserId = -1;
1527 String managedUserDecryptedPassword = null;
1528 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1529 for (UserInfo pi : profiles) {
1530 // Unlock managed profile with unified lock
1531 if (pi.isManagedProfile()
1532 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1533 && mStorage.hasChildProfileLock(pi.id)) {
1534 try {
1535 if (managedUserId == -1) {
1536 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1537 managedUserId = pi.id;
1538 } else {
1539 // Should not happen
1540 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1541 + ", uid2:" + pi.id);
1542 }
1543 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1544 | NoSuchAlgorithmException | NoSuchPaddingException
1545 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1546 | BadPaddingException | CertificateException | IOException e) {
1547 Slog.e(TAG, "Failed to decrypt child profile key", e);
1548 }
1549 }
1550 }
1551 try {
1552 // Clear all the users credentials could have been installed in for this user.
1553 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1554 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1555 mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1556 }
1557 }
1558 } finally {
1559 if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1560 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
Zach Jange61672a2016-11-22 17:47:18 +00001561 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
Ricky Wai4613fe42016-05-24 11:11:42 +01001562 }
1563 }
1564 }
1565
1566 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001567 public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001568 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xu1de89b32016-11-30 20:03:13 +00001569 checkPasswordReadPermission(userId);
1570 return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001571 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001572
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001573 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001574 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
1575 int userId) throws RemoteException {
1576 checkPasswordReadPermission(userId);
1577 return doVerifyCredential(credential, type, true, challenge, userId,
1578 null /* progressCallback */);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001579 }
1580
Rubin Xu1de89b32016-11-30 20:03:13 +00001581 /**
1582 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
1583 * format.
1584 */
1585 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001586 boolean hasChallenge, long challenge, int userId,
1587 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xu1de89b32016-11-30 20:03:13 +00001588 if (TextUtils.isEmpty(credential)) {
1589 throw new IllegalArgumentException("Credential can't be null or empty");
1590 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001591 if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
1592 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
1593 Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
1594 return VerifyCredentialResponse.ERROR;
1595 }
Rubin Xue94a7702017-06-20 17:29:57 +01001596 VerifyCredentialResponse response = null;
1597 response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
1598 userId, progressCallback);
1599 // The user employs synthetic password based credential.
1600 if (response != null) {
Robert Berry40386df2018-01-22 21:16:58 +00001601 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1602 mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
1603 userId);
1604 }
Rubin Xue94a7702017-06-20 17:29:57 +01001605 return response;
Rubin Xu3bf722a2016-12-15 16:07:38 +00001606 }
Rubin Xue94a7702017-06-20 17:29:57 +01001607
Adrian Roos7374d3a2017-03-31 14:14:53 -07001608 if (userId == USER_FRP) {
Andrew Scull971f2942017-07-12 15:09:45 +01001609 Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
1610 return VerifyCredentialResponse.ERROR;
Adrian Roos7374d3a2017-03-31 14:14:53 -07001611 }
1612
Andrew Scull971f2942017-07-12 15:09:45 +01001613 final CredentialHash storedHash = mStorage.readCredentialHash(userId);
Rubin Xu1de89b32016-11-30 20:03:13 +00001614 if (storedHash.type != credentialType) {
1615 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
1616 + " stored: " + storedHash.type + " passed in: " + credentialType);
1617 return VerifyCredentialResponse.ERROR;
1618 }
Andres Moralese40bad82015-05-28 14:21:36 -07001619
Rubin Xu1de89b32016-11-30 20:03:13 +00001620 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1621 && storedHash.isBaseZeroPattern;
Andres Moralese40bad82015-05-28 14:21:36 -07001622
Rubin Xu1de89b32016-11-30 20:03:13 +00001623 String credentialToVerify;
1624 if (shouldReEnrollBaseZero) {
1625 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
1626 } else {
1627 credentialToVerify = credential;
1628 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001629
Rubin Xue94a7702017-06-20 17:29:57 +01001630 response = verifyCredential(userId, storedHash, credentialToVerify,
Rubin Xu1de89b32016-11-30 20:03:13 +00001631 hasChallenge, challenge, progressCallback);
Andres Morales59ef1262015-06-26 13:56:39 -07001632
Michal Karpinskie71f5832017-01-13 18:18:49 +00001633 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1634 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1635 if (shouldReEnrollBaseZero) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001636 setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
1637 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
Michal Karpinskie71f5832017-01-13 18:18:49 +00001638 }
Rubin Xu1de89b32016-11-30 20:03:13 +00001639 }
Andres Moralese40bad82015-05-28 14:21:36 -07001640
Rubin Xu1de89b32016-11-30 20:03:13 +00001641 return response;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001642 }
1643
1644 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001645 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
Ricky Wai53940d42016-04-05 15:29:24 +01001646 long challenge, int userId) throws RemoteException {
1647 checkPasswordReadPermission(userId);
1648 if (!isManagedProfileWithUnifiedLock(userId)) {
1649 throw new RemoteException("User id must be managed profile with unified lock");
1650 }
1651 final int parentProfileId = mUserManager.getProfileParent(userId).id;
1652 // Unlock parent by using parent's challenge
Rubin Xu1de89b32016-11-30 20:03:13 +00001653 final VerifyCredentialResponse parentResponse = doVerifyCredential(
1654 credential,
1655 type,
1656 true /* hasChallenge */,
1657 challenge,
1658 parentProfileId,
1659 null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001660 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1661 // Failed, just return parent's response
1662 return parentResponse;
1663 }
1664
1665 try {
1666 // Unlock work profile, and work profile with unified lock must use password only
Rubin Xu1de89b32016-11-30 20:03:13 +00001667 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
1668 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1669 true,
Ricky Wai53940d42016-04-05 15:29:24 +01001670 challenge,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001671 userId, null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001672 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1673 | NoSuchAlgorithmException | NoSuchPaddingException
1674 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1675 | BadPaddingException | CertificateException | IOException e) {
1676 Slog.e(TAG, "Failed to decrypt child profile key", e);
1677 throw new RemoteException("Unable to get tied profile token");
1678 }
1679 }
1680
Rubin Xu1de89b32016-11-30 20:03:13 +00001681 /**
1682 * Lowest-level credential verification routine that talks to GateKeeper. If verification
1683 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
1684 * hash to GK.
1685 */
Andres Morales23974272015-05-14 22:42:26 -07001686 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
Rubin Xu1de89b32016-11-30 20:03:13 +00001687 String credential, boolean hasChallenge, long challenge,
1688 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Andres Morales23974272015-05-14 22:42:26 -07001689 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1690 // don't need to pass empty credentials to GateKeeper
1691 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001692 }
1693
Andrew Zeng750563e2017-03-10 15:14:08 -08001694 if (storedHash == null || TextUtils.isEmpty(credential)) {
Andres Morales23974272015-05-14 22:42:26 -07001695 return VerifyCredentialResponse.ERROR;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001696 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001697
Jeff Sharkeyeddf5182016-08-09 16:36:08 -06001698 // We're potentially going to be doing a bunch of disk I/O below as part
1699 // of unlocking the user, so yell if calling from the main thread.
1700 StrictMode.noteDiskRead();
1701
Andres Morales8fa56652015-03-31 09:19:50 -07001702 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001703 final byte[] hash;
1704 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1705 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
1706 } else {
1707 hash = mLockPatternUtils.passwordToHash(credential, userId);
1708 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001709 if (Arrays.equals(hash, storedHash.hash)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001710 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1711 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
1712 } else {
1713 unlockKeystore(credential, userId);
1714 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001715 // Users with legacy credentials don't have credential-backed
1716 // FBE keys, so just pass through a fake token/secret
1717 Slog.i(TAG, "Unlocking user with fake token: " + userId);
1718 final byte[] fakeToken = String.valueOf(userId).getBytes();
1719 unlockUser(userId, fakeToken, fakeToken);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001720
Andres Morales23974272015-05-14 22:42:26 -07001721 // migrate credential to GateKeeper
Adrian Roos7374d3a2017-03-31 14:14:53 -07001722 setLockCredentialInternal(credential, storedHash.type, null,
1723 storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1724 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1725 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1726 /* TODO(roosa): keep the same password quality */, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001727 if (!hasChallenge) {
Andrew Scull5daf2732016-11-14 15:02:45 +00001728 notifyActivePasswordMetricsAvailable(credential, userId);
Robert Berryf899bff2017-12-28 17:34:38 +00001729 // Use credentials to create recoverable keystore snapshot.
1730 mRecoverableKeyStoreManager.lockScreenSecretAvailable(
1731 storedHash.type, credential, userId);
Andres Morales23974272015-05-14 22:42:26 -07001732 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001733 }
1734 // Fall through to get the auth token. Technically this should never happen,
Andres Morales23974272015-05-14 22:42:26 -07001735 // as a user that had a legacy credential would have to unlock their device
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001736 // before getting to a flow with a challenge, but supporting for consistency.
1737 } else {
Andres Morales23974272015-05-14 22:42:26 -07001738 return VerifyCredentialResponse.ERROR;
Andres Morales8fa56652015-03-31 09:19:50 -07001739 }
Andres Morales8fa56652015-03-31 09:19:50 -07001740 }
Paul Crowley98e0a262016-02-04 09:41:53 +00001741 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1742 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
Rubin Xua55b1682017-01-31 10:06:56 +00001743 VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
1744 boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
Andres Morales8fa56652015-03-31 09:19:50 -07001745
Andres Morales23974272015-05-14 22:42:26 -07001746 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001747
Andres Morales23974272015-05-14 22:42:26 -07001748 // credential has matched
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001749
1750 if (progressCallback != null) {
1751 progressCallback.onCredentialVerified();
1752 }
Andrew Scull5daf2732016-11-14 15:02:45 +00001753 notifyActivePasswordMetricsAvailable(credential, userId);
Andres Morales23974272015-05-14 22:42:26 -07001754 unlockKeystore(credential, userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001755
Rubin Xu3bf722a2016-12-15 16:07:38 +00001756 Slog.i(TAG, "Unlocking user " + userId + " with token length "
1757 + response.getPayload().length);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001758 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001759
Ricky Waidc283a82016-03-24 19:55:08 +00001760 if (isManagedProfileWithSeparatedLock(userId)) {
Clara Bayarri56878a92015-10-29 15:43:55 +00001761 TrustManager trustManager =
1762 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1763 trustManager.setDeviceLockedForUser(userId, false);
1764 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001765 int reEnrollQuality = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1766 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1767 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1768 /* TODO(roosa): keep the same password quality */;
Andres Morales23974272015-05-14 22:42:26 -07001769 if (shouldReEnroll) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001770 setLockCredentialInternal(credential, storedHash.type, credential,
1771 reEnrollQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001772 } else {
1773 // Now that we've cleared of all required GK migration, let's do the final
1774 // migration to synthetic password.
1775 synchronized (mSpManager) {
1776 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
Rubin Xu128180b2017-04-12 18:02:44 +01001777 AuthenticationToken auth = initializeSyntheticPasswordLocked(
Adrian Roos7374d3a2017-03-31 14:14:53 -07001778 storedHash.hash, credential, storedHash.type, reEnrollQuality,
1779 userId);
Rubin Xu128180b2017-04-12 18:02:44 +01001780 activateEscrowTokens(auth, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001781 }
1782 }
Andres Morales23974272015-05-14 22:42:26 -07001783 }
Dmitry Dementyev6a509e42017-12-19 14:47:26 -08001784 // Use credentials to create recoverable keystore snapshot.
1785 mRecoverableKeyStoreManager.lockScreenSecretAvailable(storedHash.type, credential,
1786 userId);
1787
Adrian Roos873010d2015-08-25 15:59:00 -07001788 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1789 if (response.getTimeout() > 0) {
1790 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1791 }
Andres Morales23974272015-05-14 22:42:26 -07001792 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001793
Andres Morales23974272015-05-14 22:42:26 -07001794 return response;
1795 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001796
Rubin Xu7cf45092017-08-28 11:47:35 +01001797 /**
1798 * Call this method to notify DPMS regarding the latest password metric. This should be called
1799 * when the user is authenticating or when a new password is being set.
1800 */
Andrew Scull5daf2732016-11-14 15:02:45 +00001801 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
1802 final PasswordMetrics metrics;
1803 if (password == null) {
1804 metrics = new PasswordMetrics();
1805 } else {
1806 metrics = PasswordMetrics.computeForPassword(password);
1807 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
1808 }
1809
1810 // Asynchronous to avoid dead lock
1811 mHandler.post(() -> {
1812 DevicePolicyManager dpm = (DevicePolicyManager)
1813 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1814 dpm.setActivePasswordState(metrics, userId);
1815 });
1816 }
1817
1818 /**
1819 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
1820 * reporting the password changed.
1821 */
1822 private void notifyPasswordChanged(@UserIdInt int userId) {
1823 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
1824 mHandler.post(() -> {
1825 DevicePolicyManager dpm = (DevicePolicyManager)
1826 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1827 dpm.reportPasswordChanged(userId);
1828 });
1829 }
1830
Amith Yamasani52c489c2012-03-28 11:42:42 -07001831 @Override
Adrian Roos261d5ab2014-10-29 14:42:38 +01001832 public boolean checkVoldPassword(int userId) throws RemoteException {
Paul Lawrence945490c2014-03-27 16:37:28 +00001833 if (!mFirstCallToVold) {
1834 return false;
1835 }
1836 mFirstCallToVold = false;
1837
1838 checkPasswordReadPermission(userId);
1839
1840 // There's no guarantee that this will safely connect, but if it fails
1841 // we will simply show the lock screen when we shouldn't, so relatively
1842 // benign. There is an outside chance something nasty would happen if
1843 // this service restarted before vold stales out the password in this
1844 // case. The nastiness is limited to not showing the lock screen when
1845 // we should, within the first minute of decrypting the phone if this
1846 // service can't connect to vold, it restarts, and then the new instance
1847 // does successfully connect.
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001848 final IStorageManager service = mInjector.getStorageManager();
Paul Lawrence0bbd1082016-04-26 15:21:02 -07001849 String password;
1850 long identity = Binder.clearCallingIdentity();
1851 try {
1852 password = service.getPassword();
1853 service.clearPassword();
1854 } finally {
1855 Binder.restoreCallingIdentity(identity);
1856 }
Paul Lawrence945490c2014-03-27 16:37:28 +00001857 if (password == null) {
1858 return false;
1859 }
1860
1861 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001862 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001863 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
1864 null /* progressCallback */)
1865 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001866 return true;
1867 }
1868 }
1869 } catch (Exception e) {
1870 }
1871
1872 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001873 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001874 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
1875 null /* progressCallback */)
1876 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001877 return true;
1878 }
1879 }
1880 } catch (Exception e) {
1881 }
1882
1883 return false;
1884 }
1885
Amith Yamasanif11a5742016-06-16 08:20:07 -07001886 private void removeUser(int userId, boolean unknownUser) {
Rubin Xu7b7424b2017-03-31 18:03:20 +01001887 mSpManager.removeUser(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +01001888 mStorage.removeUser(userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001889 mStrongAuth.removeUser(userId);
Andrew Scullede482d2018-01-30 13:54:29 +00001890 tryRemoveUserFromSpCacheLater(userId);
Robin Lee49d810c2014-09-23 13:50:22 +01001891
1892 final KeyStore ks = KeyStore.getInstance();
Chad Brubaker83ce0952015-05-12 13:00:02 -07001893 ks.onUserRemoved(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001894
1895 try {
1896 final IGateKeeperService gk = getGateKeeperService();
1897 if (gk != null) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001898 gk.clearSecureUserId(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001899 }
1900 } catch (RemoteException ex) {
1901 Slog.w(TAG, "unable to clear GK secure user id");
1902 }
Amith Yamasanif11a5742016-06-16 08:20:07 -07001903 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
Ricky Waidc283a82016-03-24 19:55:08 +00001904 removeKeystoreProfileKey(userId);
1905 }
1906 }
1907
1908 private void removeKeystoreProfileKey(int targetUserId) {
1909 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1910 try {
1911 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1912 keyStore.load(null);
Ricky Waid3982442016-05-24 19:27:08 +01001913 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1914 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
Ricky Waidc283a82016-03-24 19:55:08 +00001915 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1916 | IOException e) {
1917 // We have tried our best to remove all keys
1918 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1919 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001920 }
1921
Adrian Roosb5e47222015-08-14 15:53:06 -07001922 @Override
1923 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1924 checkPasswordReadPermission(UserHandle.USER_ALL);
1925 mStrongAuth.registerStrongAuthTracker(tracker);
1926 }
1927
1928 @Override
1929 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1930 checkPasswordReadPermission(UserHandle.USER_ALL);
1931 mStrongAuth.unregisterStrongAuthTracker(tracker);
1932 }
1933
1934 @Override
1935 public void requireStrongAuth(int strongAuthReason, int userId) {
1936 checkWritePermission(userId);
1937 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1938 }
1939
Adrian Roos4ab7e592016-04-13 15:38:13 -07001940 @Override
1941 public void userPresent(int userId) {
1942 checkWritePermission(userId);
1943 mStrongAuth.reportUnlock(userId);
1944 }
1945
Victor Changa0940d32016-05-16 19:36:08 +01001946 @Override
1947 public int getStrongAuthForUser(int userId) {
1948 checkPasswordReadPermission(userId);
1949 return mStrongAuthTracker.getStrongAuthForUser(userId);
1950 }
1951
Jorim Jaggi2fef6f72016-11-01 19:06:25 -07001952 private boolean isCallerShell() {
1953 final int callingUid = Binder.getCallingUid();
1954 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1955 }
1956
1957 private void enforceShell() {
1958 if (!isCallerShell()) {
1959 throw new SecurityException("Caller must be shell");
1960 }
1961 }
1962
1963 @Override
1964 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1965 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1966 throws RemoteException {
1967 enforceShell();
1968 final long origId = Binder.clearCallingIdentity();
1969 try {
1970 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
1971 this, in, out, err, args, callback, resultReceiver);
1972 } finally {
1973 Binder.restoreCallingIdentity(origId);
1974 }
1975 }
1976
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08001977 @Override
1978 public void initRecoveryService(@NonNull String rootCertificateAlias,
Dmitry Dementyev14298312018-01-04 15:19:19 -08001979 @NonNull byte[] signedPublicKeyList) throws RemoteException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08001980 mRecoverableKeyStoreManager.initRecoveryService(rootCertificateAlias,
Dmitry Dementyev14298312018-01-04 15:19:19 -08001981 signedPublicKeyList);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08001982 }
1983
1984 @Override
Dmitry Dementyevb4fb9872018-01-26 11:49:34 -08001985 public KeyChainSnapshot getKeyChainSnapshot() throws RemoteException {
1986 return mRecoverableKeyStoreManager.getKeyChainSnapshot();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08001987 }
1988
Dmitry Dementyev14298312018-01-04 15:19:19 -08001989 public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08001990 throws RemoteException {
Dmitry Dementyev14298312018-01-04 15:19:19 -08001991 mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent);
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08001992 }
1993
Dmitry Dementyev14298312018-01-04 15:19:19 -08001994 public Map getRecoverySnapshotVersions() throws RemoteException {
1995 return mRecoverableKeyStoreManager.getRecoverySnapshotVersions();
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08001996 }
1997
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08001998 @Override
Dmitry Dementyev7d8c78a2018-01-12 19:14:07 -08001999 public void setServerParams(byte[] serverParams) throws RemoteException {
2000 mRecoverableKeyStoreManager.setServerParams(serverParams);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002001 }
2002
2003 @Override
2004 public void setRecoveryStatus(@NonNull String packageName, @Nullable String[] aliases,
Dmitry Dementyev14298312018-01-04 15:19:19 -08002005 int status) throws RemoteException {
2006 mRecoverableKeyStoreManager.setRecoveryStatus(packageName, aliases, status);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002007 }
2008
Dmitry Dementyev14298312018-01-04 15:19:19 -08002009 public Map getRecoveryStatus(@Nullable String packageName) throws RemoteException {
2010 return mRecoverableKeyStoreManager.getRecoveryStatus(packageName);
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002011 }
2012
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002013 @Override
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -08002014 public void setRecoverySecretTypes(@NonNull @KeyChainProtectionParams.UserSecretType
Dmitry Dementyev14298312018-01-04 15:19:19 -08002015 int[] secretTypes) throws RemoteException {
2016 mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002017 }
2018
2019 @Override
Dmitry Dementyev14298312018-01-04 15:19:19 -08002020 public int[] getRecoverySecretTypes() throws RemoteException {
2021 return mRecoverableKeyStoreManager.getRecoverySecretTypes();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002022
2023 }
2024
2025 @Override
Dmitry Dementyev14298312018-01-04 15:19:19 -08002026 public int[] getPendingRecoverySecretTypes() throws RemoteException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002027 throw new SecurityException("Not implemented");
2028 }
2029
2030 @Override
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -08002031 public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret)
Dmitry Dementyev14298312018-01-04 15:19:19 -08002032 throws RemoteException {
2033 mRecoverableKeyStoreManager.recoverySecretAvailable(recoverySecret);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002034 }
2035
2036 @Override
2037 public byte[] startRecoverySession(@NonNull String sessionId,
2038 @NonNull byte[] verifierPublicKey, @NonNull byte[] vaultParams,
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -08002039 @NonNull byte[] vaultChallenge, @NonNull List<KeyChainProtectionParams> secrets)
Dmitry Dementyev14298312018-01-04 15:19:19 -08002040 throws RemoteException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002041 return mRecoverableKeyStoreManager.startRecoverySession(sessionId, verifierPublicKey,
Dmitry Dementyev14298312018-01-04 15:19:19 -08002042 vaultParams, vaultChallenge, secrets);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002043 }
2044
Robert Berry2bcdad92018-01-18 12:53:29 +00002045 public void closeSession(@NonNull String sessionId) throws RemoteException {
2046 mRecoverableKeyStoreManager.closeSession(sessionId);
2047 }
2048
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002049 @Override
Bo Zhu57e77f72018-01-03 14:49:43 -08002050 public Map<String, byte[]> recoverKeys(@NonNull String sessionId,
Robert Berry5f138702018-01-17 15:18:05 +00002051 @NonNull byte[] recoveryKeyBlob, @NonNull List<WrappedApplicationKey> applicationKeys)
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002052 throws RemoteException {
Robert Berrybd4c43c2017-12-22 11:35:14 +00002053 return mRecoverableKeyStoreManager.recoverKeys(
Dmitry Dementyev14298312018-01-04 15:19:19 -08002054 sessionId, recoveryKeyBlob, applicationKeys);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002055 }
2056
Robert Berrycfc990a2017-12-22 15:54:30 +00002057 @Override
Robert Berry5daccec2018-01-06 19:16:25 +00002058 public void removeKey(@NonNull String alias) throws RemoteException {
2059 mRecoverableKeyStoreManager.removeKey(alias);
2060 }
2061
2062 @Override
Robert Berrycfc990a2017-12-22 15:54:30 +00002063 public byte[] generateAndStoreKey(@NonNull String alias) throws RemoteException {
2064 return mRecoverableKeyStoreManager.generateAndStoreKey(alias);
2065 }
2066
Dmitry Dementyev29b9de52018-01-31 16:09:32 -08002067 @Override
2068 public String generateKey(@NonNull String alias, byte[] account) throws RemoteException {
2069 return mRecoverableKeyStoreManager.generateKey(alias, account);
2070 }
2071
2072 @Override
2073 public String getKey(@NonNull String alias) throws RemoteException {
2074 return mRecoverableKeyStoreManager.getKey(alias);
2075 }
2076
Amith Yamasani52c489c2012-03-28 11:42:42 -07002077 private static final String[] VALID_SETTINGS = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002078 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
2079 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
2080 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
2081 LockPatternUtils.PASSWORD_TYPE_KEY,
2082 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
2083 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2084 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
2085 LockPatternUtils.LOCKSCREEN_OPTIONS,
2086 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
2087 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
2088 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
2089 LockPatternUtils.PASSWORD_HISTORY_KEY,
2090 Secure.LOCK_PATTERN_ENABLED,
2091 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
2092 Secure.LOCK_PATTERN_VISIBLE,
2093 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
Jim Miller187ec582013-04-15 18:27:54 -07002094 };
2095
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +00002096 // Reading these settings needs the contacts permission
2097 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002098 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
2099 Secure.LOCK_SCREEN_OWNER_INFO
Jim Miller187ec582013-04-15 18:27:54 -07002100 };
Paul Lawrence945490c2014-03-27 16:37:28 +00002101
Adrian Roos001b00d2015-02-24 17:08:48 +01002102 // Reading these settings needs the same permission as checking the password
2103 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
2104 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2105 LockPatternUtils.PASSWORD_HISTORY_KEY,
Adrian Roos855fa302015-04-02 16:01:12 +02002106 LockPatternUtils.PASSWORD_TYPE_KEY,
Ricky Wai7f405f12016-05-31 12:05:05 +01002107 SEPARATE_PROFILE_CHALLENGE_KEY
Adrian Roos001b00d2015-02-24 17:08:48 +01002108 };
2109
Amith Yamasani072543f2015-02-13 11:09:45 -08002110 private static final String[] SETTINGS_TO_BACKUP = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002111 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
Bryan Mawhinneye483b562017-05-15 14:46:05 +01002112 Secure.LOCK_SCREEN_OWNER_INFO,
2113 Secure.LOCK_PATTERN_VISIBLE,
2114 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
Amith Yamasani072543f2015-02-13 11:09:45 -08002115 };
2116
Andres Morales301ea442015-04-17 09:15:47 -07002117 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
2118 @Override
2119 public void binderDied() {
2120 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
2121 mGateKeeperService = null;
2122 }
2123 }
2124
Rubin Xu3bf722a2016-12-15 16:07:38 +00002125 protected synchronized IGateKeeperService getGateKeeperService()
Andres Morales301ea442015-04-17 09:15:47 -07002126 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -07002127 if (mGateKeeperService != null) {
2128 return mGateKeeperService;
2129 }
2130
Rubin Xu1de89b32016-11-30 20:03:13 +00002131 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
Andres Morales8fa56652015-03-31 09:19:50 -07002132 if (service != null) {
Andres Morales301ea442015-04-17 09:15:47 -07002133 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
Andres Morales8fa56652015-03-31 09:19:50 -07002134 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
2135 return mGateKeeperService;
2136 }
2137
2138 Slog.e(TAG, "Unable to acquire GateKeeperService");
2139 return null;
2140 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00002141
2142 /**
Andrew Scull1416bd02018-01-05 18:33:58 +00002143 * A user's synthetic password does not change so it must be cached in certain circumstances to
2144 * enable untrusted credential reset.
2145 *
2146 * Untrusted credential reset will be removed in a future version (b/68036371) at which point
2147 * this cache is no longer needed as the SP will always be known when changing the user's
2148 * credential.
2149 */
2150 @GuardedBy("mSpManager")
2151 private SparseArray<AuthenticationToken> mSpCache = new SparseArray();
2152
2153 private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
Andrew Scullede482d2018-01-30 13:54:29 +00002154 // Preemptively cache the SP and then try to remove it in a handler.
2155 Slog.i(TAG, "Caching SP for user " + userId);
2156 synchronized (mSpManager) {
2157 mSpCache.put(userId, auth);
2158 }
2159 tryRemoveUserFromSpCacheLater(userId);
2160
Andrew Sculle6527c12018-01-05 18:33:58 +00002161 // Pass the primary user's auth secret to the HAL
2162 if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
2163 try {
2164 final byte[] rawSecret = auth.deriveVendorAuthSecret();
2165 final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length);
2166 for (int i = 0; i < rawSecret.length; ++i) {
2167 secret.add(rawSecret[i]);
2168 }
2169 mAuthSecretService.primaryUserCredential(secret);
2170 } catch (RemoteException e) {
2171 Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
2172 }
2173 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002174 }
2175
Andrew Scullede482d2018-01-30 13:54:29 +00002176 private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) {
2177 mHandler.post(() -> {
2178 if (!shouldCacheSpForUser(userId)) {
2179 // The transition from 'should not cache' to 'should cache' can only happen if
2180 // certain admin apps are installed after provisioning e.g. via adb. This is not
2181 // a common case and we do not seamlessly support; it may result in the SP not
2182 // being cached when it is needed. The cache can be re-populated by verifying
2183 // the credential again.
2184 Slog.i(TAG, "Removing SP from cache for user " + userId);
2185 synchronized (mSpManager) {
2186 mSpCache.remove(userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002187 }
2188 }
Andrew Scullede482d2018-01-30 13:54:29 +00002189 });
Andrew Scull1416bd02018-01-05 18:33:58 +00002190 }
2191
Andrew Scullede482d2018-01-30 13:54:29 +00002192 /** Do not hold any of the locks from this service when calling. */
Andrew Scull1416bd02018-01-05 18:33:58 +00002193 private boolean shouldCacheSpForUser(@UserIdInt int userId) {
2194 // Before the user setup has completed, an admin could be installed that requires the SP to
2195 // be cached (see below).
2196 if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
2197 Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 0) {
2198 return true;
2199 }
2200
2201 // If the user has an admin which can perform an untrusted credential reset, the SP needs to
2202 // be cached. If there isn't a DevicePolicyManager then there can't be an admin in the first
2203 // place so caching is not necessary.
2204 final DevicePolicyManagerInternal dpmi = LocalServices.getService(
2205 DevicePolicyManagerInternal.class);
2206 if (dpmi == null) {
2207 return false;
2208 }
2209 return dpmi.canUserHaveUntrustedCredentialReset(userId);
2210 }
2211
2212 /**
Rubin Xu3bf722a2016-12-15 16:07:38 +00002213 * Precondition: vold and keystore unlocked.
2214 *
2215 * Create new synthetic password, set up synthetic password blob protected by the supplied
2216 * user credential, and make the newly-created SP blob active.
2217 *
2218 * The invariant under a synthetic password is:
2219 * 1. If user credential exists, then both vold and keystore and protected with keys derived
2220 * from the synthetic password.
2221 * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
2222 * make it consistent with current behaviour. It also allows ActivityManager to call
2223 * unlockUser() with empty secret.
2224 * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
2225 * whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
2226 * lockscreen PIN, we still maintain the existing synthetic password in a password blob
Andrew Scull1416bd02018-01-05 18:33:58 +00002227 * protected by a default PIN.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002228 * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
2229 * clears/re-creates his lockscreen PIN.
2230 *
2231 *
2232 * Different cases of calling this method:
2233 * 1. credentialHash != null
2234 * This implies credential != null, a new SP blob will be provisioned, and existing SID
2235 * migrated to associate with the new SP.
2236 * This happens during a normal migration case when the user currently has password.
2237 *
2238 * 2. credentialhash == null and credential == null
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002239 * A new SP blob and will be created, while the user has no credentials.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002240 * This can happens when we are activating an escrow token on a unsecured device, during
2241 * which we want to create the SP structure with an empty user credential.
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002242 * This could also happen during an untrusted reset to clear password.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002243 *
2244 * 3. credentialhash == null and credential != null
2245 * This is the untrusted credential reset, OR the user sets a new lockscreen password
2246 * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
2247 */
Andrew Scull1416bd02018-01-05 18:33:58 +00002248 @GuardedBy("mSpManager")
Rubin Xu16c823e2017-06-27 14:44:58 +01002249 @VisibleForTesting
2250 protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002251 String credential, int credentialType, int requestedQuality,
2252 int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002253 Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002254 final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
2255 getGateKeeperService(), credentialHash, credential, userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002256 onAuthTokenKnownForUser(userId, auth);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002257 if (auth == null) {
2258 Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
2259 return null;
2260 }
2261 long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
Adrian Roos7374d3a2017-03-31 14:14:53 -07002262 credential, credentialType, auth, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002263 if (credential != null) {
2264 if (credentialHash == null) {
2265 // Since when initializing SP, we didn't provide an existing password handle
2266 // for it to migrate SID, we need to create a new SID for the user.
2267 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2268 }
2269 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2270 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2271 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2272 } else {
2273 clearUserKeyProtection(userId);
2274 setKeystorePassword(null, userId);
2275 getGateKeeperService().clearSecureUserId(userId);
2276 }
2277 fixateNewestUserKeyAuth(userId);
2278 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
2279 return auth;
2280 }
2281
2282 private long getSyntheticPasswordHandleLocked(int userId) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +02002283 return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY,
2284 SyntheticPasswordManager.DEFAULT_HANDLE, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002285 }
2286
2287 private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002288 if (userId == USER_FRP) {
2289 final int type = mStorage.readPersistentDataBlock().type;
2290 return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
2291 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00002292 long handle = getSyntheticPasswordHandleLocked(userId);
2293 // This is a global setting
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00002294 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
2295 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002296 return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
2297 }
2298
Rubin Xu16c823e2017-06-27 14:44:58 +01002299 @VisibleForTesting
2300 protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002301 long handle = getSyntheticPasswordHandleLocked(userId);
2302 // This is a global setting
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00002303 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
2304 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002305 return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
2306 }
2307
2308 private void enableSyntheticPasswordLocked() throws RemoteException {
2309 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
2310 }
2311
Rubin Xue94a7702017-06-20 17:29:57 +01002312 private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
Rubin Xu3bf722a2016-12-15 16:07:38 +00002313 credentialType, boolean hasChallenge, long challenge, int userId,
2314 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xue94a7702017-06-20 17:29:57 +01002315 if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002316 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
2317 userCredential = null;
2318 }
Rubin Xue94a7702017-06-20 17:29:57 +01002319
2320 final AuthenticationResult authResult;
2321 VerifyCredentialResponse response;
2322 synchronized (mSpManager) {
2323 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
2324 return null;
2325 }
2326 if (userId == USER_FRP) {
2327 return mSpManager.verifyFrpCredential(getGateKeeperService(),
2328 userCredential, credentialType, progressCallback);
2329 }
2330
2331 long handle = getSyntheticPasswordHandleLocked(userId);
2332 authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
Rubin Xucf326f12017-11-15 11:55:35 +00002333 getGateKeeperService(), handle, userCredential, userId, progressCallback);
Rubin Xue94a7702017-06-20 17:29:57 +01002334
Rubin Xu16c823e2017-06-27 14:44:58 +01002335 if (authResult.credentialType != credentialType) {
2336 Slog.e(TAG, "Credential type mismatch.");
2337 return VerifyCredentialResponse.ERROR;
2338 }
Rubin Xue94a7702017-06-20 17:29:57 +01002339 response = authResult.gkResponse;
2340 // credential has matched
2341 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2342 // perform verifyChallenge with synthetic password which generates the real GK auth
2343 // token and response for the current user
2344 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
2345 challenge, userId);
2346 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2347 // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
2348 // match the recorded GK password handle.
2349 Slog.wtf(TAG, "verifyChallenge with SP failed.");
2350 return VerifyCredentialResponse.ERROR;
2351 }
2352 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07002353 }
2354
Rubin Xu3bf722a2016-12-15 16:07:38 +00002355 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002356 notifyActivePasswordMetricsAvailable(userCredential, userId);
2357 unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
2358
2359 final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
2360 Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
2361 unlockUser(userId, null, secret);
2362
Rubin Xue94a7702017-06-20 17:29:57 +01002363 activateEscrowTokens(authResult.authToken, userId);
2364
Rubin Xu3bf722a2016-12-15 16:07:38 +00002365 if (isManagedProfileWithSeparatedLock(userId)) {
2366 TrustManager trustManager =
2367 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
2368 trustManager.setDeviceLockedForUser(userId, false);
2369 }
Rubin Xue94a7702017-06-20 17:29:57 +01002370 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002371
2372 onAuthTokenKnownForUser(userId, authResult.authToken);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002373 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
2374 if (response.getTimeout() > 0) {
2375 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
2376 }
2377 }
2378
2379 return response;
2380 }
2381
2382 /**
2383 * Change the user's lockscreen password by creating a new SP blob and update the handle, based
2384 * on an existing authentication token. Even though a new SP blob is created, the underlying
2385 * synthetic password is never changed.
2386 *
2387 * When clearing credential, we keep the SP unchanged, but clear its password handle so its
2388 * SID is gone. We also clear password from (software-based) keystore and vold, which will be
2389 * added back when new password is set in future.
2390 */
Andrew Scull1416bd02018-01-05 18:33:58 +00002391 @GuardedBy("mSpManager")
Rubin Xu3bf722a2016-12-15 16:07:38 +00002392 private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002393 AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002394 if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
2395 long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
Adrian Roos7374d3a2017-03-31 14:14:53 -07002396 credential, credentialType, auth, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002397 final Map<Integer, String> profilePasswords;
2398 if (credential != null) {
2399 // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
2400 profilePasswords = null;
2401
2402 if (mSpManager.hasSidForUser(userId)) {
2403 // We are changing password of a secured device, nothing more needed as
2404 // createPasswordBasedSyntheticPassword has already taken care of maintaining
2405 // the password handle and SID unchanged.
2406
2407 //refresh auth token
2408 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2409 } else {
2410 // A new password is set on a previously-unsecured device, we need to generate
2411 // a new SID, and re-add keys to vold and keystore.
2412 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2413 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2414 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2415 fixateNewestUserKeyAuth(userId);
2416 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2417 }
2418 } else {
2419 // Cache all profile password if they use unified work challenge. This will later be
2420 // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
2421 profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
2422
2423 // we are clearing password of a secured device, so need to nuke SID as well.
2424 mSpManager.clearSidForUser(userId);
2425 getGateKeeperService().clearSecureUserId(userId);
2426 // Clear key from vold so ActivityManager can just unlock the user with empty secret
2427 // during boot.
2428 clearUserKeyProtection(userId);
2429 fixateNewestUserKeyAuth(userId);
2430 setKeystorePassword(null, userId);
2431 }
2432 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
2433 synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
Rubin Xu7cf45092017-08-28 11:47:35 +01002434
2435 notifyActivePasswordMetricsAvailable(credential, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002436 return newHandle;
2437 }
2438
Andrew Scull1416bd02018-01-05 18:33:58 +00002439 @GuardedBy("mSpManager")
Rubin Xu3bf722a2016-12-15 16:07:38 +00002440 private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002441 String savedCredential, int requestedQuality, int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002442 if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2443 if (isManagedProfileWithUnifiedLock(userId)) {
2444 // get credential from keystore when managed profile has unified lock
2445 try {
2446 savedCredential = getDecryptedPasswordForTiedProfile(userId);
2447 } catch (FileNotFoundException e) {
2448 Slog.i(TAG, "Child profile key not found");
2449 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2450 | NoSuchAlgorithmException | NoSuchPaddingException
2451 | InvalidAlgorithmParameterException | IllegalBlockSizeException
2452 | BadPaddingException | CertificateException | IOException e) {
2453 Slog.e(TAG, "Failed to decrypt child profile key", e);
2454 }
2455 }
2456 long handle = getSyntheticPasswordHandleLocked(userId);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002457 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
Rubin Xucf326f12017-11-15 11:55:35 +00002458 getGateKeeperService(), handle, savedCredential, userId, null);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002459 VerifyCredentialResponse response = authResult.gkResponse;
2460 AuthenticationToken auth = authResult.authToken;
Rubin Xu16c823e2017-06-27 14:44:58 +01002461
2462 // If existing credential is provided, then it must match.
2463 if (savedCredential != null && auth == null) {
2464 throw new RemoteException("Failed to enroll " +
2465 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
2466 : "pattern"));
2467 }
2468
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002469 boolean untrustedReset = false;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002470 if (auth != null) {
Andrew Scull1416bd02018-01-05 18:33:58 +00002471 onAuthTokenKnownForUser(userId, auth);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002472 } else if (response != null
Andrew Scull1416bd02018-01-05 18:33:58 +00002473 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002474 // We are performing an untrusted credential change, by DevicePolicyManager or other
2475 // internal callers that don't provide the existing credential
Rubin Xu3bf722a2016-12-15 16:07:38 +00002476 Slog.w(TAG, "Untrusted credential change invoked");
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002477 // Try to get a cached auth token, so we can keep SP unchanged.
2478 auth = mSpCache.get(userId);
2479 untrustedReset = true;
Rubin Xu8b30ec32017-03-05 00:47:09 +00002480 } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
2481 Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
2482 (response != null ? "rate limit exceeded" : "failed"));
2483 return;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002484 }
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002485
2486 if (auth != null) {
2487 if (untrustedReset) {
2488 // Force change the current SID to mantain existing behaviour that an untrusted
2489 // reset leads to a change of SID. If the untrusted reset is for clearing the
2490 // current password, the nuking of the SID will be done in
2491 // setLockCredentialWithAuthTokenLocked next
2492 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2493 }
2494 setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
2495 userId);
2496 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2497 } else {
2498 throw new IllegalStateException(
2499 "Untrusted credential reset not possible without cached SP");
2500 // Could call initializeSyntheticPasswordLocked(null, credential, credentialType,
2501 // requestedQuality, userId) instead if we still allow untrusted reset that changes
2502 // synthetic password. That would invalidate existing escrow tokens though.
2503 }
Dmitry Dementyev6e167242018-01-25 15:29:50 -08002504 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002505 }
2506
2507 @Override
2508 public long addEscrowToken(byte[] token, int userId) throws RemoteException {
2509 ensureCallerSystemUid();
2510 if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
2511 synchronized (mSpManager) {
2512 enableSyntheticPasswordLocked();
Rubin Xu8b30ec32017-03-05 00:47:09 +00002513 // Migrate to synthetic password based credentials if the user has no password,
Rubin Xuf095f832017-01-31 15:23:34 +00002514 // the token can then be activated immediately.
2515 AuthenticationToken auth = null;
2516 if (!isUserSecure(userId)) {
2517 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2518 auth = initializeSyntheticPasswordLocked(null, null,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002519 LockPatternUtils.CREDENTIAL_TYPE_NONE,
2520 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002521 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
2522 long pwdHandle = getSyntheticPasswordHandleLocked(userId);
2523 auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
Rubin Xucf326f12017-11-15 11:55:35 +00002524 pwdHandle, null, userId, null).authToken;
Rubin Xuf095f832017-01-31 15:23:34 +00002525 }
2526 }
Rubin Xu128180b2017-04-12 18:02:44 +01002527 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2528 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2529 if (!mSpManager.hasEscrowData(userId)) {
2530 throw new SecurityException("Escrow token is disabled on the current user");
2531 }
Rubin Xuf095f832017-01-31 15:23:34 +00002532 }
2533 long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
2534 if (auth != null) {
2535 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2536 }
2537 return handle;
2538 }
2539 }
2540
2541 private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
2542 if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
2543 synchronized (mSpManager) {
Rubin Xue94a7702017-06-20 17:29:57 +01002544 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002545 for (long handle : mSpManager.getPendingTokensForUser(userId)) {
2546 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
2547 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2548 }
2549 }
2550 }
2551
2552 @Override
2553 public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
2554 ensureCallerSystemUid();
2555 synchronized (mSpManager) {
2556 return mSpManager.existsHandle(handle, userId);
2557 }
2558 }
2559
2560 @Override
2561 public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
2562 ensureCallerSystemUid();
2563 synchronized (mSpManager) {
2564 if (handle == getSyntheticPasswordHandleLocked(userId)) {
2565 Slog.w(TAG, "Cannot remove password handle");
2566 return false;
2567 }
2568 if (mSpManager.removePendingToken(handle, userId)) {
2569 return true;
2570 }
2571 if (mSpManager.existsHandle(handle, userId)) {
2572 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
2573 return true;
2574 } else {
2575 return false;
2576 }
2577 }
2578 }
2579
2580 @Override
2581 public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002582 byte[] token, int requestedQuality, int userId) throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002583 ensureCallerSystemUid();
2584 boolean result;
2585 synchronized (mSpManager) {
2586 if (!mSpManager.hasEscrowData(userId)) {
2587 throw new SecurityException("Escrow token is disabled on the current user");
2588 }
2589 result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002590 requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002591 }
2592 if (result) {
2593 synchronized (mSeparateChallengeLock) {
Pavel Grafov28939982017-10-03 15:11:52 +01002594 setSeparateProfileChallengeEnabledLocked(userId, true, null);
Rubin Xuf095f832017-01-31 15:23:34 +00002595 }
2596 notifyPasswordChanged(userId);
Pavel Grafov28939982017-10-03 15:11:52 +01002597 notifySeparateProfileChallengeChanged(userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002598 }
2599 return result;
2600 }
2601
2602 private boolean setLockCredentialWithTokenInternal(String credential, int type,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002603 long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
Andrew Scull1416bd02018-01-05 18:33:58 +00002604 final AuthenticationResult result;
Rubin Xuf095f832017-01-31 15:23:34 +00002605 synchronized (mSpManager) {
Andrew Scull1416bd02018-01-05 18:33:58 +00002606 result = mSpManager.unwrapTokenBasedSyntheticPassword(
Rubin Xuf095f832017-01-31 15:23:34 +00002607 getGateKeeperService(), tokenHandle, token, userId);
2608 if (result.authToken == null) {
2609 Slog.w(TAG, "Invalid escrow token supplied");
2610 return false;
2611 }
Rubin Xu24570e42017-09-19 15:27:21 +01002612 if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2613 // Most likely, an untrusted credential reset happened in the past which
2614 // changed the synthetic password
2615 Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
2616 + "verification.");
2617 return false;
2618 }
Rubin Xu7cf45092017-08-28 11:47:35 +01002619 // Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable()
2620 // called by setLockCredentialWithAuthTokenLocked().
2621 // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
2622 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002623 long oldHandle = getSyntheticPasswordHandleLocked(userId);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002624 setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
2625 requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002626 mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002627 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002628 onAuthTokenKnownForUser(userId, result.authToken);
2629 return true;
Rubin Xuf095f832017-01-31 15:23:34 +00002630 }
2631
2632 @Override
2633 public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
2634 throws RemoteException {
2635 ensureCallerSystemUid();
2636 AuthenticationResult authResult;
2637 synchronized (mSpManager) {
2638 if (!mSpManager.hasEscrowData(userId)) {
2639 throw new SecurityException("Escrow token is disabled on the current user");
2640 }
2641 authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
2642 tokenHandle, token, userId);
2643 if (authResult.authToken == null) {
2644 Slog.w(TAG, "Invalid escrow token supplied");
2645 return;
2646 }
2647 }
2648 unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
Andrew Scull1416bd02018-01-05 18:33:58 +00002649 onAuthTokenKnownForUser(userId, authResult.authToken);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002650 }
2651
2652 @Override
2653 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06002654 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002655
Rubin Xua0a0d352017-05-15 16:18:01 +00002656 pw.println("Current lock settings service state:");
2657 pw.println(String.format("SP Enabled = %b",
2658 mLockPatternUtils.isSyntheticPasswordEnabled()));
Rubin Xu3bf722a2016-12-15 16:07:38 +00002659
Rubin Xua0a0d352017-05-15 16:18:01 +00002660 List<UserInfo> users = mUserManager.getUsers();
2661 for (int user = 0; user < users.size(); user++) {
2662 final int userId = users.get(user).id;
2663 pw.println(" User " + userId);
2664 synchronized (mSpManager) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002665 pw.println(String.format(" SP Handle = %x",
2666 getSyntheticPasswordHandleLocked(userId)));
Rubin Xua0a0d352017-05-15 16:18:01 +00002667 }
2668 try {
2669 pw.println(String.format(" SID = %x",
2670 getGateKeeperService().getSecureUserId(userId)));
2671 } catch (RemoteException e) {
2672 // ignore.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002673 }
2674 }
2675 }
2676
Rubin Xuf095f832017-01-31 15:23:34 +00002677 private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
2678 long ident = Binder.clearCallingIdentity();
2679 try {
2680 // Managed profile should have escrow enabled
2681 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002682 Slog.i(TAG, "Managed profile can have escrow token");
Rubin Xuf095f832017-01-31 15:23:34 +00002683 return;
2684 }
Rubin Xuf34d2f62017-03-20 12:36:35 +00002685 DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
Rubin Xuf095f832017-01-31 15:23:34 +00002686 // Devices with Device Owner should have escrow enabled on all users.
Rubin Xuf34d2f62017-03-20 12:36:35 +00002687 if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002688 Slog.i(TAG, "Corp-owned device can have escrow token");
2689 return;
2690 }
2691 // We could also have a profile owner on the given (non-managed) user for unicorn cases
Rubin Xuf34d2f62017-03-20 12:36:35 +00002692 if (dpm.getProfileOwnerAsUser(userId) != null) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002693 Slog.i(TAG, "User with profile owner can have escrow token");
Rubin Xuf095f832017-01-31 15:23:34 +00002694 return;
2695 }
2696 // If the device is yet to be provisioned (still in SUW), there is still
2697 // a chance that Device Owner will be set on the device later, so postpone
2698 // disabling escrow token for now.
Rubin Xuf34d2f62017-03-20 12:36:35 +00002699 if (!dpm.isDeviceProvisioned()) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002700 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
Rubin Xuf095f832017-01-31 15:23:34 +00002701 return;
2702 }
Rakesh Iyercb18d562017-03-06 18:05:53 -08002703
2704 // Escrow tokens are enabled on automotive builds.
2705 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
2706 return;
2707 }
2708
Rubin Xuf095f832017-01-31 15:23:34 +00002709 // Disable escrow token permanently on all other device/user types.
2710 Slog.i(TAG, "Disabling escrow token on user " + userId);
2711 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2712 mSpManager.destroyEscrowData(userId);
2713 }
2714 } catch (RemoteException e) {
2715 Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
2716 } finally {
2717 Binder.restoreCallingIdentity(ident);
2718 }
2719 }
2720
2721 private void ensureCallerSystemUid() throws SecurityException {
2722 final int callingUid = mInjector.binderGetCallingUid();
2723 if (callingUid != Process.SYSTEM_UID) {
2724 throw new SecurityException("Only system can call this API.");
2725 }
2726 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07002727
2728 private class DeviceProvisionedObserver extends ContentObserver {
2729 private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
2730 Settings.Global.DEVICE_PROVISIONED);
Andrew Scull1416bd02018-01-05 18:33:58 +00002731 private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor(
2732 Settings.Secure.USER_SETUP_COMPLETE);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002733
2734 private boolean mRegistered;
2735
2736 public DeviceProvisionedObserver() {
2737 super(null);
2738 }
2739
2740 @Override
Andrew Scullede482d2018-01-30 13:54:29 +00002741 public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002742 if (mDeviceProvisionedUri.equals(uri)) {
2743 updateRegistration();
2744
2745 if (isProvisioned()) {
2746 Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
2747 reportDeviceSetupComplete();
Adrian Roos454f53f2017-08-08 14:56:42 +02002748 clearFrpCredentialIfOwnerNotSecure();
Adrian Roos7374d3a2017-03-31 14:14:53 -07002749 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002750 } else if (mUserSetupCompleteUri.equals(uri)) {
Andrew Scullede482d2018-01-30 13:54:29 +00002751 tryRemoveUserFromSpCacheLater(userId);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002752 }
2753 }
2754
2755 public void onSystemReady() {
Adrian Roos2adc2632017-09-05 17:01:42 +02002756 if (frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002757 updateRegistration();
2758 } else {
2759 // If we don't intend to use frpCredentials and we're not provisioned yet, send
2760 // deviceSetupComplete immediately, so gatekeeper can discard any lingering
2761 // credentials immediately.
2762 if (!isProvisioned()) {
2763 Slog.i(TAG, "FRP credential disabled, reporting device setup complete "
2764 + "to Gatekeeper immediately");
2765 reportDeviceSetupComplete();
2766 }
2767 }
2768 }
2769
2770 private void reportDeviceSetupComplete() {
2771 try {
2772 getGateKeeperService().reportDeviceSetupComplete();
2773 } catch (RemoteException e) {
2774 Slog.e(TAG, "Failure reporting to IGateKeeperService", e);
2775 }
2776 }
2777
Adrian Roos454f53f2017-08-08 14:56:42 +02002778 /**
2779 * Clears the FRP credential if the user that controls it does not have a secure
2780 * lockscreen.
2781 */
2782 private void clearFrpCredentialIfOwnerNotSecure() {
2783 List<UserInfo> users = mUserManager.getUsers();
2784 for (UserInfo user : users) {
Adrian Roos2adc2632017-09-05 17:01:42 +02002785 if (userOwnsFrpCredential(mContext, user)) {
Adrian Roos454f53f2017-08-08 14:56:42 +02002786 if (!isUserSecure(user.id)) {
2787 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
2788 0, null);
2789 }
2790 return;
2791 }
2792 }
2793 }
2794
Adrian Roos7374d3a2017-03-31 14:14:53 -07002795 private void updateRegistration() {
2796 boolean register = !isProvisioned();
2797 if (register == mRegistered) {
2798 return;
2799 }
2800 if (register) {
2801 mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri,
2802 false, this);
Andrew Scull1416bd02018-01-05 18:33:58 +00002803 mContext.getContentResolver().registerContentObserver(mUserSetupCompleteUri,
2804 false, this, UserHandle.USER_ALL);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002805 } else {
2806 mContext.getContentResolver().unregisterContentObserver(this);
2807 }
2808 mRegistered = register;
2809 }
2810
2811 private boolean isProvisioned() {
2812 return Settings.Global.getInt(mContext.getContentResolver(),
2813 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
2814 }
2815 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07002816}