blob: c6a871217ebd6d24af0023a26de04eaeca291f16 [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 Xu0da89832018-03-26 14:35:34 +010024import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
Rubin Xu1de89b32016-11-30 20:03:13 +000025import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
Rubin Xu3bf722a2016-12-15 16:07:38 +000026import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
27import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
Adrian Roos7374d3a2017-03-31 14:14:53 -070028import static com.android.internal.widget.LockPatternUtils.USER_FRP;
29import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
Adrian Roos454f53f2017-08-08 14:56:42 +020030import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
Rubin Xu1de89b32016-11-30 20:03:13 +000031
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080032import android.annotation.NonNull;
33import android.annotation.Nullable;
Andrew Scull5daf2732016-11-14 15:02:45 +000034import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080035import android.app.ActivityManager;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000036import android.app.IActivityManager;
Kenny Guyb1b30262016-02-09 16:02:35 +000037import android.app.KeyguardManager;
Jim Miller4f93c582016-01-27 19:05:43 -080038import android.app.Notification;
39import android.app.NotificationManager;
40import android.app.PendingIntent;
Adrian Roos230635e2015-01-07 20:50:29 +010041import android.app.admin.DevicePolicyManager;
Pavel Grafov28939982017-10-03 15:11:52 +010042import android.app.admin.DevicePolicyManagerInternal;
Andrew Scull5daf2732016-11-14 15:02:45 +000043import android.app.admin.PasswordMetrics;
Amith Yamasani072543f2015-02-13 11:09:45 -080044import android.app.backup.BackupManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070045import android.app.trust.IStrongAuthTracker;
Clara Bayarri56878a92015-10-29 15:43:55 +000046import android.app.trust.TrustManager;
Robin Leef0246a82014-08-13 09:50:25 +010047import android.content.BroadcastReceiver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070048import android.content.ContentResolver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070049import android.content.Context;
Robin Leef0246a82014-08-13 09:50:25 +010050import android.content.Intent;
51import android.content.IntentFilter;
Jim Miller158fe192013-04-17 15:23:55 -070052import android.content.pm.PackageManager;
Jim Miller187ec582013-04-15 18:27:54 -070053import android.content.pm.UserInfo;
Jim Miller4f93c582016-01-27 19:05:43 -080054import android.content.res.Resources;
Adrian Roos7374d3a2017-03-31 14:14:53 -070055import android.database.ContentObserver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070056import android.database.sqlite.SQLiteDatabase;
Andrew Sculle6527c12018-01-05 18:33:58 +000057import android.hardware.authsecret.V1_0.IAuthSecret;
Adrian Roos7374d3a2017-03-31 14:14:53 -070058import android.net.Uri;
Amith Yamasani52c489c2012-03-28 11:42:42 -070059import android.os.Binder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060060import android.os.Bundle;
Ricky Waib0cdf382016-05-16 17:28:04 +010061import android.os.Handler;
Paul Lawrence945490c2014-03-27 16:37:28 +000062import android.os.IBinder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060063import android.os.IProgressListener;
Ricky Wai4613fe42016-05-24 11:11:42 +010064import android.os.Process;
Amith Yamasani52c489c2012-03-28 11:42:42 -070065import android.os.RemoteException;
Jorim Jaggi2fef6f72016-11-01 19:06:25 -070066import android.os.ResultReceiver;
Paul Lawrence945490c2014-03-27 16:37:28 +000067import android.os.ServiceManager;
Rubin Xu1de89b32016-11-30 20:03:13 +000068import android.os.ShellCallback;
Jeff Sharkeyeddf5182016-08-09 16:36:08 -060069import android.os.StrictMode;
Amith Yamasanid1645f82012-06-12 11:53:26 -070070import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070071import android.os.UserHandle;
Jim Miller187ec582013-04-15 18:27:54 -070072import android.os.UserManager;
Rubin Xu1de89b32016-11-30 20:03:13 +000073import android.os.storage.IStorageManager;
74import android.os.storage.StorageManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -070075import android.provider.Settings;
76import android.provider.Settings.Secure;
Jim Miller187ec582013-04-15 18:27:54 -070077import android.provider.Settings.SettingNotFoundException;
Jim Millerde1af082013-09-11 14:58:26 -070078import android.security.KeyStore;
Ricky Waidc283a82016-03-24 19:55:08 +000079import android.security.keystore.AndroidKeyStoreProvider;
80import android.security.keystore.KeyProperties;
81import android.security.keystore.KeyProtection;
Pavel Grafov0acc4bf2017-08-23 12:20:54 +010082import android.security.keystore.UserNotAuthenticatedException;
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -080083import android.security.keystore.recovery.KeyChainProtectionParams;
Bo Zhu7c1972f2018-02-22 21:43:52 -080084import android.security.keystore.recovery.RecoveryCertPath;
Robert Berry81ee34b2018-01-23 11:59:59 +000085import android.security.keystore.recovery.WrappedApplicationKey;
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -080086import android.security.keystore.recovery.KeyChainSnapshot;
Andres Morales23974272015-05-14 22:42:26 -070087import android.service.gatekeeper.GateKeeperResponse;
Andres Morales8fa56652015-03-31 09:19:50 -070088import android.service.gatekeeper.IGateKeeperService;
Amith Yamasani52c489c2012-03-28 11:42:42 -070089import android.text.TextUtils;
Rubin Xua55b1682017-01-31 10:06:56 +000090import android.util.ArrayMap;
Adrian Roosb953e182017-08-17 17:58:26 +020091import android.util.EventLog;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060092import android.util.Log;
Amith Yamasani52c489c2012-03-28 11:42:42 -070093import android.util.Slog;
Andrew Scull1416bd02018-01-05 18:33:58 +000094import android.util.SparseArray;
Amith Yamasani52c489c2012-03-28 11:42:42 -070095
Pavel Grafov28939982017-10-03 15:11:52 +010096import com.android.internal.annotations.GuardedBy;
Rubin Xu0cbc19e2016-12-09 14:00:21 +000097import com.android.internal.annotations.VisibleForTesting;
Chris Wren282cfef2017-03-27 15:01:44 -040098import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050099import com.android.internal.notification.SystemNotificationChannels;
Amith Yamasani072543f2015-02-13 11:09:45 -0800100import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600101import com.android.internal.util.DumpUtils;
Adrian Roos7374d3a2017-03-31 14:14:53 -0700102import com.android.internal.util.Preconditions;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700103import com.android.internal.widget.ICheckCredentialProgressCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800104import com.android.internal.widget.ILockSettings;
105import com.android.internal.widget.LockPatternUtils;
Rubin Xufcd49f92017-08-24 18:21:52 +0100106import com.android.internal.widget.LockSettingsInternal;
Andres Morales23974272015-05-14 22:42:26 -0700107import com.android.internal.widget.VerifyCredentialResponse;
Pavel Grafov28939982017-10-03 15:11:52 +0100108import com.android.server.LocalServices;
Andrew Scull507d11c2017-05-03 17:19:01 +0100109import com.android.server.SystemService;
110import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800111import com.android.server.locksettings.LockSettingsStorage.PersistentData;
112import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
Andrew Scull507d11c2017-05-03 17:19:01 +0100113import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
114import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800115
Ricky Waidc283a82016-03-24 19:55:08 +0000116import libcore.util.HexEncoding;
117
118import java.io.ByteArrayOutputStream;
Jorim Jaggi2fef6f72016-11-01 19:06:25 -0700119import java.io.FileDescriptor;
Ricky Waidc283a82016-03-24 19:55:08 +0000120import java.io.FileNotFoundException;
121import java.io.IOException;
Rubin Xu3bf722a2016-12-15 16:07:38 +0000122import java.io.PrintWriter;
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000123import java.nio.charset.StandardCharsets;
Ricky Waidc283a82016-03-24 19:55:08 +0000124import java.security.InvalidAlgorithmParameterException;
125import java.security.InvalidKeyException;
126import java.security.KeyStoreException;
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000127import java.security.MessageDigest;
128import java.security.NoSuchAlgorithmException;
Ricky Waidc283a82016-03-24 19:55:08 +0000129import java.security.SecureRandom;
130import java.security.UnrecoverableKeyException;
131import java.security.cert.CertificateException;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700132import java.util.Arrays;
Andrew Sculle6527c12018-01-05 18:33:58 +0000133import java.util.ArrayList;
Jim Miller187ec582013-04-15 18:27:54 -0700134import java.util.List;
Rubin Xua55b1682017-01-31 10:06:56 +0000135import java.util.Map;
Andrew Sculle6527c12018-01-05 18:33:58 +0000136import java.util.NoSuchElementException;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600137import java.util.concurrent.CountDownLatch;
138import java.util.concurrent.TimeUnit;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700139
Ricky Waidc283a82016-03-24 19:55:08 +0000140import javax.crypto.BadPaddingException;
141import javax.crypto.Cipher;
142import javax.crypto.IllegalBlockSizeException;
143import javax.crypto.KeyGenerator;
144import javax.crypto.NoSuchPaddingException;
145import javax.crypto.SecretKey;
146import javax.crypto.spec.GCMParameterSpec;
147
Amith Yamasani52c489c2012-03-28 11:42:42 -0700148/**
Rubin Xu1de89b32016-11-30 20:03:13 +0000149 * Keeps the lock pattern/password data and related settings for each user. Used by
150 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
151 * lockscreen information for secondary users.
152 *
Amith Yamasani52c489c2012-03-28 11:42:42 -0700153 * @hide
154 */
155public class LockSettingsService extends ILockSettings.Stub {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700156 private static final String TAG = "LockSettingsService";
Jim Miller4f93c582016-01-27 19:05:43 -0800157 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
Jim Miller4f93c582016-01-27 19:05:43 -0800158 private static final boolean DEBUG = false;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700159
Ricky Waidc283a82016-03-24 19:55:08 +0000160 private static final int PROFILE_KEY_IV_SIZE = 12;
161 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
Paul Crowley7a0cc0a2017-05-31 22:12:57 +0000162 private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
Rubin Xu1de89b32016-11-30 20:03:13 +0000163
Rubin Xua0a0d352017-05-15 16:18:01 +0000164 // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
Rubin Xue94a7702017-06-20 17:29:57 +0100165 // Do not call into ActivityManager while holding mSpManager lock.
Ricky Waidc283a82016-03-24 19:55:08 +0000166 private final Object mSeparateChallengeLock = new Object();
167
Adrian Roos7374d3a2017-03-31 14:14:53 -0700168 private final DeviceProvisionedObserver mDeviceProvisionedObserver =
169 new DeviceProvisionedObserver();
170
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000171 private final Injector mInjector;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700172 private final Context mContext;
Rubin Xu7cf45092017-08-28 11:47:35 +0100173 @VisibleForTesting
174 protected final Handler mHandler;
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000175 @VisibleForTesting
176 protected final LockSettingsStorage mStorage;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -0800177 private final LockSettingsStrongAuth mStrongAuth;
Victor Changa0940d32016-05-16 19:36:08 +0100178 private final SynchronizedStrongAuthTracker mStrongAuthTracker;
Adrian Roos261d5ab2014-10-29 14:42:38 +0100179
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000180 private final LockPatternUtils mLockPatternUtils;
181 private final NotificationManager mNotificationManager;
182 private final UserManager mUserManager;
183 private final IActivityManager mActivityManager;
Andrew Scull8fc2ec82017-05-19 10:50:36 +0100184 private final SyntheticPasswordManager mSpManager;
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000185
186 private final KeyStore mKeyStore;
187
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800188 private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
189
Paul Lawrence945490c2014-03-27 16:37:28 +0000190 private boolean mFirstCallToVold;
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000191 protected IGateKeeperService mGateKeeperService;
Andrew Sculle6527c12018-01-05 18:33:58 +0000192 protected IAuthSecret mAuthSecretService;
Rubin Xu3bf722a2016-12-15 16:07:38 +0000193
Ricky Wai4613fe42016-05-24 11:11:42 +0100194 /**
195 * The UIDs that are used for system credential storage in keystore.
196 */
Rubin Xu1de89b32016-11-30 20:03:13 +0000197 private static final int[] SYSTEM_CREDENTIAL_UIDS = {
198 Process.WIFI_UID, Process.VPN_UID,
Rubin Xu24b89b12017-04-26 19:44:16 +0100199 Process.ROOT_UID, Process.SYSTEM_UID };
Andres Morales23974272015-05-14 22:42:26 -0700200
Jim Miller4f93c582016-01-27 19:05:43 -0800201 // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
202 // devices. The most basic of these is to show/hide notifications about missing features until
203 // the user unlocks the account and credential-encrypted storage is available.
204 public static final class Lifecycle extends SystemService {
205 private LockSettingsService mLockSettingsService;
206
207 public Lifecycle(Context context) {
208 super(context);
209 }
210
211 @Override
212 public void onStart() {
Ricky Waidc283a82016-03-24 19:55:08 +0000213 AndroidKeyStoreProvider.install();
Jim Miller4f93c582016-01-27 19:05:43 -0800214 mLockSettingsService = new LockSettingsService(getContext());
215 publishBinderService("lock_settings", mLockSettingsService);
216 }
217
218 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200219 public void onBootPhase(int phase) {
220 super.onBootPhase(phase);
221 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
222 mLockSettingsService.migrateOldDataAfterSystemReady();
223 }
224 }
225
226 @Override
Andrew Scull85a63bc2016-10-24 13:47:47 +0100227 public void onStartUser(int userHandle) {
228 mLockSettingsService.onStartUser(userHandle);
Jim Miller4f93c582016-01-27 19:05:43 -0800229 }
230
231 @Override
232 public void onUnlockUser(int userHandle) {
233 mLockSettingsService.onUnlockUser(userHandle);
234 }
235
236 @Override
237 public void onCleanupUser(int userHandle) {
238 mLockSettingsService.onCleanupUser(userHandle);
239 }
240 }
241
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000242 @VisibleForTesting
243 protected static class SynchronizedStrongAuthTracker
244 extends LockPatternUtils.StrongAuthTracker {
Victor Changa0940d32016-05-16 19:36:08 +0100245 public SynchronizedStrongAuthTracker(Context context) {
246 super(context);
247 }
248
249 @Override
250 protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
251 synchronized (this) {
252 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
253 }
254 }
255
256 @Override
257 public int getStrongAuthForUser(int userId) {
258 synchronized (this) {
259 return super.getStrongAuthForUser(userId);
260 }
261 }
262
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000263 void register(LockSettingsStrongAuth strongAuth) {
264 strongAuth.registerStrongAuthTracker(this.mStub);
Victor Changa0940d32016-05-16 19:36:08 +0100265 }
266 }
267
Ricky Waidc283a82016-03-24 19:55:08 +0000268 /**
269 * Tie managed profile to primary profile if it is in unified mode and not tied before.
270 *
271 * @param managedUserId Managed profile user Id
272 * @param managedUserPassword Managed profile original password (when it has separated lock).
273 * NULL when it does not have a separated lock before.
274 */
275 public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
276 if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
277 // Only for managed profile
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000278 if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
Ricky Waidc283a82016-03-24 19:55:08 +0000279 return;
280 }
281 // Do not tie managed profile when work challenge is enabled
282 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
283 return;
284 }
285 // Do not tie managed profile to parent when it's done already
286 if (mStorage.hasChildProfileLock(managedUserId)) {
287 return;
288 }
289 // Do not tie it to parent when parent does not have a screen lock
290 final int parentId = mUserManager.getProfileParent(managedUserId).id;
Rubin Xua55b1682017-01-31 10:06:56 +0000291 if (!isUserSecure(parentId)) {
Ricky Waidc283a82016-03-24 19:55:08 +0000292 if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
293 return;
294 }
Rubin Xubfc7faaf2016-11-22 15:18:32 +0000295 // Do not tie when the parent has no SID (but does have a screen lock).
296 // This can only happen during an upgrade path where SID is yet to be
297 // generated when the user unlocks for the first time.
298 try {
299 if (getGateKeeperService().getSecureUserId(parentId) == 0) {
300 return;
301 }
302 } catch (RemoteException e) {
303 Slog.e(TAG, "Failed to talk to GateKeeper service", e);
304 return;
305 }
Ricky Waidc283a82016-03-24 19:55:08 +0000306 if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
307 byte[] randomLockSeed = new byte[] {};
308 try {
309 randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
310 String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
Adrian Roos7374d3a2017-03-31 14:14:53 -0700311 final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Rubin Xu1de89b32016-11-30 20:03:13 +0000312 setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
Adrian Roos7374d3a2017-03-31 14:14:53 -0700313 managedUserPassword, quality, managedUserId);
Ricky Wai7b9eb412016-05-12 17:29:12 +0100314 // We store a private credential for the managed user that's unlocked by the primary
315 // account holder's credential. As such, the user will never be prompted to enter this
316 // password directly, so we always store a password.
Adrian Roos7374d3a2017-03-31 14:14:53 -0700317 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
Zach Jange61672a2016-11-22 17:47:18 +0000318 tieProfileLockToParent(managedUserId, newPassword);
Ricky Waidc283a82016-03-24 19:55:08 +0000319 } catch (NoSuchAlgorithmException | RemoteException e) {
320 Slog.e(TAG, "Fail to tie managed profile", e);
321 // Nothing client can do to fix this issue, so we do not throw exception out
322 }
323 }
324
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000325 static class Injector {
Jim Millerde1af082013-09-11 14:58:26 -0700326
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000327 protected Context mContext;
328
329 public Injector(Context context) {
330 mContext = context;
331 }
332
333 public Context getContext() {
334 return mContext;
335 }
336
337 public Handler getHandler() {
338 return new Handler();
339 }
340
341 public LockSettingsStorage getStorage() {
342 final LockSettingsStorage storage = new LockSettingsStorage(mContext);
343 storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
344 @Override
345 public void initialize(SQLiteDatabase db) {
346 // Get the lockscreen default from a system property, if available
347 boolean lockScreenDisable = SystemProperties.getBoolean(
348 "ro.lockscreen.disable.default", false);
349 if (lockScreenDisable) {
350 storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
351 }
352 }
353 });
354 return storage;
355 }
356
357 public LockSettingsStrongAuth getStrongAuth() {
358 return new LockSettingsStrongAuth(mContext);
359 }
360
361 public SynchronizedStrongAuthTracker getStrongAuthTracker() {
362 return new SynchronizedStrongAuthTracker(mContext);
363 }
364
365 public IActivityManager getActivityManager() {
366 return ActivityManager.getService();
367 }
368
369 public LockPatternUtils getLockPatternUtils() {
370 return new LockPatternUtils(mContext);
371 }
372
373 public NotificationManager getNotificationManager() {
374 return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
375 }
376
377 public UserManager getUserManager() {
378 return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
379 }
380
Rubin Xu8b30ec32017-03-05 00:47:09 +0000381 public DevicePolicyManager getDevicePolicyManager() {
382 return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
383 }
384
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000385 public KeyStore getKeyStore() {
386 return KeyStore.getInstance();
387 }
388
Dmitry Dementyev29b9de52018-01-31 16:09:32 -0800389 public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
390 return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800391 }
392
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000393 public IStorageManager getStorageManager() {
394 final IBinder service = ServiceManager.getService("mount");
395 if (service != null) {
396 return IStorageManager.Stub.asInterface(service);
397 }
398 return null;
399 }
Rubin Xu3bf722a2016-12-15 16:07:38 +0000400
401 public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200402 return new SyntheticPasswordManager(getContext(), storage, getUserManager());
Rubin Xu3bf722a2016-12-15 16:07:38 +0000403 }
404
405 public int binderGetCallingUid() {
406 return Binder.getCallingUid();
407 }
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000408 }
409
410 public LockSettingsService(Context context) {
411 this(new Injector(context));
412 }
413
414 @VisibleForTesting
415 protected LockSettingsService(Injector injector) {
416 mInjector = injector;
417 mContext = injector.getContext();
418 mKeyStore = injector.getKeyStore();
Dmitry Dementyev29b9de52018-01-31 16:09:32 -0800419 mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000420 mHandler = injector.getHandler();
421 mStrongAuth = injector.getStrongAuth();
422 mActivityManager = injector.getActivityManager();
423
424 mLockPatternUtils = injector.getLockPatternUtils();
Paul Lawrence945490c2014-03-27 16:37:28 +0000425 mFirstCallToVold = true;
Robin Leef0246a82014-08-13 09:50:25 +0100426
427 IntentFilter filter = new IntentFilter();
428 filter.addAction(Intent.ACTION_USER_ADDED);
Adrian Roos3dcae682014-10-29 14:43:56 +0100429 filter.addAction(Intent.ACTION_USER_STARTING);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100430 filter.addAction(Intent.ACTION_USER_REMOVED);
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000431 injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
432 null, null);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100433
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000434 mStorage = injector.getStorage();
435 mNotificationManager = injector.getNotificationManager();
436 mUserManager = injector.getUserManager();
437 mStrongAuthTracker = injector.getStrongAuthTracker();
438 mStrongAuthTracker.register(mStrongAuth);
Rubin Xu3bf722a2016-12-15 16:07:38 +0000439
440 mSpManager = injector.getSyntheticPasswordManager(mStorage);
Rubin Xufcd49f92017-08-24 18:21:52 +0100441
442 LocalServices.addService(LockSettingsInternal.class, new LocalService());
Jim Miller4f93c582016-01-27 19:05:43 -0800443 }
444
445 /**
Rubin Xu1de89b32016-11-30 20:03:13 +0000446 * If the account is credential-encrypted, show notification requesting the user to unlock the
447 * device.
Jim Miller4f93c582016-01-27 19:05:43 -0800448 */
Andrew Scull85a63bc2016-10-24 13:47:47 +0100449 private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
450 final UserInfo user = mUserManager.getUserInfo(userId);
451 if (!user.isManagedProfile()) {
452 // When the user is locked, we communicate it loud-and-clear
453 // on the lockscreen; we only show a notification below for
454 // locked managed profiles.
455 return;
456 }
457
458 final UserHandle userHandle = user.getUserHandle();
Rubin Xua55b1682017-01-31 10:06:56 +0000459 final boolean isSecure = isUserSecure(userId);
Andrew Scull85a63bc2016-10-24 13:47:47 +0100460 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
461 UserInfo parent = mUserManager.getProfileParent(userId);
462 if (parent != null &&
463 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
464 !mUserManager.isQuietModeEnabled(userHandle)) {
465 // Only show notifications for managed profiles once their parent
466 // user is unlocked.
467 showEncryptionNotificationForProfile(userHandle);
Jim Miller4f93c582016-01-27 19:05:43 -0800468 }
Jim Miller4f93c582016-01-27 19:05:43 -0800469 }
470 }
471
Kenny Guyb1b30262016-02-09 16:02:35 +0000472 private void showEncryptionNotificationForProfile(UserHandle user) {
473 Resources r = mContext.getResources();
474 CharSequence title = r.getText(
475 com.android.internal.R.string.user_encrypted_title);
476 CharSequence message = r.getText(
477 com.android.internal.R.string.profile_encrypted_message);
478 CharSequence detail = r.getText(
479 com.android.internal.R.string.profile_encrypted_detail);
480
481 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
Rubin Xu1de89b32016-11-30 20:03:13 +0000482 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
483 user.getIdentifier());
Kenny Guyb1b30262016-02-09 16:02:35 +0000484 if (unlockIntent == null) {
485 return;
486 }
Rubin Xu1de89b32016-11-30 20:03:13 +0000487 unlockIntent.setFlags(
488 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Kenny Guyb1b30262016-02-09 16:02:35 +0000489 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
490 PendingIntent.FLAG_UPDATE_CURRENT);
491
492 showEncryptionNotification(user, title, message, detail, intent);
493 }
494
Rubin Xu1de89b32016-11-30 20:03:13 +0000495 private void showEncryptionNotification(UserHandle user, CharSequence title,
496 CharSequence message, CharSequence detail, PendingIntent intent) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000497 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Jeff Sharkey4a399362016-05-26 09:47:43 -0600498
499 // Suppress all notifications on non-FBE devices for now
500 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
501
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500502 Notification notification =
503 new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
504 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
505 .setWhen(0)
506 .setOngoing(true)
507 .setTicker(title)
508 .setColor(mContext.getColor(
509 com.android.internal.R.color.system_notification_accent_color))
510 .setContentTitle(title)
511 .setContentText(message)
512 .setSubText(detail)
513 .setVisibility(Notification.VISIBILITY_PUBLIC)
514 .setContentIntent(intent)
515 .build();
Chris Wren282cfef2017-03-27 15:01:44 -0400516 mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
517 notification, user);
Jim Miller4f93c582016-01-27 19:05:43 -0800518 }
519
Andrew Scull85a63bc2016-10-24 13:47:47 +0100520 private void hideEncryptionNotification(UserHandle userHandle) {
Rubin Xu1de89b32016-11-30 20:03:13 +0000521 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
Chris Wren282cfef2017-03-27 15:01:44 -0400522 mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
523 userHandle);
Jim Miller4f93c582016-01-27 19:05:43 -0800524 }
525
526 public void onCleanupUser(int userId) {
527 hideEncryptionNotification(new UserHandle(userId));
Rubin Xu0da89832018-03-26 14:35:34 +0100528 // User is stopped with its CE key evicted. Require strong auth next time to be able to
529 // unlock the user's storage. Use STRONG_AUTH_REQUIRED_AFTER_BOOT since stopping and
530 // restarting a user later is equivalent to rebooting the device.
531 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_BOOT, userId);
Jim Miller4f93c582016-01-27 19:05:43 -0800532 }
533
Andrew Scull85a63bc2016-10-24 13:47:47 +0100534 public void onStartUser(final int userId) {
535 maybeShowEncryptionNotificationForUser(userId);
536 }
537
Pavel Grafov0acc4bf2017-08-23 12:20:54 +0100538 /**
539 * Check if profile got unlocked but the keystore is still locked. This happens on full disk
540 * encryption devices since the profile may not yet be running when we consider unlocking it
541 * during the normal flow. In this case unlock the keystore for the profile.
542 */
543 private void ensureProfileKeystoreUnlocked(int userId) {
544 final KeyStore ks = KeyStore.getInstance();
545 if (ks.state(userId) == KeyStore.State.LOCKED
546 && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
547 Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
548 try {
549 // If boot took too long and the password in vold got expired, parent keystore will
550 // be still locked, we ignore this case since the user will be prompted to unlock
551 // the device after boot.
552 unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
553 } catch (RemoteException e) {
554 Slog.e(TAG, "Failed to unlock child profile");
555 }
556 }
557 }
558
Ricky Waib0cdf382016-05-16 17:28:04 +0100559 public void onUnlockUser(final int userId) {
Rubin Xua55b1682017-01-31 10:06:56 +0000560 // Perform tasks which require locks in LSS on a handler, as we are callbacks from
561 // ActivityManager.unlockUser()
562 mHandler.post(new Runnable() {
563 @Override
564 public void run() {
Pavel Grafov0acc4bf2017-08-23 12:20:54 +0100565 ensureProfileKeystoreUnlocked(userId);
Rubin Xua55b1682017-01-31 10:06:56 +0000566 // Hide notification first, as tie managed profile lock takes time
567 hideEncryptionNotification(new UserHandle(userId));
Ricky Waib0cdf382016-05-16 17:28:04 +0100568
Rubin Xua55b1682017-01-31 10:06:56 +0000569 // Now we have unlocked the parent user we should show notifications
570 // about any profiles that exist.
571 List<UserInfo> profiles = mUserManager.getProfiles(userId);
572 for (int i = 0; i < profiles.size(); i++) {
573 UserInfo profile = profiles.get(i);
574 final boolean isSecure = isUserSecure(profile.id);
575 if (isSecure && profile.isManagedProfile()) {
576 UserHandle userHandle = profile.getUserHandle();
577 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
578 !mUserManager.isQuietModeEnabled(userHandle)) {
579 showEncryptionNotificationForProfile(userHandle);
580 }
581 }
582 }
583
584 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
Ricky Waib0cdf382016-05-16 17:28:04 +0100585 tieManagedProfileLockIfNecessary(userId, null);
586 }
Andrew Scullf49794b2018-04-13 12:01:25 +0100587
588 // If the user doesn't have a credential, try and derive their secret for the
589 // AuthSecret HAL. The secret will have been enrolled if the user previously set a
590 // credential and still needs to be passed to the HAL once that credential is
591 // removed.
592 if (mUserManager.getUserInfo(userId).isPrimary() && !isUserSecure(userId)) {
593 tryDeriveAuthTokenForUnsecuredPrimaryUser(userId);
594 }
Kenny Guyb1b30262016-02-09 16:02:35 +0000595 }
Rubin Xua55b1682017-01-31 10:06:56 +0000596 });
Amith Yamasani52c489c2012-03-28 11:42:42 -0700597 }
598
Andrew Scullf49794b2018-04-13 12:01:25 +0100599 private void tryDeriveAuthTokenForUnsecuredPrimaryUser(@UserIdInt int userId) {
600 synchronized (mSpManager) {
601 // Make sure the user has a synthetic password to derive
602 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
603 return;
604 }
605
606 try {
607 final long handle = getSyntheticPasswordHandleLocked(userId);
608 final String noCredential = null;
609 AuthenticationResult result =
610 mSpManager.unwrapPasswordBasedSyntheticPassword(
611 getGateKeeperService(), handle, noCredential, userId, null);
612 if (result.authToken != null) {
613 Slog.i(TAG, "Retrieved auth token for user " + userId);
614 onAuthTokenKnownForUser(userId, result.authToken);
615 } else {
616 Slog.e(TAG, "Auth token not available for user " + userId);
617 }
618 } catch (RemoteException e) {
619 Slog.e(TAG, "Failure retrieving auth token", e);
620 }
621 }
622 }
623
Robin Leef0246a82014-08-13 09:50:25 +0100624 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
625 @Override
626 public void onReceive(Context context, Intent intent) {
Robin Lee1096cf82014-09-01 16:52:47 +0100627 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
Chad Brubaker83ce0952015-05-12 13:00:02 -0700628 // Notify keystore that a new user was added.
Robin Leef0246a82014-08-13 09:50:25 +0100629 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Amith Yamasanif11a5742016-06-16 08:20:07 -0700630 if (userHandle > UserHandle.USER_SYSTEM) {
631 removeUser(userHandle, /* unknownUser= */ true);
632 }
Robin Lee49d810c2014-09-23 13:50:22 +0100633 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +0000634 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
Chad Brubaker83ce0952015-05-12 13:00:02 -0700635 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
636 ks.onUserAdded(userHandle, parentHandle);
Adrian Roos3dcae682014-10-29 14:43:56 +0100637 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
638 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
639 mStorage.prefetchUser(userHandle);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100640 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
641 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
642 if (userHandle > 0) {
Amith Yamasanif11a5742016-06-16 08:20:07 -0700643 removeUser(userHandle, /* unknownUser= */ false);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100644 }
Robin Leef0246a82014-08-13 09:50:25 +0100645 }
646 }
647 };
648
Jim Miller4f93c582016-01-27 19:05:43 -0800649 @Override // binder interface
Amith Yamasani52c489c2012-03-28 11:42:42 -0700650 public void systemReady() {
Adrian Roosb953e182017-08-17 17:58:26 +0200651 if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
652 EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
653 }
654 checkWritePermission(UserHandle.USER_SYSTEM);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700655 migrateOldData();
Andres Morales301ea442015-04-17 09:15:47 -0700656 try {
657 getGateKeeperService();
Rubin Xu7b7424b2017-03-31 18:03:20 +0100658 mSpManager.initWeaverService();
Andres Morales301ea442015-04-17 09:15:47 -0700659 } catch (RemoteException e) {
660 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
661 }
Andrew Sculle6527c12018-01-05 18:33:58 +0000662 // Find the AuthSecret HAL
663 try {
664 mAuthSecretService = IAuthSecret.getService();
665 } catch (NoSuchElementException e) {
666 Slog.i(TAG, "Device doesn't implement AuthSecret HAL");
667 } catch (RemoteException e) {
668 Slog.w(TAG, "Failed to get AuthSecret HAL", e);
669 }
Adrian Roos7374d3a2017-03-31 14:14:53 -0700670 mDeviceProvisionedObserver.onSystemReady();
Xiaohui Chen7c696362015-09-16 09:56:14 -0700671 // TODO: maybe skip this for split system user mode.
672 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
Kevin Chyn4dc098a2017-08-08 15:06:28 -0700673 mStrongAuth.systemReady();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700674 }
675
676 private void migrateOldData() {
Rubin Xufe354472017-11-21 12:05:06 +0000677 // These Settings moved before multi-user was enabled, so we only have to do it for the
678 // root user.
679 if (getString("migrated", null, 0) == null) {
680 final ContentResolver cr = mContext.getContentResolver();
681 for (String validSetting : VALID_SETTINGS) {
682 String value = Settings.Secure.getString(cr, validSetting);
683 if (value != null) {
684 setString(validSetting, value, 0);
Jim Miller187ec582013-04-15 18:27:54 -0700685 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700686 }
Rubin Xufe354472017-11-21 12:05:06 +0000687 // No need to move the password / pattern files. They're already in the right place.
688 setString("migrated", "true", 0);
689 Slog.i(TAG, "Migrated lock settings to new location");
690 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700691
Rubin Xufe354472017-11-21 12:05:06 +0000692 // These Settings changed after multi-user was enabled, hence need to be moved per user.
693 if (getString("migrated_user_specific", null, 0) == null) {
694 final ContentResolver cr = mContext.getContentResolver();
695 List<UserInfo> users = mUserManager.getUsers();
696 for (int user = 0; user < users.size(); user++) {
697 // Migrate owner info
698 final int userId = users.get(user).id;
699 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
700 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
701 if (!TextUtils.isEmpty(ownerInfo)) {
702 setString(OWNER_INFO, ownerInfo, userId);
703 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
Adrian Roos43830582015-04-21 16:04:43 -0700704 }
705
Rubin Xufe354472017-11-21 12:05:06 +0000706 // Migrate owner info enabled. Note there was a bug where older platforms only
707 // stored this value if the checkbox was toggled at least once. The code detects
708 // this case by handling the exception.
709 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
710 boolean enabled;
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100711 try {
Rubin Xufe354472017-11-21 12:05:06 +0000712 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
713 enabled = ivalue != 0;
714 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
715 } catch (SettingNotFoundException e) {
716 // Setting was never stored. Store it if the string is not empty.
717 if (!TextUtils.isEmpty(ownerInfo)) {
718 setLong(OWNER_INFO_ENABLED, 1, userId);
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100719 }
Rubin Xufe354472017-11-21 12:05:06 +0000720 }
721 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
722 }
723 // No need to move the password / pattern files. They're already in the right place.
724 setString("migrated_user_specific", "true", 0);
725 Slog.i(TAG, "Migrated per-user lock settings to new location");
726 }
727
728 // Migrates biometric weak such that the fallback mechanism becomes the primary.
729 if (getString("migrated_biometric_weak", null, 0) == null) {
730 List<UserInfo> users = mUserManager.getUsers();
731 for (int i = 0; i < users.size(); i++) {
732 int userId = users.get(i).id;
733 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
734 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
735 userId);
736 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
737 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
738 userId);
739 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
740 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
741 alternateType,
742 userId);
743 }
744 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
745 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
746 userId);
747 }
748 setString("migrated_biometric_weak", "true", 0);
749 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
750 }
751
752 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
753 // user was present on the system, so if we're upgrading to M and there is more than one
754 // user we disable the flag to remain consistent.
755 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
756 final List<UserInfo> users = mUserManager.getUsers();
757 final int userCount = users.size();
758 int switchableUsers = 0;
759 for (int i = 0; i < userCount; i++) {
760 if (users.get(i).supportsSwitchTo()) {
761 switchableUsers++;
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100762 }
Ricky Wai7b9eb412016-05-12 17:29:12 +0100763 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400764
Rubin Xufe354472017-11-21 12:05:06 +0000765 if (switchableUsers > 1) {
Greg Plesureb2e4532016-11-02 17:10:27 -0400766 for (int i = 0; i < userCount; i++) {
767 int id = users.get(i).id;
Rubin Xufe354472017-11-21 12:05:06 +0000768
769 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
770 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
771 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400772 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400773 }
Rubin Xufe354472017-11-21 12:05:06 +0000774
775 setString("migrated_lockscreen_disabled", "true", 0);
776 Slog.i(TAG, "Migrated lockscreen disabled flag");
777 }
778
779 final List<UserInfo> users = mUserManager.getUsers();
780 for (int i = 0; i < users.size(); i++) {
781 final UserInfo userInfo = users.get(i);
782 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
783 // When managed profile has a unified lock, the password quality stored has 2
784 // possibilities only.
785 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
786 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
787 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
788 // unified lock.
789 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
790 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
791 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
792 // Only possible when it's upgraded from nyc dp3
793 Slog.i(TAG, "Migrated tied profile lock type");
794 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
795 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
796 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
797 // It should not happen
798 Slog.e(TAG, "Invalid tied profile lock type: " + quality);
799 }
800 }
801 try {
802 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
803 java.security.KeyStore keyStore =
804 java.security.KeyStore.getInstance("AndroidKeyStore");
805 keyStore.load(null);
806 if (keyStore.containsAlias(alias)) {
807 keyStore.deleteEntry(alias);
808 }
809 } catch (KeyStoreException | NoSuchAlgorithmException |
810 CertificateException | IOException e) {
811 Slog.e(TAG, "Unable to remove tied profile key", e);
812 }
813 }
814
815 boolean isWatch = mContext.getPackageManager().hasSystemFeature(
816 PackageManager.FEATURE_WATCH);
817 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
818 // and device management the lockscreen must be re-enabled now for users that upgrade.
819 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
820 final int userCount = users.size();
821 for (int i = 0; i < userCount; i++) {
822 int id = users.get(i).id;
823 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
824 }
825 setString("migrated_wear_lockscreen_disabled", "true", 0);
826 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700827 }
828 }
829
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200830 private void migrateOldDataAfterSystemReady() {
831 try {
832 // Migrate the FRP credential to the persistent data block
Adrian Roos2adc2632017-09-05 17:01:42 +0200833 if (LockPatternUtils.frpCredentialEnabled(mContext)
834 && !getBoolean("migrated_frp", false, 0)) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200835 migrateFrpCredential();
836 setBoolean("migrated_frp", true, 0);
837 Slog.i(TAG, "Migrated migrated_frp.");
838 }
839 } catch (RemoteException e) {
840 Slog.e(TAG, "Unable to migrateOldDataAfterSystemReady", e);
841 }
842 }
843
844 /**
845 * Migrate the credential for the FRP credential owner user if the following are satisfied:
846 * - the user has a secure credential
847 * - the FRP credential is not set up
848 * - the credential is based on a synthetic password.
849 */
850 private void migrateFrpCredential() throws RemoteException {
851 if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
852 return;
853 }
854 for (UserInfo userInfo : mUserManager.getUsers()) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200855 if (userOwnsFrpCredential(mContext, userInfo) && isUserSecure(userInfo.id)) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +0200856 synchronized (mSpManager) {
857 if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) {
858 int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
859 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
860
861 mSpManager.migrateFrpPasswordLocked(
862 getSyntheticPasswordHandleLocked(userInfo.id),
863 userInfo,
864 redactActualQualityToMostLenientEquivalentQuality(actualQuality));
865 }
866 }
867 return;
868 }
869 }
870 }
871
872 /**
873 * Returns the lowest password quality that still presents the same UI for entering it.
874 *
875 * For the FRP credential, we do not want to leak the actual quality of the password, only what
876 * kind of UI it requires. However, when migrating, we only know the actual quality, not the
877 * originally requested quality; since this is only used to determine what input variant to
878 * present to the user, we just assume the lowest possible quality was requested.
879 */
880 private int redactActualQualityToMostLenientEquivalentQuality(int quality) {
881 switch (quality) {
882 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
883 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
884 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
885 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
886 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
887 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
888 return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
889 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
890 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
891 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
892 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
893 default:
894 return quality;
895 }
896 }
897
Jim Miller5ecd8112013-01-09 18:50:26 -0800898 private final void checkWritePermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800899 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700900 }
901
Jim Miller5ecd8112013-01-09 18:50:26 -0800902 private final void checkPasswordReadPermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800903 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700904 }
905
Adrian Roosb953e182017-08-17 17:58:26 +0200906 private final void checkPasswordHavePermission(int userId) {
907 if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
908 EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
909 }
910 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
911 }
912
Jim Miller158fe192013-04-17 15:23:55 -0700913 private final void checkReadPermission(String requestedKey, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700914 final int callingUid = Binder.getCallingUid();
Adrian Roos001b00d2015-02-24 17:08:48 +0100915
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000916 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
917 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
918 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
Jim Miller158fe192013-04-17 15:23:55 -0700919 != PackageManager.PERMISSION_GRANTED) {
920 throw new SecurityException("uid=" + callingUid
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000921 + " needs permission " + READ_CONTACTS + " to read "
Jim Miller158fe192013-04-17 15:23:55 -0700922 + requestedKey + " for user " + userId);
923 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700924 }
Adrian Roos001b00d2015-02-24 17:08:48 +0100925
926 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
927 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
928 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
929 != PackageManager.PERMISSION_GRANTED) {
930 throw new SecurityException("uid=" + callingUid
931 + " needs permission " + PERMISSION + " to read "
932 + requestedKey + " for user " + userId);
933 }
934 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700935 }
936
937 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000938 public boolean getSeparateProfileChallengeEnabled(int userId) {
Ricky Wai7f405f12016-05-31 12:05:05 +0100939 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000940 synchronized (mSeparateChallengeLock) {
941 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
942 }
943 }
944
945 @Override
946 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
Rubin Xufe354472017-11-21 12:05:06 +0000947 String managedUserPassword) {
Ricky Wai7f405f12016-05-31 12:05:05 +0100948 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000949 synchronized (mSeparateChallengeLock) {
Pavel Grafov28939982017-10-03 15:11:52 +0100950 setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword);
Ricky Waidc283a82016-03-24 19:55:08 +0000951 }
Pavel Grafov28939982017-10-03 15:11:52 +0100952 notifySeparateProfileChallengeChanged(userId);
953 }
954
955 @GuardedBy("mSeparateChallengeLock")
956 private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
957 String managedUserPassword) {
Pavel Grafovf10ae7e2018-06-25 12:13:38 +0100958 final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
Pavel Grafov28939982017-10-03 15:11:52 +0100959 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
Pavel Grafovf10ae7e2018-06-25 12:13:38 +0100960 try {
961 if (enabled) {
962 mStorage.removeChildProfileLock(userId);
963 removeKeystoreProfileKey(userId);
964 } else {
965 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
966 }
967 } catch (IllegalStateException e) {
968 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, old, userId);
969 throw e;
Pavel Grafov28939982017-10-03 15:11:52 +0100970 }
971 }
972
973 private void notifySeparateProfileChallengeChanged(int userId) {
Andrew Scull7f4ff4c2018-01-05 18:33:58 +0000974 final DevicePolicyManagerInternal dpmi = LocalServices.getService(
975 DevicePolicyManagerInternal.class);
976 if (dpmi != null) {
977 dpmi.reportSeparateProfileChallengeChanged(userId);
978 }
Ricky Waidc283a82016-03-24 19:55:08 +0000979 }
980
981 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000982 public void setBoolean(String key, boolean value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700983 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100984 setStringUnchecked(key, userId, value ? "1" : "0");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700985 }
986
987 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000988 public void setLong(String key, long value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700989 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100990 setStringUnchecked(key, userId, Long.toString(value));
Amith Yamasani52c489c2012-03-28 11:42:42 -0700991 }
992
993 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000994 public void setString(String key, String value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700995 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100996 setStringUnchecked(key, userId, value);
997 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700998
Adrian Roos261d5ab2014-10-29 14:42:38 +0100999 private void setStringUnchecked(String key, int userId, String value) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001000 Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
1001
Adrian Roos261d5ab2014-10-29 14:42:38 +01001002 mStorage.writeKeyValue(key, value, userId);
Amith Yamasani072543f2015-02-13 11:09:45 -08001003 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
1004 BackupManager.dataChanged("com.android.providers.settings");
1005 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001006 }
1007
1008 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +02001009 public boolean getBoolean(String key, boolean defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -07001010 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001011 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001012 return TextUtils.isEmpty(value) ?
1013 defaultValue : (value.equals("1") || value.equals("true"));
1014 }
1015
1016 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +02001017 public long getLong(String key, long defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -07001018 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001019 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001020 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
1021 }
1022
1023 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +02001024 public String getString(String key, String defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -07001025 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001026 return getStringUnchecked(key, defaultValue, userId);
1027 }
1028
1029 public String getStringUnchecked(String key, String defaultValue, int userId) {
1030 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
Adrian Roos7811d9f2015-07-27 15:10:13 -07001031 long ident = Binder.clearCallingIdentity();
1032 try {
1033 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
1034 } finally {
1035 Binder.restoreCallingIdentity(ident);
1036 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001037 }
1038
Adrian Roos7374d3a2017-03-31 14:14:53 -07001039 if (userId == USER_FRP) {
1040 return getFrpStringUnchecked(key);
1041 }
1042
Bryce Lee46145962015-12-14 14:39:10 -08001043 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
1044 key = Settings.Secure.LOCK_PATTERN_ENABLED;
1045 }
1046
Adrian Roos261d5ab2014-10-29 14:42:38 +01001047 return mStorage.readKeyValue(key, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001048 }
1049
Adrian Roos7374d3a2017-03-31 14:14:53 -07001050 private String getFrpStringUnchecked(String key) {
1051 if (LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
1052 return String.valueOf(readFrpPasswordQuality());
1053 }
1054 return null;
1055 }
1056
1057 private int readFrpPasswordQuality() {
1058 return mStorage.readPersistentDataBlock().qualityForUi;
1059 }
1060
Adrian Roos4f788452014-05-22 20:45:59 +02001061 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -07001062 public boolean havePassword(int userId) throws RemoteException {
Adrian Roosb953e182017-08-17 17:58:26 +02001063 checkPasswordHavePermission(userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001064 synchronized (mSpManager) {
1065 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1066 long handle = getSyntheticPasswordHandleLocked(userId);
1067 return mSpManager.getCredentialType(handle, userId) ==
1068 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
1069 }
1070 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001071 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +01001072 return mStorage.hasPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001073 }
1074
1075 @Override
1076 public boolean havePattern(int userId) throws RemoteException {
Adrian Roosb953e182017-08-17 17:58:26 +02001077 checkPasswordHavePermission(userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001078 synchronized (mSpManager) {
1079 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1080 long handle = getSyntheticPasswordHandleLocked(userId);
1081 return mSpManager.getCredentialType(handle, userId) ==
1082 LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
1083 }
1084 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001085 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +01001086 return mStorage.hasPattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001087 }
1088
Rubin Xua55b1682017-01-31 10:06:56 +00001089 private boolean isUserSecure(int userId) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00001090 synchronized (mSpManager) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001091 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1092 long handle = getSyntheticPasswordHandleLocked(userId);
1093 return mSpManager.getCredentialType(handle, userId) !=
1094 LockPatternUtils.CREDENTIAL_TYPE_NONE;
Rubin Xu3bf722a2016-12-15 16:07:38 +00001095 }
1096 }
Rubin Xua55b1682017-01-31 10:06:56 +00001097 return mStorage.hasCredential(userId);
1098 }
1099
Chad Brubakera91a8502015-05-07 10:02:22 -07001100 private void setKeystorePassword(String password, int userHandle) {
Robin Leef0246a82014-08-13 09:50:25 +01001101 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +00001102 ks.onUserPasswordChanged(userHandle, password);
Chad Brubakera91a8502015-05-07 10:02:22 -07001103 }
1104
1105 private void unlockKeystore(String password, int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +00001106 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
Chad Brubakera91a8502015-05-07 10:02:22 -07001107 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +00001108 ks.unlock(userHandle, password);
1109 }
Chad Brubakera91a8502015-05-07 10:02:22 -07001110
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001111 @VisibleForTesting
1112 protected String getDecryptedPasswordForTiedProfile(int userId)
Ricky Waidc283a82016-03-24 19:55:08 +00001113 throws KeyStoreException, UnrecoverableKeyException,
1114 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
1115 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
1116 CertificateException, IOException {
Ricky Wai4613fe42016-05-24 11:11:42 +01001117 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
Ricky Waidc283a82016-03-24 19:55:08 +00001118 byte[] storedData = mStorage.readChildProfileLock(userId);
1119 if (storedData == null) {
1120 throw new FileNotFoundException("Child profile lock file not found");
1121 }
1122 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
1123 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
1124 storedData.length);
1125 byte[] decryptionResult;
1126 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1127 keyStore.load(null);
1128 SecretKey decryptionKey = (SecretKey) keyStore.getKey(
Ricky Waid3982442016-05-24 19:27:08 +01001129 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
Ricky Waidc283a82016-03-24 19:55:08 +00001130
1131 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
1132 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
1133
1134 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
1135 decryptionResult = cipher.doFinal(encryptedPassword);
1136 return new String(decryptionResult, StandardCharsets.UTF_8);
1137 }
1138
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001139 private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
1140 throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001141 try {
Rubin Xu1de89b32016-11-30 20:03:13 +00001142 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
1143 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1144 false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
Ricky Waidc283a82016-03-24 19:55:08 +00001145 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1146 | NoSuchAlgorithmException | NoSuchPaddingException
1147 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1148 | BadPaddingException | CertificateException | IOException e) {
1149 if (e instanceof FileNotFoundException) {
1150 Slog.i(TAG, "Child profile key not found");
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001151 } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
1152 Slog.i(TAG, "Parent keystore seems locked, ignoring");
Clara Bayarri0a587d22016-02-23 14:49:41 -08001153 } else {
Ricky Waidc283a82016-03-24 19:55:08 +00001154 Slog.e(TAG, "Failed to decrypt child profile key", e);
Clara Bayarri0a587d22016-02-23 14:49:41 -08001155 }
Jim Millerde1af082013-09-11 14:58:26 -07001156 }
1157 }
1158
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001159 private void unlockUser(int userId, byte[] token, byte[] secret) {
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001160 // TODO: make this method fully async so we can update UI with progress strings
1161 final CountDownLatch latch = new CountDownLatch(1);
1162 final IProgressListener listener = new IProgressListener.Stub() {
1163 @Override
1164 public void onStarted(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001165 Log.d(TAG, "unlockUser started");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001166 }
1167
1168 @Override
1169 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001170 Log.d(TAG, "unlockUser progress " + progress);
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001171 }
1172
1173 @Override
1174 public void onFinished(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001175 Log.d(TAG, "unlockUser finished");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001176 latch.countDown();
1177 }
1178 };
1179
Jeff Sharkey8924e872015-11-30 12:52:10 -07001180 try {
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001181 mActivityManager.unlockUser(userId, token, secret, listener);
Jeff Sharkey8924e872015-11-30 12:52:10 -07001182 } catch (RemoteException e) {
1183 throw e.rethrowAsRuntimeException();
1184 }
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001185
1186 try {
1187 latch.await(15, TimeUnit.SECONDS);
1188 } catch (InterruptedException e) {
1189 Thread.currentThread().interrupt();
1190 }
Ricky Waidc283a82016-03-24 19:55:08 +00001191 try {
1192 if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
1193 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1194 for (UserInfo pi : profiles) {
1195 // Unlock managed profile with unified lock
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001196 if (tiedManagedProfileReadyToUnlock(pi)) {
1197 unlockChildProfile(pi.id, false /* ignoreUserNotAuthenticated */);
Ricky Waidc283a82016-03-24 19:55:08 +00001198 }
1199 }
1200 }
1201 } catch (RemoteException e) {
1202 Log.d(TAG, "Failed to unlock child profile", e);
1203 }
Jeff Sharkey8924e872015-11-30 12:52:10 -07001204 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001205
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001206 private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
1207 return userInfo.isManagedProfile()
1208 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id)
1209 && mStorage.hasChildProfileLock(userInfo.id)
1210 && mUserManager.isUserRunning(userInfo.id);
1211 }
1212
Rubin Xua55b1682017-01-31 10:06:56 +00001213 private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
1214 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1215 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001216 }
Rubin Xua55b1682017-01-31 10:06:56 +00001217 Map<Integer, String> result = new ArrayMap<Integer, String>();
1218 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1219 final int size = profiles.size();
1220 for (int i = 0; i < size; i++) {
1221 final UserInfo profile = profiles.get(i);
1222 if (!profile.isManagedProfile()) {
1223 continue;
1224 }
1225 final int managedUserId = profile.id;
1226 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1227 continue;
1228 }
1229 try {
Rubin Xu4f988c92017-09-12 16:25:26 +01001230 result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId));
Rubin Xua55b1682017-01-31 10:06:56 +00001231 } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
1232 | NoSuchPaddingException | InvalidKeyException
1233 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1234 | BadPaddingException | CertificateException | IOException e) {
Rubin Xu4f988c92017-09-12 16:25:26 +01001235 Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " +
1236 managedUserId, e);
Rubin Xua55b1682017-01-31 10:06:56 +00001237 }
1238 }
1239 return result;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001240 }
1241
Rubin Xua55b1682017-01-31 10:06:56 +00001242 /**
1243 * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1244 * depending on the parent user's secure state.
1245 *
1246 * When clearing tied work challenges, a pre-computed password table for profiles are required,
1247 * since changing password for profiles requires existing password, and existing passwords can
1248 * only be computed before the parent user's password is cleared.
1249 *
1250 * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1251 * method again on profiles. However the recursion is guaranteed to terminate as this method
1252 * terminates when the user is a managed profile.
1253 */
1254 private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1255 Map<Integer, String> profilePasswordMap) throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001256 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1257 return;
1258 }
Rubin Xua55b1682017-01-31 10:06:56 +00001259 final boolean isSecure = isUserSecure(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001260 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1261 final int size = profiles.size();
1262 for (int i = 0; i < size; i++) {
1263 final UserInfo profile = profiles.get(i);
1264 if (profile.isManagedProfile()) {
1265 final int managedUserId = profile.id;
1266 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1267 continue;
1268 }
1269 if (isSecure) {
1270 tieManagedProfileLockIfNecessary(managedUserId, null);
1271 } else {
Rubin Xua55b1682017-01-31 10:06:56 +00001272 // We use cached work profile password computed before clearing the parent's
1273 // credential, otherwise they get lost
1274 if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
1275 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001276 profilePasswordMap.get(managedUserId),
1277 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
Rubin Xua55b1682017-01-31 10:06:56 +00001278 } else {
1279 Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
1280 // Supplying null here would lead to untrusted credential change
1281 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001282 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
Rubin Xua55b1682017-01-31 10:06:56 +00001283 }
Ricky Waidc283a82016-03-24 19:55:08 +00001284 mStorage.removeChildProfileLock(managedUserId);
1285 removeKeystoreProfileKey(managedUserId);
1286 }
1287 }
1288 }
1289 }
Andres Morales8fa56652015-03-31 09:19:50 -07001290
Ricky Waidc283a82016-03-24 19:55:08 +00001291 private boolean isManagedProfileWithUnifiedLock(int userId) {
1292 return mUserManager.getUserInfo(userId).isManagedProfile()
1293 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1294 }
1295
1296 private boolean isManagedProfileWithSeparatedLock(int userId) {
1297 return mUserManager.getUserInfo(userId).isManagedProfile()
1298 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1299 }
1300
1301 // This method should be called by LockPatternUtil only, all internal methods in this class
Rubin Xu1de89b32016-11-30 20:03:13 +00001302 // should call setLockCredentialInternal.
Amith Yamasani52c489c2012-03-28 11:42:42 -07001303 @Override
Adrian Roos7374d3a2017-03-31 14:14:53 -07001304 public void setLockCredential(String credential, int type, String savedCredential,
1305 int requestedQuality, int userId)
Andres Morales8fa56652015-03-31 09:19:50 -07001306 throws RemoteException {
Jim Millere484eaf2016-04-13 16:35:36 -07001307 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001308 synchronized (mSeparateChallengeLock) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001309 setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
Pavel Grafov28939982017-10-03 15:11:52 +01001310 setSeparateProfileChallengeEnabledLocked(userId, true, null);
Andrew Scull5daf2732016-11-14 15:02:45 +00001311 notifyPasswordChanged(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001312 }
Pavel Grafov28939982017-10-03 15:11:52 +01001313 notifySeparateProfileChallengeChanged(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001314 }
1315
Rubin Xu1de89b32016-11-30 20:03:13 +00001316 private void setLockCredentialInternal(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001317 String savedCredential, int requestedQuality, int userId) throws RemoteException {
Rubin Xudf406d82017-02-16 16:49:43 +00001318 // Normalize savedCredential and credential such that empty string is always represented
1319 // as null.
1320 if (TextUtils.isEmpty(savedCredential)) {
1321 savedCredential = null;
1322 }
1323 if (TextUtils.isEmpty(credential)) {
1324 credential = null;
1325 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001326 synchronized (mSpManager) {
1327 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1328 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001329 requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001330 return;
1331 }
1332 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001333
Rubin Xu1de89b32016-11-30 20:03:13 +00001334 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1335 if (credential != null) {
1336 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
1337 }
Paul Crowleycc701552016-05-17 14:18:49 -07001338 clearUserKeyProtection(userId);
Andres Moralescfb61602015-04-16 16:31:15 -07001339 getGateKeeperService().clearSecureUserId(userId);
Rubin Xu1de89b32016-11-30 20:03:13 +00001340 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
Chad Brubakera91a8502015-05-07 10:02:22 -07001341 setKeystorePassword(null, userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001342 fixateNewestUserKeyAuth(userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001343 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
Andrew Scull5daf2732016-11-14 15:02:45 +00001344 notifyActivePasswordMetricsAvailable(null, userId);
Dmitry Dementyev77183ef2018-01-05 15:46:00 -08001345 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001346 return;
1347 }
Rubin Xu1de89b32016-11-30 20:03:13 +00001348 if (credential == null) {
1349 throw new RemoteException("Null credential with mismatched credential type");
Andres Morales8fa56652015-03-31 09:19:50 -07001350 }
Rubin Xua55b1682017-01-31 10:06:56 +00001351
1352 CredentialHash currentHandle = mStorage.readCredentialHash(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001353 if (isManagedProfileWithUnifiedLock(userId)) {
1354 // get credential from keystore when managed profile has unified lock
Rubin Xua55b1682017-01-31 10:06:56 +00001355 if (savedCredential == null) {
1356 try {
1357 savedCredential = getDecryptedPasswordForTiedProfile(userId);
1358 } catch (FileNotFoundException e) {
1359 Slog.i(TAG, "Child profile key not found");
1360 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1361 | NoSuchAlgorithmException | NoSuchPaddingException
1362 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1363 | BadPaddingException | CertificateException | IOException e) {
1364 Slog.e(TAG, "Failed to decrypt child profile key", e);
1365 }
Andres Morales8fa56652015-03-31 09:19:50 -07001366 }
Ricky Waidc283a82016-03-24 19:55:08 +00001367 } else {
Rubin Xua55b1682017-01-31 10:06:56 +00001368 if (currentHandle.hash == null) {
Ricky Waidc283a82016-03-24 19:55:08 +00001369 if (savedCredential != null) {
1370 Slog.w(TAG, "Saved credential provided, but none stored");
1371 }
1372 savedCredential = null;
1373 }
Andres Morales8fa56652015-03-31 09:19:50 -07001374 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001375 synchronized (mSpManager) {
1376 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1377 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001378 currentHandle.type, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001379 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001380 requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001381 return;
1382 }
1383 }
1384 if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001385 byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
Rubin Xu1de89b32016-11-30 20:03:13 +00001386 userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001387 if (enrolledHandle != null) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001388 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
1389 mStorage.writeCredentialHash(willStore, userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001390 // push new secret and auth token to vold
1391 GateKeeperResponse gkResponse = getGateKeeperService()
1392 .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
1393 setUserKeyProtection(userId, credential, convertResponse(gkResponse));
Paul Crowleycc701552016-05-17 14:18:49 -07001394 fixateNewestUserKeyAuth(userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001395 // Refresh the auth token
1396 doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
1397 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
Dmitry Dementyev6e167242018-01-25 15:29:50 -08001398 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential,
1399 userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001400 } else {
Rubin Xu1de89b32016-11-30 20:03:13 +00001401 throw new RemoteException("Failed to enroll " +
1402 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
1403 : "pattern"));
Andres Morales8fa56652015-03-31 09:19:50 -07001404 }
1405 }
1406
Rubin Xua55b1682017-01-31 10:06:56 +00001407 private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001408 return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
Rubin Xua55b1682017-01-31 10:06:56 +00001409 }
1410
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001411 @VisibleForTesting
1412 protected void tieProfileLockToParent(int userId, String password) {
Ricky Waidc283a82016-03-24 19:55:08 +00001413 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1414 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1415 byte[] encryptionResult;
1416 byte[] iv;
1417 try {
1418 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1419 keyGenerator.init(new SecureRandom());
1420 SecretKey secretKey = keyGenerator.generateKey();
Ricky Waidc283a82016-03-24 19:55:08 +00001421 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1422 keyStore.load(null);
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001423 try {
1424 keyStore.setEntry(
1425 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1426 new java.security.KeyStore.SecretKeyEntry(secretKey),
1427 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1428 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1429 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1430 .build());
1431 keyStore.setEntry(
1432 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1433 new java.security.KeyStore.SecretKeyEntry(secretKey),
1434 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1435 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1436 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1437 .setUserAuthenticationRequired(true)
1438 .setUserAuthenticationValidityDurationSeconds(30)
Pavel Grafove053c1e2017-08-08 16:53:32 +01001439 .setCriticalToDeviceEncryption(true)
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001440 .build());
1441 // Key imported, obtain a reference to it.
1442 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1443 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1444 Cipher cipher = Cipher.getInstance(
1445 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1446 + KeyProperties.ENCRYPTION_PADDING_NONE);
1447 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1448 encryptionResult = cipher.doFinal(randomLockSeed);
1449 iv = cipher.getIV();
1450 } finally {
1451 // The original key can now be discarded.
1452 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1453 }
Ricky Waidc283a82016-03-24 19:55:08 +00001454 } catch (CertificateException | UnrecoverableKeyException
Zach Jange61672a2016-11-22 17:47:18 +00001455 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
Ricky Waidc283a82016-03-24 19:55:08 +00001456 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1457 throw new RuntimeException("Failed to encrypt key", e);
1458 }
1459 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1460 try {
1461 if (iv.length != PROFILE_KEY_IV_SIZE) {
1462 throw new RuntimeException("Invalid iv length: " + iv.length);
1463 }
1464 outputStream.write(iv);
1465 outputStream.write(encryptionResult);
1466 } catch (IOException e) {
1467 throw new RuntimeException("Failed to concatenate byte arrays", e);
1468 }
1469 mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1470 }
1471
Andres Morales8fa56652015-03-31 09:19:50 -07001472 private byte[] enrollCredential(byte[] enrolledHandle,
1473 String enrolledCredential, String toEnroll, int userId)
1474 throws RemoteException {
Jim Millerde1af082013-09-11 14:58:26 -07001475 checkWritePermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001476 byte[] enrolledCredentialBytes = enrolledCredential == null
1477 ? null
1478 : enrolledCredential.getBytes();
1479 byte[] toEnrollBytes = toEnroll == null
1480 ? null
1481 : toEnroll.getBytes();
Andres Morales23974272015-05-14 22:42:26 -07001482 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1483 enrolledCredentialBytes, toEnrollBytes);
Jim Millerde1af082013-09-11 14:58:26 -07001484
Andres Morales23974272015-05-14 22:42:26 -07001485 if (response == null) {
1486 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001487 }
Jim Millerde1af082013-09-11 14:58:26 -07001488
Andres Morales23974272015-05-14 22:42:26 -07001489 byte[] hash = response.getPayload();
1490 if (hash != null) {
1491 setKeystorePassword(toEnroll, userId);
1492 } else {
1493 // Should not happen
1494 Slog.e(TAG, "Throttled while enrolling a password");
1495 }
Andres Morales8fa56652015-03-31 09:19:50 -07001496 return hash;
Jim Millerde1af082013-09-11 14:58:26 -07001497 }
1498
Rubin Xu3bf722a2016-12-15 16:07:38 +00001499 private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
1500 if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1501 addUserKeyAuth(userId, null, key);
1502 }
1503
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001504 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1505 throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001506 if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001507 if (vcr == null) {
1508 throw new RemoteException("Null response verifying a credential we just set");
1509 }
1510 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1511 throw new RemoteException("Non-OK response verifying a credential we just set: "
Rubin Xu1de89b32016-11-30 20:03:13 +00001512 + vcr.getResponseCode());
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001513 }
1514 byte[] token = vcr.getPayload();
1515 if (token == null) {
1516 throw new RemoteException("Empty payload verifying a credential we just set");
1517 }
Paul Crowleycc701552016-05-17 14:18:49 -07001518 addUserKeyAuth(userId, token, secretFromCredential(credential));
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001519 }
1520
1521 private void clearUserKeyProtection(int userId) throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001522 if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001523 addUserKeyAuth(userId, null, null);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001524 }
1525
1526 private static byte[] secretFromCredential(String credential) throws RemoteException {
1527 try {
1528 MessageDigest digest = MessageDigest.getInstance("SHA-512");
1529 // Personalize the hash
1530 byte[] personalization = "Android FBE credential hash"
1531 .getBytes(StandardCharsets.UTF_8);
1532 // Pad it to the block size of the hash function
1533 personalization = Arrays.copyOf(personalization, 128);
1534 digest.update(personalization);
1535 digest.update(credential.getBytes(StandardCharsets.UTF_8));
1536 return digest.digest();
1537 } catch (NoSuchAlgorithmException e) {
1538 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1539 }
1540 }
1541
Paul Crowleycc701552016-05-17 14:18:49 -07001542 private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001543 throws RemoteException {
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001544 final UserInfo userInfo = mUserManager.getUserInfo(userId);
1545 final IStorageManager storageManager = mInjector.getStorageManager();
Paul Crowley815036f2016-03-29 14:14:48 -07001546 final long callingId = Binder.clearCallingIdentity();
1547 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001548 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
Paul Crowley815036f2016-03-29 14:14:48 -07001549 } finally {
1550 Binder.restoreCallingIdentity(callingId);
1551 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001552 }
1553
Paul Crowleycc701552016-05-17 14:18:49 -07001554 private void fixateNewestUserKeyAuth(int userId)
1555 throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001556 if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001557 final IStorageManager storageManager = mInjector.getStorageManager();
Toni Barzic6c818722016-05-27 09:18:39 -07001558 final long callingId = Binder.clearCallingIdentity();
1559 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001560 storageManager.fixateNewestUserKeyAuth(userId);
Toni Barzic6c818722016-05-27 09:18:39 -07001561 } finally {
1562 Binder.restoreCallingIdentity(callingId);
1563 }
Paul Crowleycc701552016-05-17 14:18:49 -07001564 }
1565
Jim Millerde1af082013-09-11 14:58:26 -07001566 @Override
Ricky Wai4613fe42016-05-24 11:11:42 +01001567 public void resetKeyStore(int userId) throws RemoteException {
Ricky Wai7f405f12016-05-31 12:05:05 +01001568 checkWritePermission(userId);
Ricky Wai4613fe42016-05-24 11:11:42 +01001569 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1570 int managedUserId = -1;
1571 String managedUserDecryptedPassword = null;
1572 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1573 for (UserInfo pi : profiles) {
1574 // Unlock managed profile with unified lock
1575 if (pi.isManagedProfile()
1576 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1577 && mStorage.hasChildProfileLock(pi.id)) {
1578 try {
1579 if (managedUserId == -1) {
1580 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1581 managedUserId = pi.id;
1582 } else {
1583 // Should not happen
1584 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1585 + ", uid2:" + pi.id);
1586 }
1587 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1588 | NoSuchAlgorithmException | NoSuchPaddingException
1589 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1590 | BadPaddingException | CertificateException | IOException e) {
1591 Slog.e(TAG, "Failed to decrypt child profile key", e);
1592 }
1593 }
1594 }
1595 try {
1596 // Clear all the users credentials could have been installed in for this user.
1597 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1598 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1599 mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1600 }
1601 }
1602 } finally {
1603 if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1604 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
Zach Jange61672a2016-11-22 17:47:18 +00001605 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
Ricky Wai4613fe42016-05-24 11:11:42 +01001606 }
1607 }
1608 }
1609
1610 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001611 public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001612 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xu1de89b32016-11-30 20:03:13 +00001613 checkPasswordReadPermission(userId);
1614 return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001615 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001616
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001617 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001618 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
1619 int userId) throws RemoteException {
1620 checkPasswordReadPermission(userId);
1621 return doVerifyCredential(credential, type, true, challenge, userId,
1622 null /* progressCallback */);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001623 }
1624
Rubin Xu1de89b32016-11-30 20:03:13 +00001625 /**
1626 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
1627 * format.
1628 */
1629 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001630 boolean hasChallenge, long challenge, int userId,
1631 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xu1de89b32016-11-30 20:03:13 +00001632 if (TextUtils.isEmpty(credential)) {
1633 throw new IllegalArgumentException("Credential can't be null or empty");
1634 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001635 if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
1636 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
1637 Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
1638 return VerifyCredentialResponse.ERROR;
1639 }
Rubin Xue94a7702017-06-20 17:29:57 +01001640 VerifyCredentialResponse response = null;
1641 response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
1642 userId, progressCallback);
1643 // The user employs synthetic password based credential.
1644 if (response != null) {
Robert Berry40386df2018-01-22 21:16:58 +00001645 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1646 mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
1647 userId);
1648 }
Rubin Xue94a7702017-06-20 17:29:57 +01001649 return response;
Rubin Xu3bf722a2016-12-15 16:07:38 +00001650 }
Rubin Xue94a7702017-06-20 17:29:57 +01001651
Adrian Roos7374d3a2017-03-31 14:14:53 -07001652 if (userId == USER_FRP) {
Andrew Scull971f2942017-07-12 15:09:45 +01001653 Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
1654 return VerifyCredentialResponse.ERROR;
Adrian Roos7374d3a2017-03-31 14:14:53 -07001655 }
1656
Andrew Scull971f2942017-07-12 15:09:45 +01001657 final CredentialHash storedHash = mStorage.readCredentialHash(userId);
Rubin Xu1de89b32016-11-30 20:03:13 +00001658 if (storedHash.type != credentialType) {
1659 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
1660 + " stored: " + storedHash.type + " passed in: " + credentialType);
1661 return VerifyCredentialResponse.ERROR;
1662 }
Andres Moralese40bad82015-05-28 14:21:36 -07001663
Rubin Xu1de89b32016-11-30 20:03:13 +00001664 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1665 && storedHash.isBaseZeroPattern;
Andres Moralese40bad82015-05-28 14:21:36 -07001666
Rubin Xu1de89b32016-11-30 20:03:13 +00001667 String credentialToVerify;
1668 if (shouldReEnrollBaseZero) {
1669 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
1670 } else {
1671 credentialToVerify = credential;
1672 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001673
Rubin Xue94a7702017-06-20 17:29:57 +01001674 response = verifyCredential(userId, storedHash, credentialToVerify,
Rubin Xu1de89b32016-11-30 20:03:13 +00001675 hasChallenge, challenge, progressCallback);
Andres Morales59ef1262015-06-26 13:56:39 -07001676
Michal Karpinskie71f5832017-01-13 18:18:49 +00001677 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1678 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1679 if (shouldReEnrollBaseZero) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001680 setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
1681 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
Michal Karpinskie71f5832017-01-13 18:18:49 +00001682 }
Rubin Xu1de89b32016-11-30 20:03:13 +00001683 }
Andres Moralese40bad82015-05-28 14:21:36 -07001684
Rubin Xu1de89b32016-11-30 20:03:13 +00001685 return response;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001686 }
1687
1688 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001689 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
Ricky Wai53940d42016-04-05 15:29:24 +01001690 long challenge, int userId) throws RemoteException {
1691 checkPasswordReadPermission(userId);
1692 if (!isManagedProfileWithUnifiedLock(userId)) {
1693 throw new RemoteException("User id must be managed profile with unified lock");
1694 }
1695 final int parentProfileId = mUserManager.getProfileParent(userId).id;
1696 // Unlock parent by using parent's challenge
Rubin Xu1de89b32016-11-30 20:03:13 +00001697 final VerifyCredentialResponse parentResponse = doVerifyCredential(
1698 credential,
1699 type,
1700 true /* hasChallenge */,
1701 challenge,
1702 parentProfileId,
1703 null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001704 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1705 // Failed, just return parent's response
1706 return parentResponse;
1707 }
1708
1709 try {
1710 // Unlock work profile, and work profile with unified lock must use password only
Rubin Xu1de89b32016-11-30 20:03:13 +00001711 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
1712 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1713 true,
Ricky Wai53940d42016-04-05 15:29:24 +01001714 challenge,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001715 userId, null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001716 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1717 | NoSuchAlgorithmException | NoSuchPaddingException
1718 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1719 | BadPaddingException | CertificateException | IOException e) {
1720 Slog.e(TAG, "Failed to decrypt child profile key", e);
1721 throw new RemoteException("Unable to get tied profile token");
1722 }
1723 }
1724
Rubin Xu1de89b32016-11-30 20:03:13 +00001725 /**
1726 * Lowest-level credential verification routine that talks to GateKeeper. If verification
1727 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
1728 * hash to GK.
1729 */
Andres Morales23974272015-05-14 22:42:26 -07001730 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
Rubin Xu1de89b32016-11-30 20:03:13 +00001731 String credential, boolean hasChallenge, long challenge,
1732 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Andres Morales23974272015-05-14 22:42:26 -07001733 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1734 // don't need to pass empty credentials to GateKeeper
1735 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001736 }
1737
Andrew Zeng750563e2017-03-10 15:14:08 -08001738 if (storedHash == null || TextUtils.isEmpty(credential)) {
Andres Morales23974272015-05-14 22:42:26 -07001739 return VerifyCredentialResponse.ERROR;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001740 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001741
Jeff Sharkeyeddf5182016-08-09 16:36:08 -06001742 // We're potentially going to be doing a bunch of disk I/O below as part
1743 // of unlocking the user, so yell if calling from the main thread.
1744 StrictMode.noteDiskRead();
1745
Andres Morales8fa56652015-03-31 09:19:50 -07001746 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001747 final byte[] hash;
1748 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1749 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
1750 } else {
Rubin Xuf01e9072018-03-30 20:59:28 +01001751 hash = mLockPatternUtils.legacyPasswordToHash(credential, userId)
1752 .getBytes(StandardCharsets.UTF_8);
Rubin Xu1de89b32016-11-30 20:03:13 +00001753 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001754 if (Arrays.equals(hash, storedHash.hash)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001755 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1756 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
1757 } else {
1758 unlockKeystore(credential, userId);
1759 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001760 // Users with legacy credentials don't have credential-backed
1761 // FBE keys, so just pass through a fake token/secret
1762 Slog.i(TAG, "Unlocking user with fake token: " + userId);
1763 final byte[] fakeToken = String.valueOf(userId).getBytes();
1764 unlockUser(userId, fakeToken, fakeToken);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001765
Andres Morales23974272015-05-14 22:42:26 -07001766 // migrate credential to GateKeeper
Adrian Roos7374d3a2017-03-31 14:14:53 -07001767 setLockCredentialInternal(credential, storedHash.type, null,
1768 storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1769 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1770 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1771 /* TODO(roosa): keep the same password quality */, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001772 if (!hasChallenge) {
Andrew Scull5daf2732016-11-14 15:02:45 +00001773 notifyActivePasswordMetricsAvailable(credential, userId);
Robert Berryf899bff2017-12-28 17:34:38 +00001774 // Use credentials to create recoverable keystore snapshot.
1775 mRecoverableKeyStoreManager.lockScreenSecretAvailable(
1776 storedHash.type, credential, userId);
Andres Morales23974272015-05-14 22:42:26 -07001777 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001778 }
1779 // Fall through to get the auth token. Technically this should never happen,
Andres Morales23974272015-05-14 22:42:26 -07001780 // as a user that had a legacy credential would have to unlock their device
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001781 // before getting to a flow with a challenge, but supporting for consistency.
1782 } else {
Andres Morales23974272015-05-14 22:42:26 -07001783 return VerifyCredentialResponse.ERROR;
Andres Morales8fa56652015-03-31 09:19:50 -07001784 }
Andres Morales8fa56652015-03-31 09:19:50 -07001785 }
Paul Crowley98e0a262016-02-04 09:41:53 +00001786 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1787 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
Rubin Xua55b1682017-01-31 10:06:56 +00001788 VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
1789 boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
Andres Morales8fa56652015-03-31 09:19:50 -07001790
Andres Morales23974272015-05-14 22:42:26 -07001791 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001792
Andres Morales23974272015-05-14 22:42:26 -07001793 // credential has matched
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001794
1795 if (progressCallback != null) {
1796 progressCallback.onCredentialVerified();
1797 }
Andrew Scull5daf2732016-11-14 15:02:45 +00001798 notifyActivePasswordMetricsAvailable(credential, userId);
Andres Morales23974272015-05-14 22:42:26 -07001799 unlockKeystore(credential, userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001800
Rubin Xu3bf722a2016-12-15 16:07:38 +00001801 Slog.i(TAG, "Unlocking user " + userId + " with token length "
1802 + response.getPayload().length);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001803 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001804
Ricky Waidc283a82016-03-24 19:55:08 +00001805 if (isManagedProfileWithSeparatedLock(userId)) {
Clara Bayarri56878a92015-10-29 15:43:55 +00001806 TrustManager trustManager =
1807 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1808 trustManager.setDeviceLockedForUser(userId, false);
1809 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001810 int reEnrollQuality = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1811 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1812 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1813 /* TODO(roosa): keep the same password quality */;
Andres Morales23974272015-05-14 22:42:26 -07001814 if (shouldReEnroll) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001815 setLockCredentialInternal(credential, storedHash.type, credential,
1816 reEnrollQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001817 } else {
1818 // Now that we've cleared of all required GK migration, let's do the final
1819 // migration to synthetic password.
1820 synchronized (mSpManager) {
1821 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
Rubin Xu128180b2017-04-12 18:02:44 +01001822 AuthenticationToken auth = initializeSyntheticPasswordLocked(
Adrian Roos7374d3a2017-03-31 14:14:53 -07001823 storedHash.hash, credential, storedHash.type, reEnrollQuality,
1824 userId);
Rubin Xu128180b2017-04-12 18:02:44 +01001825 activateEscrowTokens(auth, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001826 }
1827 }
Andres Morales23974272015-05-14 22:42:26 -07001828 }
Dmitry Dementyev6a509e42017-12-19 14:47:26 -08001829 // Use credentials to create recoverable keystore snapshot.
1830 mRecoverableKeyStoreManager.lockScreenSecretAvailable(storedHash.type, credential,
1831 userId);
1832
Adrian Roos873010d2015-08-25 15:59:00 -07001833 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1834 if (response.getTimeout() > 0) {
1835 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1836 }
Andres Morales23974272015-05-14 22:42:26 -07001837 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001838
Andres Morales23974272015-05-14 22:42:26 -07001839 return response;
1840 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001841
Rubin Xu7cf45092017-08-28 11:47:35 +01001842 /**
1843 * Call this method to notify DPMS regarding the latest password metric. This should be called
1844 * when the user is authenticating or when a new password is being set.
1845 */
Andrew Scull5daf2732016-11-14 15:02:45 +00001846 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
1847 final PasswordMetrics metrics;
1848 if (password == null) {
1849 metrics = new PasswordMetrics();
1850 } else {
1851 metrics = PasswordMetrics.computeForPassword(password);
1852 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
1853 }
1854
1855 // Asynchronous to avoid dead lock
1856 mHandler.post(() -> {
1857 DevicePolicyManager dpm = (DevicePolicyManager)
1858 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1859 dpm.setActivePasswordState(metrics, userId);
1860 });
1861 }
1862
1863 /**
1864 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
1865 * reporting the password changed.
1866 */
1867 private void notifyPasswordChanged(@UserIdInt int userId) {
1868 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
1869 mHandler.post(() -> {
1870 DevicePolicyManager dpm = (DevicePolicyManager)
1871 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1872 dpm.reportPasswordChanged(userId);
1873 });
1874 }
1875
Amith Yamasani52c489c2012-03-28 11:42:42 -07001876 @Override
Adrian Roos261d5ab2014-10-29 14:42:38 +01001877 public boolean checkVoldPassword(int userId) throws RemoteException {
Paul Lawrence945490c2014-03-27 16:37:28 +00001878 if (!mFirstCallToVold) {
1879 return false;
1880 }
1881 mFirstCallToVold = false;
1882
1883 checkPasswordReadPermission(userId);
1884
1885 // There's no guarantee that this will safely connect, but if it fails
1886 // we will simply show the lock screen when we shouldn't, so relatively
1887 // benign. There is an outside chance something nasty would happen if
1888 // this service restarted before vold stales out the password in this
1889 // case. The nastiness is limited to not showing the lock screen when
1890 // we should, within the first minute of decrypting the phone if this
1891 // service can't connect to vold, it restarts, and then the new instance
1892 // does successfully connect.
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001893 final IStorageManager service = mInjector.getStorageManager();
Paul Lawrence0bbd1082016-04-26 15:21:02 -07001894 String password;
1895 long identity = Binder.clearCallingIdentity();
1896 try {
1897 password = service.getPassword();
1898 service.clearPassword();
1899 } finally {
1900 Binder.restoreCallingIdentity(identity);
1901 }
Paul Lawrence945490c2014-03-27 16:37:28 +00001902 if (password == null) {
1903 return false;
1904 }
1905
1906 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001907 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001908 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
1909 null /* progressCallback */)
1910 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001911 return true;
1912 }
1913 }
1914 } catch (Exception e) {
1915 }
1916
1917 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001918 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001919 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
1920 null /* progressCallback */)
1921 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001922 return true;
1923 }
1924 }
1925 } catch (Exception e) {
1926 }
1927
1928 return false;
1929 }
1930
Amith Yamasanif11a5742016-06-16 08:20:07 -07001931 private void removeUser(int userId, boolean unknownUser) {
Rubin Xu7b7424b2017-03-31 18:03:20 +01001932 mSpManager.removeUser(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +01001933 mStorage.removeUser(userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001934 mStrongAuth.removeUser(userId);
Andrew Scullede482d2018-01-30 13:54:29 +00001935 tryRemoveUserFromSpCacheLater(userId);
Robin Lee49d810c2014-09-23 13:50:22 +01001936
1937 final KeyStore ks = KeyStore.getInstance();
Chad Brubaker83ce0952015-05-12 13:00:02 -07001938 ks.onUserRemoved(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001939
1940 try {
1941 final IGateKeeperService gk = getGateKeeperService();
1942 if (gk != null) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001943 gk.clearSecureUserId(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001944 }
1945 } catch (RemoteException ex) {
1946 Slog.w(TAG, "unable to clear GK secure user id");
1947 }
Amith Yamasanif11a5742016-06-16 08:20:07 -07001948 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
Ricky Waidc283a82016-03-24 19:55:08 +00001949 removeKeystoreProfileKey(userId);
1950 }
1951 }
1952
1953 private void removeKeystoreProfileKey(int targetUserId) {
1954 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1955 try {
1956 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1957 keyStore.load(null);
Ricky Waid3982442016-05-24 19:27:08 +01001958 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1959 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
Ricky Waidc283a82016-03-24 19:55:08 +00001960 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1961 | IOException e) {
1962 // We have tried our best to remove all keys
1963 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1964 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001965 }
1966
Adrian Roosb5e47222015-08-14 15:53:06 -07001967 @Override
1968 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1969 checkPasswordReadPermission(UserHandle.USER_ALL);
1970 mStrongAuth.registerStrongAuthTracker(tracker);
1971 }
1972
1973 @Override
1974 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1975 checkPasswordReadPermission(UserHandle.USER_ALL);
1976 mStrongAuth.unregisterStrongAuthTracker(tracker);
1977 }
1978
1979 @Override
1980 public void requireStrongAuth(int strongAuthReason, int userId) {
1981 checkWritePermission(userId);
1982 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1983 }
1984
Adrian Roos4ab7e592016-04-13 15:38:13 -07001985 @Override
1986 public void userPresent(int userId) {
1987 checkWritePermission(userId);
1988 mStrongAuth.reportUnlock(userId);
1989 }
1990
Victor Changa0940d32016-05-16 19:36:08 +01001991 @Override
1992 public int getStrongAuthForUser(int userId) {
1993 checkPasswordReadPermission(userId);
1994 return mStrongAuthTracker.getStrongAuthForUser(userId);
1995 }
1996
Jorim Jaggi2fef6f72016-11-01 19:06:25 -07001997 private boolean isCallerShell() {
1998 final int callingUid = Binder.getCallingUid();
1999 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
2000 }
2001
2002 private void enforceShell() {
2003 if (!isCallerShell()) {
2004 throw new SecurityException("Caller must be shell");
2005 }
2006 }
2007
2008 @Override
2009 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2010 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
2011 throws RemoteException {
2012 enforceShell();
2013 final long origId = Binder.clearCallingIdentity();
2014 try {
2015 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
2016 this, in, out, err, args, callback, resultReceiver);
2017 } finally {
2018 Binder.restoreCallingIdentity(origId);
2019 }
2020 }
2021
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002022 @Override
Bo Zhu7f414d92018-02-28 09:28:19 -08002023 public void initRecoveryServiceWithSigFile(@NonNull String rootCertificateAlias,
2024 @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile)
2025 throws RemoteException {
2026 mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(rootCertificateAlias,
2027 recoveryServiceCertFile, recoveryServiceSigFile);
2028 }
2029
2030 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002031 public @NonNull KeyChainSnapshot getKeyChainSnapshot() throws RemoteException {
Dmitry Dementyevb4fb9872018-01-26 11:49:34 -08002032 return mRecoverableKeyStoreManager.getKeyChainSnapshot();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002033 }
2034
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002035 @Override
Dmitry Dementyev14298312018-01-04 15:19:19 -08002036 public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002037 throws RemoteException {
Dmitry Dementyev14298312018-01-04 15:19:19 -08002038 mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent);
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002039 }
2040
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002041 @Override
Dmitry Dementyev7d8c78a2018-01-12 19:14:07 -08002042 public void setServerParams(byte[] serverParams) throws RemoteException {
2043 mRecoverableKeyStoreManager.setServerParams(serverParams);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002044 }
2045
2046 @Override
Robert Berrybbe02ae2018-02-20 19:47:43 +00002047 public void setRecoveryStatus(String alias, int status) throws RemoteException {
2048 mRecoverableKeyStoreManager.setRecoveryStatus(alias, status);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002049 }
2050
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002051 @Override
2052 public @NonNull Map getRecoveryStatus() throws RemoteException {
Robert Berry56f06b42018-02-23 13:31:32 +00002053 return mRecoverableKeyStoreManager.getRecoveryStatus();
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002054 }
2055
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002056 @Override
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -08002057 public void setRecoverySecretTypes(@NonNull @KeyChainProtectionParams.UserSecretType
Dmitry Dementyev14298312018-01-04 15:19:19 -08002058 int[] secretTypes) throws RemoteException {
2059 mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002060 }
2061
2062 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002063 public @NonNull int[] getRecoverySecretTypes() throws RemoteException {
Dmitry Dementyev14298312018-01-04 15:19:19 -08002064 return mRecoverableKeyStoreManager.getRecoverySecretTypes();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002065
2066 }
2067
2068 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002069 public @NonNull byte[] startRecoverySessionWithCertPath(@NonNull String sessionId,
Bo Zhub31ab672018-03-20 22:44:18 -07002070 @NonNull String rootCertificateAlias, @NonNull RecoveryCertPath verifierCertPath,
2071 @NonNull byte[] vaultParams, @NonNull byte[] vaultChallenge,
2072 @NonNull List<KeyChainProtectionParams> secrets)
Bo Zhu7c1972f2018-02-22 21:43:52 -08002073 throws RemoteException {
2074 return mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
Bo Zhub31ab672018-03-20 22:44:18 -07002075 sessionId, rootCertificateAlias, verifierCertPath, vaultParams, vaultChallenge,
2076 secrets);
Bo Zhu7c1972f2018-02-22 21:43:52 -08002077 }
2078
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002079 @Override
Robert Berry4a5c87d2018-03-19 18:00:46 +00002080 public Map<String, String> recoverKeyChainSnapshot(
2081 @NonNull String sessionId,
2082 @NonNull byte[] recoveryKeyBlob,
2083 @NonNull List<WrappedApplicationKey> applicationKeys) throws RemoteException {
2084 return mRecoverableKeyStoreManager.recoverKeyChainSnapshot(
2085 sessionId, recoveryKeyBlob, applicationKeys);
2086 }
2087
2088 @Override
Dmitry Dementyev745d2c92018-04-13 14:10:05 -07002089 public void closeSession(@NonNull String sessionId) throws RemoteException {
2090 mRecoverableKeyStoreManager.closeSession(sessionId);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002091 }
2092
Robert Berrycfc990a2017-12-22 15:54:30 +00002093 @Override
Robert Berry5daccec2018-01-06 19:16:25 +00002094 public void removeKey(@NonNull String alias) throws RemoteException {
2095 mRecoverableKeyStoreManager.removeKey(alias);
2096 }
2097
2098 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002099 public @Nullable String generateKey(@NonNull String alias) throws RemoteException {
Robert Berrya3b99472018-02-23 15:59:02 +00002100 return mRecoverableKeyStoreManager.generateKey(alias);
Dmitry Dementyev29b9de52018-01-31 16:09:32 -08002101 }
2102
2103 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002104 public @Nullable String importKey(@NonNull String alias, byte[] keyBytes) throws RemoteException {
Bo Zhu2c8e5382018-02-26 15:54:25 -08002105 return mRecoverableKeyStoreManager.importKey(alias, keyBytes);
2106 }
2107
2108 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002109 public @Nullable String getKey(@NonNull String alias) throws RemoteException {
Dmitry Dementyev29b9de52018-01-31 16:09:32 -08002110 return mRecoverableKeyStoreManager.getKey(alias);
2111 }
2112
Amith Yamasani52c489c2012-03-28 11:42:42 -07002113 private static final String[] VALID_SETTINGS = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002114 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
Rubin Xu1de89b32016-11-30 20:03:13 +00002115 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
2116 LockPatternUtils.PASSWORD_TYPE_KEY,
2117 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
2118 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2119 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
2120 LockPatternUtils.LOCKSCREEN_OPTIONS,
2121 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
2122 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
2123 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
2124 LockPatternUtils.PASSWORD_HISTORY_KEY,
2125 Secure.LOCK_PATTERN_ENABLED,
2126 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
2127 Secure.LOCK_PATTERN_VISIBLE,
2128 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
Jim Miller187ec582013-04-15 18:27:54 -07002129 };
2130
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +00002131 // Reading these settings needs the contacts permission
2132 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002133 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
2134 Secure.LOCK_SCREEN_OWNER_INFO
Jim Miller187ec582013-04-15 18:27:54 -07002135 };
Paul Lawrence945490c2014-03-27 16:37:28 +00002136
Adrian Roos001b00d2015-02-24 17:08:48 +01002137 // Reading these settings needs the same permission as checking the password
2138 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
2139 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2140 LockPatternUtils.PASSWORD_HISTORY_KEY,
Adrian Roos855fa302015-04-02 16:01:12 +02002141 LockPatternUtils.PASSWORD_TYPE_KEY,
Ricky Wai7f405f12016-05-31 12:05:05 +01002142 SEPARATE_PROFILE_CHALLENGE_KEY
Adrian Roos001b00d2015-02-24 17:08:48 +01002143 };
2144
Amith Yamasani072543f2015-02-13 11:09:45 -08002145 private static final String[] SETTINGS_TO_BACKUP = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002146 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
Bryan Mawhinneye483b562017-05-15 14:46:05 +01002147 Secure.LOCK_SCREEN_OWNER_INFO,
2148 Secure.LOCK_PATTERN_VISIBLE,
2149 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
Amith Yamasani072543f2015-02-13 11:09:45 -08002150 };
2151
Andres Morales301ea442015-04-17 09:15:47 -07002152 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
2153 @Override
2154 public void binderDied() {
2155 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
2156 mGateKeeperService = null;
2157 }
2158 }
2159
Rubin Xu3bf722a2016-12-15 16:07:38 +00002160 protected synchronized IGateKeeperService getGateKeeperService()
Andres Morales301ea442015-04-17 09:15:47 -07002161 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -07002162 if (mGateKeeperService != null) {
2163 return mGateKeeperService;
2164 }
2165
Rubin Xu1de89b32016-11-30 20:03:13 +00002166 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
Andres Morales8fa56652015-03-31 09:19:50 -07002167 if (service != null) {
Andres Morales301ea442015-04-17 09:15:47 -07002168 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
Andres Morales8fa56652015-03-31 09:19:50 -07002169 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
2170 return mGateKeeperService;
2171 }
2172
2173 Slog.e(TAG, "Unable to acquire GateKeeperService");
2174 return null;
2175 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00002176
2177 /**
Andrew Scull1416bd02018-01-05 18:33:58 +00002178 * A user's synthetic password does not change so it must be cached in certain circumstances to
2179 * enable untrusted credential reset.
2180 *
2181 * Untrusted credential reset will be removed in a future version (b/68036371) at which point
2182 * this cache is no longer needed as the SP will always be known when changing the user's
2183 * credential.
2184 */
2185 @GuardedBy("mSpManager")
2186 private SparseArray<AuthenticationToken> mSpCache = new SparseArray();
2187
2188 private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
Andrew Scullede482d2018-01-30 13:54:29 +00002189 // Preemptively cache the SP and then try to remove it in a handler.
2190 Slog.i(TAG, "Caching SP for user " + userId);
2191 synchronized (mSpManager) {
2192 mSpCache.put(userId, auth);
2193 }
2194 tryRemoveUserFromSpCacheLater(userId);
2195
Andrew Sculle6527c12018-01-05 18:33:58 +00002196 // Pass the primary user's auth secret to the HAL
2197 if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
2198 try {
2199 final byte[] rawSecret = auth.deriveVendorAuthSecret();
2200 final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length);
2201 for (int i = 0; i < rawSecret.length; ++i) {
2202 secret.add(rawSecret[i]);
2203 }
2204 mAuthSecretService.primaryUserCredential(secret);
2205 } catch (RemoteException e) {
2206 Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
2207 }
2208 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002209 }
2210
Andrew Scullede482d2018-01-30 13:54:29 +00002211 private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) {
2212 mHandler.post(() -> {
2213 if (!shouldCacheSpForUser(userId)) {
2214 // The transition from 'should not cache' to 'should cache' can only happen if
2215 // certain admin apps are installed after provisioning e.g. via adb. This is not
2216 // a common case and we do not seamlessly support; it may result in the SP not
2217 // being cached when it is needed. The cache can be re-populated by verifying
2218 // the credential again.
2219 Slog.i(TAG, "Removing SP from cache for user " + userId);
2220 synchronized (mSpManager) {
2221 mSpCache.remove(userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002222 }
2223 }
Andrew Scullede482d2018-01-30 13:54:29 +00002224 });
Andrew Scull1416bd02018-01-05 18:33:58 +00002225 }
2226
Andrew Scullede482d2018-01-30 13:54:29 +00002227 /** Do not hold any of the locks from this service when calling. */
Andrew Scull1416bd02018-01-05 18:33:58 +00002228 private boolean shouldCacheSpForUser(@UserIdInt int userId) {
2229 // Before the user setup has completed, an admin could be installed that requires the SP to
2230 // be cached (see below).
2231 if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
2232 Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 0) {
2233 return true;
2234 }
2235
2236 // If the user has an admin which can perform an untrusted credential reset, the SP needs to
2237 // be cached. If there isn't a DevicePolicyManager then there can't be an admin in the first
2238 // place so caching is not necessary.
2239 final DevicePolicyManagerInternal dpmi = LocalServices.getService(
2240 DevicePolicyManagerInternal.class);
2241 if (dpmi == null) {
2242 return false;
2243 }
2244 return dpmi.canUserHaveUntrustedCredentialReset(userId);
2245 }
2246
2247 /**
Rubin Xu3bf722a2016-12-15 16:07:38 +00002248 * Precondition: vold and keystore unlocked.
2249 *
2250 * Create new synthetic password, set up synthetic password blob protected by the supplied
2251 * user credential, and make the newly-created SP blob active.
2252 *
2253 * The invariant under a synthetic password is:
2254 * 1. If user credential exists, then both vold and keystore and protected with keys derived
2255 * from the synthetic password.
2256 * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
2257 * make it consistent with current behaviour. It also allows ActivityManager to call
2258 * unlockUser() with empty secret.
2259 * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
2260 * whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
2261 * lockscreen PIN, we still maintain the existing synthetic password in a password blob
Andrew Scull1416bd02018-01-05 18:33:58 +00002262 * protected by a default PIN.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002263 * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
2264 * clears/re-creates his lockscreen PIN.
2265 *
2266 *
2267 * Different cases of calling this method:
2268 * 1. credentialHash != null
2269 * This implies credential != null, a new SP blob will be provisioned, and existing SID
2270 * migrated to associate with the new SP.
2271 * This happens during a normal migration case when the user currently has password.
2272 *
2273 * 2. credentialhash == null and credential == null
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002274 * A new SP blob and will be created, while the user has no credentials.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002275 * This can happens when we are activating an escrow token on a unsecured device, during
2276 * which we want to create the SP structure with an empty user credential.
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002277 * This could also happen during an untrusted reset to clear password.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002278 *
2279 * 3. credentialhash == null and credential != null
2280 * This is the untrusted credential reset, OR the user sets a new lockscreen password
2281 * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
2282 */
Andrew Scull1416bd02018-01-05 18:33:58 +00002283 @GuardedBy("mSpManager")
Rubin Xu16c823e2017-06-27 14:44:58 +01002284 @VisibleForTesting
2285 protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002286 String credential, int credentialType, int requestedQuality,
2287 int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002288 Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002289 final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
2290 getGateKeeperService(), credentialHash, credential, userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002291 onAuthTokenKnownForUser(userId, auth);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002292 if (auth == null) {
2293 Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
2294 return null;
2295 }
2296 long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
Adrian Roos7374d3a2017-03-31 14:14:53 -07002297 credential, credentialType, auth, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002298 if (credential != null) {
2299 if (credentialHash == null) {
2300 // Since when initializing SP, we didn't provide an existing password handle
2301 // for it to migrate SID, we need to create a new SID for the user.
2302 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2303 }
2304 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2305 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2306 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2307 } else {
2308 clearUserKeyProtection(userId);
2309 setKeystorePassword(null, userId);
2310 getGateKeeperService().clearSecureUserId(userId);
2311 }
2312 fixateNewestUserKeyAuth(userId);
2313 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
2314 return auth;
2315 }
2316
2317 private long getSyntheticPasswordHandleLocked(int userId) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +02002318 return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY,
2319 SyntheticPasswordManager.DEFAULT_HANDLE, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002320 }
2321
Rubin Xufcd49f92017-08-24 18:21:52 +01002322 private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002323 if (userId == USER_FRP) {
2324 final int type = mStorage.readPersistentDataBlock().type;
2325 return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
2326 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00002327 long handle = getSyntheticPasswordHandleLocked(userId);
2328 // This is a global setting
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00002329 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
2330 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002331 return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
2332 }
2333
Rubin Xu16c823e2017-06-27 14:44:58 +01002334 @VisibleForTesting
Rubin Xufcd49f92017-08-24 18:21:52 +01002335 protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002336 long handle = getSyntheticPasswordHandleLocked(userId);
2337 // This is a global setting
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00002338 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
2339 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002340 return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
2341 }
2342
Rubin Xufcd49f92017-08-24 18:21:52 +01002343 private void enableSyntheticPasswordLocked() {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002344 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
2345 }
2346
Rubin Xue94a7702017-06-20 17:29:57 +01002347 private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
Rubin Xu3bf722a2016-12-15 16:07:38 +00002348 credentialType, boolean hasChallenge, long challenge, int userId,
2349 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xue94a7702017-06-20 17:29:57 +01002350 if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002351 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
2352 userCredential = null;
2353 }
Rubin Xue94a7702017-06-20 17:29:57 +01002354
2355 final AuthenticationResult authResult;
2356 VerifyCredentialResponse response;
2357 synchronized (mSpManager) {
2358 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
2359 return null;
2360 }
2361 if (userId == USER_FRP) {
2362 return mSpManager.verifyFrpCredential(getGateKeeperService(),
2363 userCredential, credentialType, progressCallback);
2364 }
2365
2366 long handle = getSyntheticPasswordHandleLocked(userId);
2367 authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
Rubin Xucf326f12017-11-15 11:55:35 +00002368 getGateKeeperService(), handle, userCredential, userId, progressCallback);
Rubin Xue94a7702017-06-20 17:29:57 +01002369
Rubin Xu16c823e2017-06-27 14:44:58 +01002370 if (authResult.credentialType != credentialType) {
2371 Slog.e(TAG, "Credential type mismatch.");
2372 return VerifyCredentialResponse.ERROR;
2373 }
Rubin Xue94a7702017-06-20 17:29:57 +01002374 response = authResult.gkResponse;
2375 // credential has matched
2376 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2377 // perform verifyChallenge with synthetic password which generates the real GK auth
2378 // token and response for the current user
2379 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
2380 challenge, userId);
2381 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2382 // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
2383 // match the recorded GK password handle.
2384 Slog.wtf(TAG, "verifyChallenge with SP failed.");
2385 return VerifyCredentialResponse.ERROR;
2386 }
2387 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07002388 }
2389
Rubin Xu3bf722a2016-12-15 16:07:38 +00002390 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002391 notifyActivePasswordMetricsAvailable(userCredential, userId);
2392 unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
2393
2394 final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
2395 Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
2396 unlockUser(userId, null, secret);
2397
Rubin Xue94a7702017-06-20 17:29:57 +01002398 activateEscrowTokens(authResult.authToken, userId);
2399
Rubin Xu3bf722a2016-12-15 16:07:38 +00002400 if (isManagedProfileWithSeparatedLock(userId)) {
2401 TrustManager trustManager =
2402 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
2403 trustManager.setDeviceLockedForUser(userId, false);
2404 }
Rubin Xue94a7702017-06-20 17:29:57 +01002405 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002406
2407 onAuthTokenKnownForUser(userId, authResult.authToken);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002408 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
2409 if (response.getTimeout() > 0) {
2410 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
2411 }
2412 }
2413
2414 return response;
2415 }
2416
2417 /**
2418 * Change the user's lockscreen password by creating a new SP blob and update the handle, based
2419 * on an existing authentication token. Even though a new SP blob is created, the underlying
2420 * synthetic password is never changed.
2421 *
2422 * When clearing credential, we keep the SP unchanged, but clear its password handle so its
2423 * SID is gone. We also clear password from (software-based) keystore and vold, which will be
2424 * added back when new password is set in future.
2425 */
Andrew Scull1416bd02018-01-05 18:33:58 +00002426 @GuardedBy("mSpManager")
Rubin Xu3bf722a2016-12-15 16:07:38 +00002427 private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002428 AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002429 if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
2430 long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
Adrian Roos7374d3a2017-03-31 14:14:53 -07002431 credential, credentialType, auth, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002432 final Map<Integer, String> profilePasswords;
2433 if (credential != null) {
2434 // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
2435 profilePasswords = null;
2436
2437 if (mSpManager.hasSidForUser(userId)) {
2438 // We are changing password of a secured device, nothing more needed as
2439 // createPasswordBasedSyntheticPassword has already taken care of maintaining
2440 // the password handle and SID unchanged.
2441
2442 //refresh auth token
2443 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2444 } else {
2445 // A new password is set on a previously-unsecured device, we need to generate
2446 // a new SID, and re-add keys to vold and keystore.
2447 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2448 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2449 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2450 fixateNewestUserKeyAuth(userId);
2451 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2452 }
2453 } else {
2454 // Cache all profile password if they use unified work challenge. This will later be
2455 // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
2456 profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
2457
2458 // we are clearing password of a secured device, so need to nuke SID as well.
2459 mSpManager.clearSidForUser(userId);
2460 getGateKeeperService().clearSecureUserId(userId);
2461 // Clear key from vold so ActivityManager can just unlock the user with empty secret
2462 // during boot.
2463 clearUserKeyProtection(userId);
2464 fixateNewestUserKeyAuth(userId);
2465 setKeystorePassword(null, userId);
2466 }
2467 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
2468 synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
Rubin Xu7cf45092017-08-28 11:47:35 +01002469
2470 notifyActivePasswordMetricsAvailable(credential, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002471 return newHandle;
2472 }
2473
Andrew Scull1416bd02018-01-05 18:33:58 +00002474 @GuardedBy("mSpManager")
Rubin Xu3bf722a2016-12-15 16:07:38 +00002475 private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002476 String savedCredential, int requestedQuality, int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002477 if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2478 if (isManagedProfileWithUnifiedLock(userId)) {
2479 // get credential from keystore when managed profile has unified lock
2480 try {
2481 savedCredential = getDecryptedPasswordForTiedProfile(userId);
2482 } catch (FileNotFoundException e) {
2483 Slog.i(TAG, "Child profile key not found");
2484 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2485 | NoSuchAlgorithmException | NoSuchPaddingException
2486 | InvalidAlgorithmParameterException | IllegalBlockSizeException
2487 | BadPaddingException | CertificateException | IOException e) {
2488 Slog.e(TAG, "Failed to decrypt child profile key", e);
2489 }
2490 }
2491 long handle = getSyntheticPasswordHandleLocked(userId);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002492 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
Rubin Xucf326f12017-11-15 11:55:35 +00002493 getGateKeeperService(), handle, savedCredential, userId, null);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002494 VerifyCredentialResponse response = authResult.gkResponse;
2495 AuthenticationToken auth = authResult.authToken;
Rubin Xu16c823e2017-06-27 14:44:58 +01002496
2497 // If existing credential is provided, then it must match.
2498 if (savedCredential != null && auth == null) {
2499 throw new RemoteException("Failed to enroll " +
2500 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
2501 : "pattern"));
2502 }
2503
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002504 boolean untrustedReset = false;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002505 if (auth != null) {
Andrew Scull1416bd02018-01-05 18:33:58 +00002506 onAuthTokenKnownForUser(userId, auth);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002507 } else if (response != null
Andrew Scull1416bd02018-01-05 18:33:58 +00002508 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002509 // We are performing an untrusted credential change, by DevicePolicyManager or other
2510 // internal callers that don't provide the existing credential
Rubin Xu3bf722a2016-12-15 16:07:38 +00002511 Slog.w(TAG, "Untrusted credential change invoked");
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002512 // Try to get a cached auth token, so we can keep SP unchanged.
2513 auth = mSpCache.get(userId);
2514 untrustedReset = true;
Rubin Xu8b30ec32017-03-05 00:47:09 +00002515 } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
2516 Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
2517 (response != null ? "rate limit exceeded" : "failed"));
2518 return;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002519 }
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002520
2521 if (auth != null) {
2522 if (untrustedReset) {
2523 // Force change the current SID to mantain existing behaviour that an untrusted
2524 // reset leads to a change of SID. If the untrusted reset is for clearing the
2525 // current password, the nuking of the SID will be done in
2526 // setLockCredentialWithAuthTokenLocked next
2527 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2528 }
2529 setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
2530 userId);
2531 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2532 } else {
2533 throw new IllegalStateException(
2534 "Untrusted credential reset not possible without cached SP");
2535 // Could call initializeSyntheticPasswordLocked(null, credential, credentialType,
2536 // requestedQuality, userId) instead if we still allow untrusted reset that changes
2537 // synthetic password. That would invalidate existing escrow tokens though.
2538 }
Dmitry Dementyev6e167242018-01-25 15:29:50 -08002539 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002540 }
2541
Rubin Xuf01e9072018-03-30 20:59:28 +01002542 /**
2543 * Returns a fixed pseudorandom byte string derived from the user's synthetic password.
2544 * This is used to salt the password history hash to protect the hash against offline
2545 * bruteforcing, since rederiving this value requires a successful authentication.
Rubin Xu4ed98982018-05-23 14:27:53 +01002546 * If user is a managed profile with unified challenge, currentCredential is ignored.
Rubin Xuf01e9072018-03-30 20:59:28 +01002547 */
2548 @Override
2549 public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
2550 checkPasswordReadPermission(userId);
2551 if (TextUtils.isEmpty(currentCredential)) {
2552 currentCredential = null;
2553 }
Rubin Xu4ed98982018-05-23 14:27:53 +01002554 if (isManagedProfileWithUnifiedLock(userId)) {
2555 try {
2556 currentCredential = getDecryptedPasswordForTiedProfile(userId);
2557 } catch (Exception e) {
2558 Slog.e(TAG, "Failed to get work profile credential", e);
2559 return null;
2560 }
2561 }
Rubin Xuf01e9072018-03-30 20:59:28 +01002562 synchronized (mSpManager) {
2563 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
2564 Slog.w(TAG, "Synthetic password not enabled");
2565 return null;
2566 }
2567 long handle = getSyntheticPasswordHandleLocked(userId);
2568 AuthenticationResult auth = mSpManager.unwrapPasswordBasedSyntheticPassword(
2569 getGateKeeperService(), handle, currentCredential, userId, null);
2570 if (auth.authToken == null) {
2571 Slog.w(TAG, "Current credential is incorrect");
2572 return null;
2573 }
2574 return auth.authToken.derivePasswordHashFactor();
2575 }
2576 }
2577
Rubin Xufcd49f92017-08-24 18:21:52 +01002578 private long addEscrowToken(byte[] token, int userId) throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002579 if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
2580 synchronized (mSpManager) {
2581 enableSyntheticPasswordLocked();
Rubin Xu8b30ec32017-03-05 00:47:09 +00002582 // Migrate to synthetic password based credentials if the user has no password,
Rubin Xuf095f832017-01-31 15:23:34 +00002583 // the token can then be activated immediately.
2584 AuthenticationToken auth = null;
2585 if (!isUserSecure(userId)) {
2586 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2587 auth = initializeSyntheticPasswordLocked(null, null,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002588 LockPatternUtils.CREDENTIAL_TYPE_NONE,
2589 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002590 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
2591 long pwdHandle = getSyntheticPasswordHandleLocked(userId);
2592 auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
Rubin Xucf326f12017-11-15 11:55:35 +00002593 pwdHandle, null, userId, null).authToken;
Rubin Xuf095f832017-01-31 15:23:34 +00002594 }
2595 }
Rubin Xu128180b2017-04-12 18:02:44 +01002596 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2597 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2598 if (!mSpManager.hasEscrowData(userId)) {
2599 throw new SecurityException("Escrow token is disabled on the current user");
2600 }
Rubin Xuf095f832017-01-31 15:23:34 +00002601 }
2602 long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
2603 if (auth != null) {
2604 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2605 }
2606 return handle;
2607 }
2608 }
2609
Rubin Xufcd49f92017-08-24 18:21:52 +01002610 private void activateEscrowTokens(AuthenticationToken auth, int userId) {
Rubin Xuf095f832017-01-31 15:23:34 +00002611 if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
2612 synchronized (mSpManager) {
Rubin Xue94a7702017-06-20 17:29:57 +01002613 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002614 for (long handle : mSpManager.getPendingTokensForUser(userId)) {
2615 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
2616 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2617 }
2618 }
2619 }
2620
Rubin Xufcd49f92017-08-24 18:21:52 +01002621 private boolean isEscrowTokenActive(long handle, int userId) {
Rubin Xuf095f832017-01-31 15:23:34 +00002622 synchronized (mSpManager) {
2623 return mSpManager.existsHandle(handle, userId);
2624 }
2625 }
2626
Rubin Xufcd49f92017-08-24 18:21:52 +01002627 private boolean removeEscrowToken(long handle, int userId) {
Rubin Xuf095f832017-01-31 15:23:34 +00002628 synchronized (mSpManager) {
2629 if (handle == getSyntheticPasswordHandleLocked(userId)) {
2630 Slog.w(TAG, "Cannot remove password handle");
2631 return false;
2632 }
2633 if (mSpManager.removePendingToken(handle, userId)) {
2634 return true;
2635 }
2636 if (mSpManager.existsHandle(handle, userId)) {
2637 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
2638 return true;
2639 } else {
2640 return false;
2641 }
2642 }
2643 }
2644
Rubin Xufcd49f92017-08-24 18:21:52 +01002645 private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002646 byte[] token, int requestedQuality, int userId) throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002647 boolean result;
2648 synchronized (mSpManager) {
2649 if (!mSpManager.hasEscrowData(userId)) {
2650 throw new SecurityException("Escrow token is disabled on the current user");
2651 }
2652 result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002653 requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002654 }
2655 if (result) {
2656 synchronized (mSeparateChallengeLock) {
Pavel Grafov28939982017-10-03 15:11:52 +01002657 setSeparateProfileChallengeEnabledLocked(userId, true, null);
Rubin Xuf095f832017-01-31 15:23:34 +00002658 }
2659 notifyPasswordChanged(userId);
Pavel Grafov28939982017-10-03 15:11:52 +01002660 notifySeparateProfileChallengeChanged(userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002661 }
2662 return result;
2663 }
2664
2665 private boolean setLockCredentialWithTokenInternal(String credential, int type,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002666 long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
Andrew Scull1416bd02018-01-05 18:33:58 +00002667 final AuthenticationResult result;
Rubin Xuf095f832017-01-31 15:23:34 +00002668 synchronized (mSpManager) {
Andrew Scull1416bd02018-01-05 18:33:58 +00002669 result = mSpManager.unwrapTokenBasedSyntheticPassword(
Rubin Xuf095f832017-01-31 15:23:34 +00002670 getGateKeeperService(), tokenHandle, token, userId);
2671 if (result.authToken == null) {
2672 Slog.w(TAG, "Invalid escrow token supplied");
2673 return false;
2674 }
Rubin Xu24570e42017-09-19 15:27:21 +01002675 if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2676 // Most likely, an untrusted credential reset happened in the past which
2677 // changed the synthetic password
2678 Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
2679 + "verification.");
2680 return false;
2681 }
Rubin Xu7cf45092017-08-28 11:47:35 +01002682 // Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable()
2683 // called by setLockCredentialWithAuthTokenLocked().
2684 // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
2685 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002686 long oldHandle = getSyntheticPasswordHandleLocked(userId);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002687 setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
2688 requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002689 mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002690 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002691 onAuthTokenKnownForUser(userId, result.authToken);
2692 return true;
Rubin Xuf095f832017-01-31 15:23:34 +00002693 }
2694
Rubin Xufcd49f92017-08-24 18:21:52 +01002695 private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
Rubin Xuf095f832017-01-31 15:23:34 +00002696 throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002697 AuthenticationResult authResult;
2698 synchronized (mSpManager) {
2699 if (!mSpManager.hasEscrowData(userId)) {
2700 throw new SecurityException("Escrow token is disabled on the current user");
2701 }
2702 authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
2703 tokenHandle, token, userId);
2704 if (authResult.authToken == null) {
2705 Slog.w(TAG, "Invalid escrow token supplied");
Rubin Xufcd49f92017-08-24 18:21:52 +01002706 return false;
Rubin Xuf095f832017-01-31 15:23:34 +00002707 }
2708 }
2709 unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
Andrew Scull1416bd02018-01-05 18:33:58 +00002710 onAuthTokenKnownForUser(userId, authResult.authToken);
Rubin Xufcd49f92017-08-24 18:21:52 +01002711 return true;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002712 }
2713
2714 @Override
2715 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06002716 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002717
Rubin Xua0a0d352017-05-15 16:18:01 +00002718 pw.println("Current lock settings service state:");
2719 pw.println(String.format("SP Enabled = %b",
2720 mLockPatternUtils.isSyntheticPasswordEnabled()));
Rubin Xu3bf722a2016-12-15 16:07:38 +00002721
Rubin Xua0a0d352017-05-15 16:18:01 +00002722 List<UserInfo> users = mUserManager.getUsers();
2723 for (int user = 0; user < users.size(); user++) {
2724 final int userId = users.get(user).id;
2725 pw.println(" User " + userId);
2726 synchronized (mSpManager) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002727 pw.println(String.format(" SP Handle = %x",
2728 getSyntheticPasswordHandleLocked(userId)));
Rubin Xua0a0d352017-05-15 16:18:01 +00002729 }
2730 try {
2731 pw.println(String.format(" SID = %x",
2732 getGateKeeperService().getSecureUserId(userId)));
2733 } catch (RemoteException e) {
2734 // ignore.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002735 }
2736 }
2737 }
2738
Rubin Xuf095f832017-01-31 15:23:34 +00002739 private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
2740 long ident = Binder.clearCallingIdentity();
2741 try {
2742 // Managed profile should have escrow enabled
2743 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002744 Slog.i(TAG, "Managed profile can have escrow token");
Rubin Xuf095f832017-01-31 15:23:34 +00002745 return;
2746 }
Rubin Xuf34d2f62017-03-20 12:36:35 +00002747 DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
Rubin Xuf095f832017-01-31 15:23:34 +00002748 // Devices with Device Owner should have escrow enabled on all users.
Rubin Xuf34d2f62017-03-20 12:36:35 +00002749 if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002750 Slog.i(TAG, "Corp-owned device can have escrow token");
2751 return;
2752 }
2753 // We could also have a profile owner on the given (non-managed) user for unicorn cases
Rubin Xuf34d2f62017-03-20 12:36:35 +00002754 if (dpm.getProfileOwnerAsUser(userId) != null) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002755 Slog.i(TAG, "User with profile owner can have escrow token");
Rubin Xuf095f832017-01-31 15:23:34 +00002756 return;
2757 }
2758 // If the device is yet to be provisioned (still in SUW), there is still
2759 // a chance that Device Owner will be set on the device later, so postpone
2760 // disabling escrow token for now.
Rubin Xuf34d2f62017-03-20 12:36:35 +00002761 if (!dpm.isDeviceProvisioned()) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002762 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
Rubin Xuf095f832017-01-31 15:23:34 +00002763 return;
2764 }
Rakesh Iyercb18d562017-03-06 18:05:53 -08002765
2766 // Escrow tokens are enabled on automotive builds.
2767 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
2768 return;
2769 }
2770
Rubin Xuf095f832017-01-31 15:23:34 +00002771 // Disable escrow token permanently on all other device/user types.
2772 Slog.i(TAG, "Disabling escrow token on user " + userId);
2773 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2774 mSpManager.destroyEscrowData(userId);
2775 }
Rubin Xuf095f832017-01-31 15:23:34 +00002776 } finally {
2777 Binder.restoreCallingIdentity(ident);
2778 }
2779 }
2780
Adrian Roos7374d3a2017-03-31 14:14:53 -07002781 private class DeviceProvisionedObserver extends ContentObserver {
2782 private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
2783 Settings.Global.DEVICE_PROVISIONED);
Andrew Scull1416bd02018-01-05 18:33:58 +00002784 private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor(
2785 Settings.Secure.USER_SETUP_COMPLETE);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002786
2787 private boolean mRegistered;
2788
2789 public DeviceProvisionedObserver() {
2790 super(null);
2791 }
2792
2793 @Override
Andrew Scullede482d2018-01-30 13:54:29 +00002794 public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002795 if (mDeviceProvisionedUri.equals(uri)) {
2796 updateRegistration();
2797
2798 if (isProvisioned()) {
2799 Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
2800 reportDeviceSetupComplete();
Adrian Roos454f53f2017-08-08 14:56:42 +02002801 clearFrpCredentialIfOwnerNotSecure();
Adrian Roos7374d3a2017-03-31 14:14:53 -07002802 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002803 } else if (mUserSetupCompleteUri.equals(uri)) {
Andrew Scullede482d2018-01-30 13:54:29 +00002804 tryRemoveUserFromSpCacheLater(userId);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002805 }
2806 }
2807
2808 public void onSystemReady() {
Adrian Roos2adc2632017-09-05 17:01:42 +02002809 if (frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002810 updateRegistration();
2811 } else {
2812 // If we don't intend to use frpCredentials and we're not provisioned yet, send
2813 // deviceSetupComplete immediately, so gatekeeper can discard any lingering
2814 // credentials immediately.
2815 if (!isProvisioned()) {
2816 Slog.i(TAG, "FRP credential disabled, reporting device setup complete "
2817 + "to Gatekeeper immediately");
2818 reportDeviceSetupComplete();
2819 }
2820 }
2821 }
2822
2823 private void reportDeviceSetupComplete() {
2824 try {
2825 getGateKeeperService().reportDeviceSetupComplete();
2826 } catch (RemoteException e) {
2827 Slog.e(TAG, "Failure reporting to IGateKeeperService", e);
2828 }
2829 }
2830
Adrian Roos454f53f2017-08-08 14:56:42 +02002831 /**
2832 * Clears the FRP credential if the user that controls it does not have a secure
2833 * lockscreen.
2834 */
2835 private void clearFrpCredentialIfOwnerNotSecure() {
2836 List<UserInfo> users = mUserManager.getUsers();
2837 for (UserInfo user : users) {
Adrian Roos2adc2632017-09-05 17:01:42 +02002838 if (userOwnsFrpCredential(mContext, user)) {
Adrian Roos454f53f2017-08-08 14:56:42 +02002839 if (!isUserSecure(user.id)) {
2840 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
2841 0, null);
2842 }
2843 return;
2844 }
2845 }
2846 }
2847
Adrian Roos7374d3a2017-03-31 14:14:53 -07002848 private void updateRegistration() {
2849 boolean register = !isProvisioned();
2850 if (register == mRegistered) {
2851 return;
2852 }
2853 if (register) {
2854 mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri,
2855 false, this);
Andrew Scull1416bd02018-01-05 18:33:58 +00002856 mContext.getContentResolver().registerContentObserver(mUserSetupCompleteUri,
2857 false, this, UserHandle.USER_ALL);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002858 } else {
2859 mContext.getContentResolver().unregisterContentObserver(this);
2860 }
2861 mRegistered = register;
2862 }
2863
2864 private boolean isProvisioned() {
2865 return Settings.Global.getInt(mContext.getContentResolver(),
2866 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
2867 }
2868 }
Rubin Xufcd49f92017-08-24 18:21:52 +01002869
2870 private final class LocalService extends LockSettingsInternal {
2871
2872 @Override
2873 public long addEscrowToken(byte[] token, int userId) {
2874 try {
2875 return LockSettingsService.this.addEscrowToken(token, userId);
2876 } catch (RemoteException re) {
2877 throw re.rethrowFromSystemServer();
2878 }
2879 }
2880
2881 @Override
2882 public boolean removeEscrowToken(long handle, int userId) {
2883 return LockSettingsService.this.removeEscrowToken(handle, userId);
2884 }
2885
2886 @Override
2887 public boolean isEscrowTokenActive(long handle, int userId) {
2888 return LockSettingsService.this.isEscrowTokenActive(handle, userId);
2889 }
2890
2891 @Override
2892 public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
2893 byte[] token, int requestedQuality, int userId) {
2894 try {
2895 return LockSettingsService.this.setLockCredentialWithToken(credential, type,
2896 tokenHandle, token, requestedQuality, userId);
2897 } catch (RemoteException re) {
2898 throw re.rethrowFromSystemServer();
2899 }
2900 }
2901
2902 @Override
2903 public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
2904 try {
2905 return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
2906 } catch (RemoteException re) {
2907 throw re.rethrowFromSystemServer();
2908 }
2909 }
2910 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07002911}