blob: 36b04fcd6108217190e9f924b110118ab96164bf [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) {
958 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
959 if (enabled) {
960 mStorage.removeChildProfileLock(userId);
961 removeKeystoreProfileKey(userId);
962 } else {
963 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
964 }
965 }
966
967 private void notifySeparateProfileChallengeChanged(int userId) {
Andrew Scull7f4ff4c2018-01-05 18:33:58 +0000968 final DevicePolicyManagerInternal dpmi = LocalServices.getService(
969 DevicePolicyManagerInternal.class);
970 if (dpmi != null) {
971 dpmi.reportSeparateProfileChallengeChanged(userId);
972 }
Ricky Waidc283a82016-03-24 19:55:08 +0000973 }
974
975 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000976 public void setBoolean(String key, boolean value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700977 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100978 setStringUnchecked(key, userId, value ? "1" : "0");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700979 }
980
981 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000982 public void setLong(String key, long value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700983 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100984 setStringUnchecked(key, userId, Long.toString(value));
Amith Yamasani52c489c2012-03-28 11:42:42 -0700985 }
986
987 @Override
Rubin Xufe354472017-11-21 12:05:06 +0000988 public void setString(String key, String value, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700989 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100990 setStringUnchecked(key, userId, value);
991 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700992
Adrian Roos261d5ab2014-10-29 14:42:38 +0100993 private void setStringUnchecked(String key, int userId, String value) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700994 Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
995
Adrian Roos261d5ab2014-10-29 14:42:38 +0100996 mStorage.writeKeyValue(key, value, userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800997 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
998 BackupManager.dataChanged("com.android.providers.settings");
999 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001000 }
1001
1002 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +02001003 public boolean getBoolean(String key, boolean defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -07001004 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001005 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001006 return TextUtils.isEmpty(value) ?
1007 defaultValue : (value.equals("1") || value.equals("true"));
1008 }
1009
1010 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +02001011 public long getLong(String key, long defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -07001012 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001013 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001014 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
1015 }
1016
1017 @Override
Adrian Roos60dcbbf2017-08-08 16:19:33 +02001018 public String getString(String key, String defaultValue, int userId) {
Jim Miller158fe192013-04-17 15:23:55 -07001019 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001020 return getStringUnchecked(key, defaultValue, userId);
1021 }
1022
1023 public String getStringUnchecked(String key, String defaultValue, int userId) {
1024 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
Adrian Roos7811d9f2015-07-27 15:10:13 -07001025 long ident = Binder.clearCallingIdentity();
1026 try {
1027 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
1028 } finally {
1029 Binder.restoreCallingIdentity(ident);
1030 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001031 }
1032
Adrian Roos7374d3a2017-03-31 14:14:53 -07001033 if (userId == USER_FRP) {
1034 return getFrpStringUnchecked(key);
1035 }
1036
Bryce Lee46145962015-12-14 14:39:10 -08001037 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
1038 key = Settings.Secure.LOCK_PATTERN_ENABLED;
1039 }
1040
Adrian Roos261d5ab2014-10-29 14:42:38 +01001041 return mStorage.readKeyValue(key, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001042 }
1043
Adrian Roos7374d3a2017-03-31 14:14:53 -07001044 private String getFrpStringUnchecked(String key) {
1045 if (LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
1046 return String.valueOf(readFrpPasswordQuality());
1047 }
1048 return null;
1049 }
1050
1051 private int readFrpPasswordQuality() {
1052 return mStorage.readPersistentDataBlock().qualityForUi;
1053 }
1054
Adrian Roos4f788452014-05-22 20:45:59 +02001055 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -07001056 public boolean havePassword(int userId) throws RemoteException {
Adrian Roosb953e182017-08-17 17:58:26 +02001057 checkPasswordHavePermission(userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001058 synchronized (mSpManager) {
1059 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1060 long handle = getSyntheticPasswordHandleLocked(userId);
1061 return mSpManager.getCredentialType(handle, userId) ==
1062 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
1063 }
1064 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001065 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +01001066 return mStorage.hasPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001067 }
1068
1069 @Override
1070 public boolean havePattern(int userId) throws RemoteException {
Adrian Roosb953e182017-08-17 17:58:26 +02001071 checkPasswordHavePermission(userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001072 synchronized (mSpManager) {
1073 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1074 long handle = getSyntheticPasswordHandleLocked(userId);
1075 return mSpManager.getCredentialType(handle, userId) ==
1076 LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
1077 }
1078 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001079 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +01001080 return mStorage.hasPattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001081 }
1082
Rubin Xua55b1682017-01-31 10:06:56 +00001083 private boolean isUserSecure(int userId) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00001084 synchronized (mSpManager) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001085 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1086 long handle = getSyntheticPasswordHandleLocked(userId);
1087 return mSpManager.getCredentialType(handle, userId) !=
1088 LockPatternUtils.CREDENTIAL_TYPE_NONE;
Rubin Xu3bf722a2016-12-15 16:07:38 +00001089 }
1090 }
Rubin Xua55b1682017-01-31 10:06:56 +00001091 return mStorage.hasCredential(userId);
1092 }
1093
Chad Brubakera91a8502015-05-07 10:02:22 -07001094 private void setKeystorePassword(String password, int userHandle) {
Robin Leef0246a82014-08-13 09:50:25 +01001095 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +00001096 ks.onUserPasswordChanged(userHandle, password);
Chad Brubakera91a8502015-05-07 10:02:22 -07001097 }
1098
1099 private void unlockKeystore(String password, int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +00001100 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
Chad Brubakera91a8502015-05-07 10:02:22 -07001101 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +00001102 ks.unlock(userHandle, password);
1103 }
Chad Brubakera91a8502015-05-07 10:02:22 -07001104
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001105 @VisibleForTesting
1106 protected String getDecryptedPasswordForTiedProfile(int userId)
Ricky Waidc283a82016-03-24 19:55:08 +00001107 throws KeyStoreException, UnrecoverableKeyException,
1108 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
1109 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
1110 CertificateException, IOException {
Ricky Wai4613fe42016-05-24 11:11:42 +01001111 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
Ricky Waidc283a82016-03-24 19:55:08 +00001112 byte[] storedData = mStorage.readChildProfileLock(userId);
1113 if (storedData == null) {
1114 throw new FileNotFoundException("Child profile lock file not found");
1115 }
1116 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
1117 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
1118 storedData.length);
1119 byte[] decryptionResult;
1120 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1121 keyStore.load(null);
1122 SecretKey decryptionKey = (SecretKey) keyStore.getKey(
Ricky Waid3982442016-05-24 19:27:08 +01001123 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
Ricky Waidc283a82016-03-24 19:55:08 +00001124
1125 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
1126 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
1127
1128 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
1129 decryptionResult = cipher.doFinal(encryptedPassword);
1130 return new String(decryptionResult, StandardCharsets.UTF_8);
1131 }
1132
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001133 private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
1134 throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001135 try {
Rubin Xu1de89b32016-11-30 20:03:13 +00001136 doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
1137 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1138 false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
Ricky Waidc283a82016-03-24 19:55:08 +00001139 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1140 | NoSuchAlgorithmException | NoSuchPaddingException
1141 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1142 | BadPaddingException | CertificateException | IOException e) {
1143 if (e instanceof FileNotFoundException) {
1144 Slog.i(TAG, "Child profile key not found");
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001145 } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
1146 Slog.i(TAG, "Parent keystore seems locked, ignoring");
Clara Bayarri0a587d22016-02-23 14:49:41 -08001147 } else {
Ricky Waidc283a82016-03-24 19:55:08 +00001148 Slog.e(TAG, "Failed to decrypt child profile key", e);
Clara Bayarri0a587d22016-02-23 14:49:41 -08001149 }
Jim Millerde1af082013-09-11 14:58:26 -07001150 }
1151 }
1152
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001153 private void unlockUser(int userId, byte[] token, byte[] secret) {
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001154 // TODO: make this method fully async so we can update UI with progress strings
1155 final CountDownLatch latch = new CountDownLatch(1);
1156 final IProgressListener listener = new IProgressListener.Stub() {
1157 @Override
1158 public void onStarted(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001159 Log.d(TAG, "unlockUser started");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001160 }
1161
1162 @Override
1163 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001164 Log.d(TAG, "unlockUser progress " + progress);
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001165 }
1166
1167 @Override
1168 public void onFinished(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -06001169 Log.d(TAG, "unlockUser finished");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001170 latch.countDown();
1171 }
1172 };
1173
Jeff Sharkey8924e872015-11-30 12:52:10 -07001174 try {
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001175 mActivityManager.unlockUser(userId, token, secret, listener);
Jeff Sharkey8924e872015-11-30 12:52:10 -07001176 } catch (RemoteException e) {
1177 throw e.rethrowAsRuntimeException();
1178 }
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -06001179
1180 try {
1181 latch.await(15, TimeUnit.SECONDS);
1182 } catch (InterruptedException e) {
1183 Thread.currentThread().interrupt();
1184 }
Ricky Waidc283a82016-03-24 19:55:08 +00001185 try {
1186 if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
1187 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1188 for (UserInfo pi : profiles) {
1189 // Unlock managed profile with unified lock
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001190 if (tiedManagedProfileReadyToUnlock(pi)) {
1191 unlockChildProfile(pi.id, false /* ignoreUserNotAuthenticated */);
Ricky Waidc283a82016-03-24 19:55:08 +00001192 }
1193 }
1194 }
1195 } catch (RemoteException e) {
1196 Log.d(TAG, "Failed to unlock child profile", e);
1197 }
Jeff Sharkey8924e872015-11-30 12:52:10 -07001198 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001199
Pavel Grafov0acc4bf2017-08-23 12:20:54 +01001200 private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
1201 return userInfo.isManagedProfile()
1202 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id)
1203 && mStorage.hasChildProfileLock(userInfo.id)
1204 && mUserManager.isUserRunning(userInfo.id);
1205 }
1206
Rubin Xua55b1682017-01-31 10:06:56 +00001207 private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
1208 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1209 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001210 }
Rubin Xua55b1682017-01-31 10:06:56 +00001211 Map<Integer, String> result = new ArrayMap<Integer, String>();
1212 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1213 final int size = profiles.size();
1214 for (int i = 0; i < size; i++) {
1215 final UserInfo profile = profiles.get(i);
1216 if (!profile.isManagedProfile()) {
1217 continue;
1218 }
1219 final int managedUserId = profile.id;
1220 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1221 continue;
1222 }
1223 try {
Rubin Xu4f988c92017-09-12 16:25:26 +01001224 result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId));
Rubin Xua55b1682017-01-31 10:06:56 +00001225 } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
1226 | NoSuchPaddingException | InvalidKeyException
1227 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1228 | BadPaddingException | CertificateException | IOException e) {
Rubin Xu4f988c92017-09-12 16:25:26 +01001229 Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " +
1230 managedUserId, e);
Rubin Xua55b1682017-01-31 10:06:56 +00001231 }
1232 }
1233 return result;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001234 }
1235
Rubin Xua55b1682017-01-31 10:06:56 +00001236 /**
1237 * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1238 * depending on the parent user's secure state.
1239 *
1240 * When clearing tied work challenges, a pre-computed password table for profiles are required,
1241 * since changing password for profiles requires existing password, and existing passwords can
1242 * only be computed before the parent user's password is cleared.
1243 *
1244 * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1245 * method again on profiles. However the recursion is guaranteed to terminate as this method
1246 * terminates when the user is a managed profile.
1247 */
1248 private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1249 Map<Integer, String> profilePasswordMap) throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001250 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1251 return;
1252 }
Rubin Xua55b1682017-01-31 10:06:56 +00001253 final boolean isSecure = isUserSecure(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001254 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1255 final int size = profiles.size();
1256 for (int i = 0; i < size; i++) {
1257 final UserInfo profile = profiles.get(i);
1258 if (profile.isManagedProfile()) {
1259 final int managedUserId = profile.id;
1260 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1261 continue;
1262 }
1263 if (isSecure) {
1264 tieManagedProfileLockIfNecessary(managedUserId, null);
1265 } else {
Rubin Xua55b1682017-01-31 10:06:56 +00001266 // We use cached work profile password computed before clearing the parent's
1267 // credential, otherwise they get lost
1268 if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
1269 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001270 profilePasswordMap.get(managedUserId),
1271 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
Rubin Xua55b1682017-01-31 10:06:56 +00001272 } else {
1273 Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
1274 // Supplying null here would lead to untrusted credential change
1275 setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001276 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
Rubin Xua55b1682017-01-31 10:06:56 +00001277 }
Ricky Waidc283a82016-03-24 19:55:08 +00001278 mStorage.removeChildProfileLock(managedUserId);
1279 removeKeystoreProfileKey(managedUserId);
1280 }
1281 }
1282 }
1283 }
Andres Morales8fa56652015-03-31 09:19:50 -07001284
Ricky Waidc283a82016-03-24 19:55:08 +00001285 private boolean isManagedProfileWithUnifiedLock(int userId) {
1286 return mUserManager.getUserInfo(userId).isManagedProfile()
1287 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1288 }
1289
1290 private boolean isManagedProfileWithSeparatedLock(int userId) {
1291 return mUserManager.getUserInfo(userId).isManagedProfile()
1292 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1293 }
1294
1295 // This method should be called by LockPatternUtil only, all internal methods in this class
Rubin Xu1de89b32016-11-30 20:03:13 +00001296 // should call setLockCredentialInternal.
Amith Yamasani52c489c2012-03-28 11:42:42 -07001297 @Override
Adrian Roos7374d3a2017-03-31 14:14:53 -07001298 public void setLockCredential(String credential, int type, String savedCredential,
1299 int requestedQuality, int userId)
Andres Morales8fa56652015-03-31 09:19:50 -07001300 throws RemoteException {
Jim Millere484eaf2016-04-13 16:35:36 -07001301 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001302 synchronized (mSeparateChallengeLock) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001303 setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
Pavel Grafov28939982017-10-03 15:11:52 +01001304 setSeparateProfileChallengeEnabledLocked(userId, true, null);
Andrew Scull5daf2732016-11-14 15:02:45 +00001305 notifyPasswordChanged(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001306 }
Pavel Grafov28939982017-10-03 15:11:52 +01001307 notifySeparateProfileChallengeChanged(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001308 }
1309
Rubin Xu1de89b32016-11-30 20:03:13 +00001310 private void setLockCredentialInternal(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001311 String savedCredential, int requestedQuality, int userId) throws RemoteException {
Rubin Xudf406d82017-02-16 16:49:43 +00001312 // Normalize savedCredential and credential such that empty string is always represented
1313 // as null.
1314 if (TextUtils.isEmpty(savedCredential)) {
1315 savedCredential = null;
1316 }
1317 if (TextUtils.isEmpty(credential)) {
1318 credential = null;
1319 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001320 synchronized (mSpManager) {
1321 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1322 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001323 requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001324 return;
1325 }
1326 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001327
Rubin Xu1de89b32016-11-30 20:03:13 +00001328 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1329 if (credential != null) {
1330 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
1331 }
Paul Crowleycc701552016-05-17 14:18:49 -07001332 clearUserKeyProtection(userId);
Andres Moralescfb61602015-04-16 16:31:15 -07001333 getGateKeeperService().clearSecureUserId(userId);
Rubin Xu1de89b32016-11-30 20:03:13 +00001334 mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
Chad Brubakera91a8502015-05-07 10:02:22 -07001335 setKeystorePassword(null, userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001336 fixateNewestUserKeyAuth(userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001337 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
Andrew Scull5daf2732016-11-14 15:02:45 +00001338 notifyActivePasswordMetricsAvailable(null, userId);
Dmitry Dementyev77183ef2018-01-05 15:46:00 -08001339 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001340 return;
1341 }
Rubin Xu1de89b32016-11-30 20:03:13 +00001342 if (credential == null) {
1343 throw new RemoteException("Null credential with mismatched credential type");
Andres Morales8fa56652015-03-31 09:19:50 -07001344 }
Rubin Xua55b1682017-01-31 10:06:56 +00001345
1346 CredentialHash currentHandle = mStorage.readCredentialHash(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001347 if (isManagedProfileWithUnifiedLock(userId)) {
1348 // get credential from keystore when managed profile has unified lock
Rubin Xua55b1682017-01-31 10:06:56 +00001349 if (savedCredential == null) {
1350 try {
1351 savedCredential = getDecryptedPasswordForTiedProfile(userId);
1352 } catch (FileNotFoundException e) {
1353 Slog.i(TAG, "Child profile key not found");
1354 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1355 | NoSuchAlgorithmException | NoSuchPaddingException
1356 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1357 | BadPaddingException | CertificateException | IOException e) {
1358 Slog.e(TAG, "Failed to decrypt child profile key", e);
1359 }
Andres Morales8fa56652015-03-31 09:19:50 -07001360 }
Ricky Waidc283a82016-03-24 19:55:08 +00001361 } else {
Rubin Xua55b1682017-01-31 10:06:56 +00001362 if (currentHandle.hash == null) {
Ricky Waidc283a82016-03-24 19:55:08 +00001363 if (savedCredential != null) {
1364 Slog.w(TAG, "Saved credential provided, but none stored");
1365 }
1366 savedCredential = null;
1367 }
Andres Morales8fa56652015-03-31 09:19:50 -07001368 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001369 synchronized (mSpManager) {
1370 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1371 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001372 currentHandle.type, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001373 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
Adrian Roos7374d3a2017-03-31 14:14:53 -07001374 requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001375 return;
1376 }
1377 }
1378 if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001379 byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
Rubin Xu1de89b32016-11-30 20:03:13 +00001380 userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001381 if (enrolledHandle != null) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001382 CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
1383 mStorage.writeCredentialHash(willStore, userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001384 // push new secret and auth token to vold
1385 GateKeeperResponse gkResponse = getGateKeeperService()
1386 .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
1387 setUserKeyProtection(userId, credential, convertResponse(gkResponse));
Paul Crowleycc701552016-05-17 14:18:49 -07001388 fixateNewestUserKeyAuth(userId);
Rubin Xua55b1682017-01-31 10:06:56 +00001389 // Refresh the auth token
1390 doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
1391 synchronizeUnifiedWorkChallengeForProfiles(userId, null);
Dmitry Dementyev6e167242018-01-25 15:29:50 -08001392 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential,
1393 userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001394 } else {
Rubin Xu1de89b32016-11-30 20:03:13 +00001395 throw new RemoteException("Failed to enroll " +
1396 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
1397 : "pattern"));
Andres Morales8fa56652015-03-31 09:19:50 -07001398 }
1399 }
1400
Rubin Xua55b1682017-01-31 10:06:56 +00001401 private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001402 return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
Rubin Xua55b1682017-01-31 10:06:56 +00001403 }
1404
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001405 @VisibleForTesting
1406 protected void tieProfileLockToParent(int userId, String password) {
Ricky Waidc283a82016-03-24 19:55:08 +00001407 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1408 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1409 byte[] encryptionResult;
1410 byte[] iv;
1411 try {
1412 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1413 keyGenerator.init(new SecureRandom());
1414 SecretKey secretKey = keyGenerator.generateKey();
Ricky Waidc283a82016-03-24 19:55:08 +00001415 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1416 keyStore.load(null);
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001417 try {
1418 keyStore.setEntry(
1419 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1420 new java.security.KeyStore.SecretKeyEntry(secretKey),
1421 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1422 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1423 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1424 .build());
1425 keyStore.setEntry(
1426 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1427 new java.security.KeyStore.SecretKeyEntry(secretKey),
1428 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1429 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1430 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1431 .setUserAuthenticationRequired(true)
1432 .setUserAuthenticationValidityDurationSeconds(30)
Pavel Grafove053c1e2017-08-08 16:53:32 +01001433 .setCriticalToDeviceEncryption(true)
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001434 .build());
1435 // Key imported, obtain a reference to it.
1436 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1437 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1438 Cipher cipher = Cipher.getInstance(
1439 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1440 + KeyProperties.ENCRYPTION_PADDING_NONE);
1441 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1442 encryptionResult = cipher.doFinal(randomLockSeed);
1443 iv = cipher.getIV();
1444 } finally {
1445 // The original key can now be discarded.
1446 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1447 }
Ricky Waidc283a82016-03-24 19:55:08 +00001448 } catch (CertificateException | UnrecoverableKeyException
Zach Jange61672a2016-11-22 17:47:18 +00001449 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
Ricky Waidc283a82016-03-24 19:55:08 +00001450 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1451 throw new RuntimeException("Failed to encrypt key", e);
1452 }
1453 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1454 try {
1455 if (iv.length != PROFILE_KEY_IV_SIZE) {
1456 throw new RuntimeException("Invalid iv length: " + iv.length);
1457 }
1458 outputStream.write(iv);
1459 outputStream.write(encryptionResult);
1460 } catch (IOException e) {
1461 throw new RuntimeException("Failed to concatenate byte arrays", e);
1462 }
1463 mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1464 }
1465
Andres Morales8fa56652015-03-31 09:19:50 -07001466 private byte[] enrollCredential(byte[] enrolledHandle,
1467 String enrolledCredential, String toEnroll, int userId)
1468 throws RemoteException {
Jim Millerde1af082013-09-11 14:58:26 -07001469 checkWritePermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001470 byte[] enrolledCredentialBytes = enrolledCredential == null
1471 ? null
1472 : enrolledCredential.getBytes();
1473 byte[] toEnrollBytes = toEnroll == null
1474 ? null
1475 : toEnroll.getBytes();
Andres Morales23974272015-05-14 22:42:26 -07001476 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1477 enrolledCredentialBytes, toEnrollBytes);
Jim Millerde1af082013-09-11 14:58:26 -07001478
Andres Morales23974272015-05-14 22:42:26 -07001479 if (response == null) {
1480 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001481 }
Jim Millerde1af082013-09-11 14:58:26 -07001482
Andres Morales23974272015-05-14 22:42:26 -07001483 byte[] hash = response.getPayload();
1484 if (hash != null) {
1485 setKeystorePassword(toEnroll, userId);
1486 } else {
1487 // Should not happen
1488 Slog.e(TAG, "Throttled while enrolling a password");
1489 }
Andres Morales8fa56652015-03-31 09:19:50 -07001490 return hash;
Jim Millerde1af082013-09-11 14:58:26 -07001491 }
1492
Rubin Xu3bf722a2016-12-15 16:07:38 +00001493 private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
1494 if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1495 addUserKeyAuth(userId, null, key);
1496 }
1497
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001498 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1499 throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001500 if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001501 if (vcr == null) {
1502 throw new RemoteException("Null response verifying a credential we just set");
1503 }
1504 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1505 throw new RemoteException("Non-OK response verifying a credential we just set: "
Rubin Xu1de89b32016-11-30 20:03:13 +00001506 + vcr.getResponseCode());
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001507 }
1508 byte[] token = vcr.getPayload();
1509 if (token == null) {
1510 throw new RemoteException("Empty payload verifying a credential we just set");
1511 }
Paul Crowleycc701552016-05-17 14:18:49 -07001512 addUserKeyAuth(userId, token, secretFromCredential(credential));
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001513 }
1514
1515 private void clearUserKeyProtection(int userId) throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001516 if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001517 addUserKeyAuth(userId, null, null);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001518 }
1519
1520 private static byte[] secretFromCredential(String credential) throws RemoteException {
1521 try {
1522 MessageDigest digest = MessageDigest.getInstance("SHA-512");
1523 // Personalize the hash
1524 byte[] personalization = "Android FBE credential hash"
1525 .getBytes(StandardCharsets.UTF_8);
1526 // Pad it to the block size of the hash function
1527 personalization = Arrays.copyOf(personalization, 128);
1528 digest.update(personalization);
1529 digest.update(credential.getBytes(StandardCharsets.UTF_8));
1530 return digest.digest();
1531 } catch (NoSuchAlgorithmException e) {
1532 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1533 }
1534 }
1535
Paul Crowleycc701552016-05-17 14:18:49 -07001536 private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001537 throws RemoteException {
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001538 final UserInfo userInfo = mUserManager.getUserInfo(userId);
1539 final IStorageManager storageManager = mInjector.getStorageManager();
Paul Crowley815036f2016-03-29 14:14:48 -07001540 final long callingId = Binder.clearCallingIdentity();
1541 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001542 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
Paul Crowley815036f2016-03-29 14:14:48 -07001543 } finally {
1544 Binder.restoreCallingIdentity(callingId);
1545 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001546 }
1547
Paul Crowleycc701552016-05-17 14:18:49 -07001548 private void fixateNewestUserKeyAuth(int userId)
1549 throws RemoteException {
Rubin Xua55b1682017-01-31 10:06:56 +00001550 if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001551 final IStorageManager storageManager = mInjector.getStorageManager();
Toni Barzic6c818722016-05-27 09:18:39 -07001552 final long callingId = Binder.clearCallingIdentity();
1553 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001554 storageManager.fixateNewestUserKeyAuth(userId);
Toni Barzic6c818722016-05-27 09:18:39 -07001555 } finally {
1556 Binder.restoreCallingIdentity(callingId);
1557 }
Paul Crowleycc701552016-05-17 14:18:49 -07001558 }
1559
Jim Millerde1af082013-09-11 14:58:26 -07001560 @Override
Ricky Wai4613fe42016-05-24 11:11:42 +01001561 public void resetKeyStore(int userId) throws RemoteException {
Ricky Wai7f405f12016-05-31 12:05:05 +01001562 checkWritePermission(userId);
Ricky Wai4613fe42016-05-24 11:11:42 +01001563 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1564 int managedUserId = -1;
1565 String managedUserDecryptedPassword = null;
1566 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1567 for (UserInfo pi : profiles) {
1568 // Unlock managed profile with unified lock
1569 if (pi.isManagedProfile()
1570 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1571 && mStorage.hasChildProfileLock(pi.id)) {
1572 try {
1573 if (managedUserId == -1) {
1574 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1575 managedUserId = pi.id;
1576 } else {
1577 // Should not happen
1578 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1579 + ", uid2:" + pi.id);
1580 }
1581 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1582 | NoSuchAlgorithmException | NoSuchPaddingException
1583 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1584 | BadPaddingException | CertificateException | IOException e) {
1585 Slog.e(TAG, "Failed to decrypt child profile key", e);
1586 }
1587 }
1588 }
1589 try {
1590 // Clear all the users credentials could have been installed in for this user.
1591 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1592 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1593 mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1594 }
1595 }
1596 } finally {
1597 if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1598 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
Zach Jange61672a2016-11-22 17:47:18 +00001599 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
Ricky Wai4613fe42016-05-24 11:11:42 +01001600 }
1601 }
1602 }
1603
1604 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001605 public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001606 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xu1de89b32016-11-30 20:03:13 +00001607 checkPasswordReadPermission(userId);
1608 return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001609 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001610
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001611 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001612 public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
1613 int userId) throws RemoteException {
1614 checkPasswordReadPermission(userId);
1615 return doVerifyCredential(credential, type, true, challenge, userId,
1616 null /* progressCallback */);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001617 }
1618
Rubin Xu1de89b32016-11-30 20:03:13 +00001619 /**
1620 * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
1621 * format.
1622 */
1623 private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001624 boolean hasChallenge, long challenge, int userId,
1625 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xu1de89b32016-11-30 20:03:13 +00001626 if (TextUtils.isEmpty(credential)) {
1627 throw new IllegalArgumentException("Credential can't be null or empty");
1628 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001629 if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
1630 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
1631 Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
1632 return VerifyCredentialResponse.ERROR;
1633 }
Rubin Xue94a7702017-06-20 17:29:57 +01001634 VerifyCredentialResponse response = null;
1635 response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
1636 userId, progressCallback);
1637 // The user employs synthetic password based credential.
1638 if (response != null) {
Robert Berry40386df2018-01-22 21:16:58 +00001639 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1640 mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
1641 userId);
1642 }
Rubin Xue94a7702017-06-20 17:29:57 +01001643 return response;
Rubin Xu3bf722a2016-12-15 16:07:38 +00001644 }
Rubin Xue94a7702017-06-20 17:29:57 +01001645
Adrian Roos7374d3a2017-03-31 14:14:53 -07001646 if (userId == USER_FRP) {
Andrew Scull971f2942017-07-12 15:09:45 +01001647 Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
1648 return VerifyCredentialResponse.ERROR;
Adrian Roos7374d3a2017-03-31 14:14:53 -07001649 }
1650
Andrew Scull971f2942017-07-12 15:09:45 +01001651 final CredentialHash storedHash = mStorage.readCredentialHash(userId);
Rubin Xu1de89b32016-11-30 20:03:13 +00001652 if (storedHash.type != credentialType) {
1653 Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
1654 + " stored: " + storedHash.type + " passed in: " + credentialType);
1655 return VerifyCredentialResponse.ERROR;
1656 }
Andres Moralese40bad82015-05-28 14:21:36 -07001657
Rubin Xu1de89b32016-11-30 20:03:13 +00001658 boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1659 && storedHash.isBaseZeroPattern;
Andres Moralese40bad82015-05-28 14:21:36 -07001660
Rubin Xu1de89b32016-11-30 20:03:13 +00001661 String credentialToVerify;
1662 if (shouldReEnrollBaseZero) {
1663 credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
1664 } else {
1665 credentialToVerify = credential;
1666 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001667
Rubin Xue94a7702017-06-20 17:29:57 +01001668 response = verifyCredential(userId, storedHash, credentialToVerify,
Rubin Xu1de89b32016-11-30 20:03:13 +00001669 hasChallenge, challenge, progressCallback);
Andres Morales59ef1262015-06-26 13:56:39 -07001670
Michal Karpinskie71f5832017-01-13 18:18:49 +00001671 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1672 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1673 if (shouldReEnrollBaseZero) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001674 setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
1675 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
Michal Karpinskie71f5832017-01-13 18:18:49 +00001676 }
Rubin Xu1de89b32016-11-30 20:03:13 +00001677 }
Andres Moralese40bad82015-05-28 14:21:36 -07001678
Rubin Xu1de89b32016-11-30 20:03:13 +00001679 return response;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001680 }
1681
1682 @Override
Rubin Xu1de89b32016-11-30 20:03:13 +00001683 public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
Ricky Wai53940d42016-04-05 15:29:24 +01001684 long challenge, int userId) throws RemoteException {
1685 checkPasswordReadPermission(userId);
1686 if (!isManagedProfileWithUnifiedLock(userId)) {
1687 throw new RemoteException("User id must be managed profile with unified lock");
1688 }
1689 final int parentProfileId = mUserManager.getProfileParent(userId).id;
1690 // Unlock parent by using parent's challenge
Rubin Xu1de89b32016-11-30 20:03:13 +00001691 final VerifyCredentialResponse parentResponse = doVerifyCredential(
1692 credential,
1693 type,
1694 true /* hasChallenge */,
1695 challenge,
1696 parentProfileId,
1697 null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001698 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1699 // Failed, just return parent's response
1700 return parentResponse;
1701 }
1702
1703 try {
1704 // Unlock work profile, and work profile with unified lock must use password only
Rubin Xu1de89b32016-11-30 20:03:13 +00001705 return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
1706 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1707 true,
Ricky Wai53940d42016-04-05 15:29:24 +01001708 challenge,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001709 userId, null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001710 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1711 | NoSuchAlgorithmException | NoSuchPaddingException
1712 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1713 | BadPaddingException | CertificateException | IOException e) {
1714 Slog.e(TAG, "Failed to decrypt child profile key", e);
1715 throw new RemoteException("Unable to get tied profile token");
1716 }
1717 }
1718
Rubin Xu1de89b32016-11-30 20:03:13 +00001719 /**
1720 * Lowest-level credential verification routine that talks to GateKeeper. If verification
1721 * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
1722 * hash to GK.
1723 */
Andres Morales23974272015-05-14 22:42:26 -07001724 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
Rubin Xu1de89b32016-11-30 20:03:13 +00001725 String credential, boolean hasChallenge, long challenge,
1726 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Andres Morales23974272015-05-14 22:42:26 -07001727 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1728 // don't need to pass empty credentials to GateKeeper
1729 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001730 }
1731
Andrew Zeng750563e2017-03-10 15:14:08 -08001732 if (storedHash == null || TextUtils.isEmpty(credential)) {
Andres Morales23974272015-05-14 22:42:26 -07001733 return VerifyCredentialResponse.ERROR;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001734 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001735
Jeff Sharkeyeddf5182016-08-09 16:36:08 -06001736 // We're potentially going to be doing a bunch of disk I/O below as part
1737 // of unlocking the user, so yell if calling from the main thread.
1738 StrictMode.noteDiskRead();
1739
Andres Morales8fa56652015-03-31 09:19:50 -07001740 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001741 final byte[] hash;
1742 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1743 hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
1744 } else {
Rubin Xuf01e9072018-03-30 20:59:28 +01001745 hash = mLockPatternUtils.legacyPasswordToHash(credential, userId)
1746 .getBytes(StandardCharsets.UTF_8);
Rubin Xu1de89b32016-11-30 20:03:13 +00001747 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001748 if (Arrays.equals(hash, storedHash.hash)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001749 if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1750 unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
1751 } else {
1752 unlockKeystore(credential, userId);
1753 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001754 // Users with legacy credentials don't have credential-backed
1755 // FBE keys, so just pass through a fake token/secret
1756 Slog.i(TAG, "Unlocking user with fake token: " + userId);
1757 final byte[] fakeToken = String.valueOf(userId).getBytes();
1758 unlockUser(userId, fakeToken, fakeToken);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001759
Andres Morales23974272015-05-14 22:42:26 -07001760 // migrate credential to GateKeeper
Adrian Roos7374d3a2017-03-31 14:14:53 -07001761 setLockCredentialInternal(credential, storedHash.type, null,
1762 storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1763 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1764 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1765 /* TODO(roosa): keep the same password quality */, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001766 if (!hasChallenge) {
Andrew Scull5daf2732016-11-14 15:02:45 +00001767 notifyActivePasswordMetricsAvailable(credential, userId);
Robert Berryf899bff2017-12-28 17:34:38 +00001768 // Use credentials to create recoverable keystore snapshot.
1769 mRecoverableKeyStoreManager.lockScreenSecretAvailable(
1770 storedHash.type, credential, userId);
Andres Morales23974272015-05-14 22:42:26 -07001771 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001772 }
1773 // Fall through to get the auth token. Technically this should never happen,
Andres Morales23974272015-05-14 22:42:26 -07001774 // as a user that had a legacy credential would have to unlock their device
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001775 // before getting to a flow with a challenge, but supporting for consistency.
1776 } else {
Andres Morales23974272015-05-14 22:42:26 -07001777 return VerifyCredentialResponse.ERROR;
Andres Morales8fa56652015-03-31 09:19:50 -07001778 }
Andres Morales8fa56652015-03-31 09:19:50 -07001779 }
Paul Crowley98e0a262016-02-04 09:41:53 +00001780 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1781 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
Rubin Xua55b1682017-01-31 10:06:56 +00001782 VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
1783 boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
Andres Morales8fa56652015-03-31 09:19:50 -07001784
Andres Morales23974272015-05-14 22:42:26 -07001785 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001786
Andres Morales23974272015-05-14 22:42:26 -07001787 // credential has matched
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001788
1789 if (progressCallback != null) {
1790 progressCallback.onCredentialVerified();
1791 }
Andrew Scull5daf2732016-11-14 15:02:45 +00001792 notifyActivePasswordMetricsAvailable(credential, userId);
Andres Morales23974272015-05-14 22:42:26 -07001793 unlockKeystore(credential, userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001794
Rubin Xu3bf722a2016-12-15 16:07:38 +00001795 Slog.i(TAG, "Unlocking user " + userId + " with token length "
1796 + response.getPayload().length);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001797 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001798
Ricky Waidc283a82016-03-24 19:55:08 +00001799 if (isManagedProfileWithSeparatedLock(userId)) {
Clara Bayarri56878a92015-10-29 15:43:55 +00001800 TrustManager trustManager =
1801 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1802 trustManager.setDeviceLockedForUser(userId, false);
1803 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001804 int reEnrollQuality = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1805 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1806 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1807 /* TODO(roosa): keep the same password quality */;
Andres Morales23974272015-05-14 22:42:26 -07001808 if (shouldReEnroll) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07001809 setLockCredentialInternal(credential, storedHash.type, credential,
1810 reEnrollQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001811 } else {
1812 // Now that we've cleared of all required GK migration, let's do the final
1813 // migration to synthetic password.
1814 synchronized (mSpManager) {
1815 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
Rubin Xu128180b2017-04-12 18:02:44 +01001816 AuthenticationToken auth = initializeSyntheticPasswordLocked(
Adrian Roos7374d3a2017-03-31 14:14:53 -07001817 storedHash.hash, credential, storedHash.type, reEnrollQuality,
1818 userId);
Rubin Xu128180b2017-04-12 18:02:44 +01001819 activateEscrowTokens(auth, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00001820 }
1821 }
Andres Morales23974272015-05-14 22:42:26 -07001822 }
Dmitry Dementyev6a509e42017-12-19 14:47:26 -08001823 // Use credentials to create recoverable keystore snapshot.
1824 mRecoverableKeyStoreManager.lockScreenSecretAvailable(storedHash.type, credential,
1825 userId);
1826
Adrian Roos873010d2015-08-25 15:59:00 -07001827 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1828 if (response.getTimeout() > 0) {
1829 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1830 }
Andres Morales23974272015-05-14 22:42:26 -07001831 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001832
Andres Morales23974272015-05-14 22:42:26 -07001833 return response;
1834 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001835
Rubin Xu7cf45092017-08-28 11:47:35 +01001836 /**
1837 * Call this method to notify DPMS regarding the latest password metric. This should be called
1838 * when the user is authenticating or when a new password is being set.
1839 */
Andrew Scull5daf2732016-11-14 15:02:45 +00001840 private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
1841 final PasswordMetrics metrics;
1842 if (password == null) {
1843 metrics = new PasswordMetrics();
1844 } else {
1845 metrics = PasswordMetrics.computeForPassword(password);
1846 metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
1847 }
1848
1849 // Asynchronous to avoid dead lock
1850 mHandler.post(() -> {
1851 DevicePolicyManager dpm = (DevicePolicyManager)
1852 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1853 dpm.setActivePasswordState(metrics, userId);
1854 });
1855 }
1856
1857 /**
1858 * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
1859 * reporting the password changed.
1860 */
1861 private void notifyPasswordChanged(@UserIdInt int userId) {
1862 // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
1863 mHandler.post(() -> {
1864 DevicePolicyManager dpm = (DevicePolicyManager)
1865 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1866 dpm.reportPasswordChanged(userId);
1867 });
1868 }
1869
Amith Yamasani52c489c2012-03-28 11:42:42 -07001870 @Override
Adrian Roos261d5ab2014-10-29 14:42:38 +01001871 public boolean checkVoldPassword(int userId) throws RemoteException {
Paul Lawrence945490c2014-03-27 16:37:28 +00001872 if (!mFirstCallToVold) {
1873 return false;
1874 }
1875 mFirstCallToVold = false;
1876
1877 checkPasswordReadPermission(userId);
1878
1879 // There's no guarantee that this will safely connect, but if it fails
1880 // we will simply show the lock screen when we shouldn't, so relatively
1881 // benign. There is an outside chance something nasty would happen if
1882 // this service restarted before vold stales out the password in this
1883 // case. The nastiness is limited to not showing the lock screen when
1884 // we should, within the first minute of decrypting the phone if this
1885 // service can't connect to vold, it restarts, and then the new instance
1886 // does successfully connect.
Rubin Xu0cbc19e2016-12-09 14:00:21 +00001887 final IStorageManager service = mInjector.getStorageManager();
Paul Lawrence0bbd1082016-04-26 15:21:02 -07001888 String password;
1889 long identity = Binder.clearCallingIdentity();
1890 try {
1891 password = service.getPassword();
1892 service.clearPassword();
1893 } finally {
1894 Binder.restoreCallingIdentity(identity);
1895 }
Paul Lawrence945490c2014-03-27 16:37:28 +00001896 if (password == null) {
1897 return false;
1898 }
1899
1900 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001901 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001902 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
1903 null /* progressCallback */)
1904 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001905 return true;
1906 }
1907 }
1908 } catch (Exception e) {
1909 }
1910
1911 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001912 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001913 if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
1914 null /* progressCallback */)
1915 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001916 return true;
1917 }
1918 }
1919 } catch (Exception e) {
1920 }
1921
1922 return false;
1923 }
1924
Amith Yamasanif11a5742016-06-16 08:20:07 -07001925 private void removeUser(int userId, boolean unknownUser) {
Rubin Xu7b7424b2017-03-31 18:03:20 +01001926 mSpManager.removeUser(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +01001927 mStorage.removeUser(userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001928 mStrongAuth.removeUser(userId);
Andrew Scullede482d2018-01-30 13:54:29 +00001929 tryRemoveUserFromSpCacheLater(userId);
Robin Lee49d810c2014-09-23 13:50:22 +01001930
1931 final KeyStore ks = KeyStore.getInstance();
Chad Brubaker83ce0952015-05-12 13:00:02 -07001932 ks.onUserRemoved(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001933
1934 try {
1935 final IGateKeeperService gk = getGateKeeperService();
1936 if (gk != null) {
Rubin Xu1de89b32016-11-30 20:03:13 +00001937 gk.clearSecureUserId(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001938 }
1939 } catch (RemoteException ex) {
1940 Slog.w(TAG, "unable to clear GK secure user id");
1941 }
Amith Yamasanif11a5742016-06-16 08:20:07 -07001942 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
Ricky Waidc283a82016-03-24 19:55:08 +00001943 removeKeystoreProfileKey(userId);
1944 }
1945 }
1946
1947 private void removeKeystoreProfileKey(int targetUserId) {
1948 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1949 try {
1950 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1951 keyStore.load(null);
Ricky Waid3982442016-05-24 19:27:08 +01001952 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1953 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
Ricky Waidc283a82016-03-24 19:55:08 +00001954 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1955 | IOException e) {
1956 // We have tried our best to remove all keys
1957 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1958 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001959 }
1960
Adrian Roosb5e47222015-08-14 15:53:06 -07001961 @Override
1962 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1963 checkPasswordReadPermission(UserHandle.USER_ALL);
1964 mStrongAuth.registerStrongAuthTracker(tracker);
1965 }
1966
1967 @Override
1968 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1969 checkPasswordReadPermission(UserHandle.USER_ALL);
1970 mStrongAuth.unregisterStrongAuthTracker(tracker);
1971 }
1972
1973 @Override
1974 public void requireStrongAuth(int strongAuthReason, int userId) {
1975 checkWritePermission(userId);
1976 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1977 }
1978
Adrian Roos4ab7e592016-04-13 15:38:13 -07001979 @Override
1980 public void userPresent(int userId) {
1981 checkWritePermission(userId);
1982 mStrongAuth.reportUnlock(userId);
1983 }
1984
Victor Changa0940d32016-05-16 19:36:08 +01001985 @Override
1986 public int getStrongAuthForUser(int userId) {
1987 checkPasswordReadPermission(userId);
1988 return mStrongAuthTracker.getStrongAuthForUser(userId);
1989 }
1990
Jorim Jaggi2fef6f72016-11-01 19:06:25 -07001991 private boolean isCallerShell() {
1992 final int callingUid = Binder.getCallingUid();
1993 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1994 }
1995
1996 private void enforceShell() {
1997 if (!isCallerShell()) {
1998 throw new SecurityException("Caller must be shell");
1999 }
2000 }
2001
2002 @Override
2003 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2004 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
2005 throws RemoteException {
2006 enforceShell();
2007 final long origId = Binder.clearCallingIdentity();
2008 try {
2009 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
2010 this, in, out, err, args, callback, resultReceiver);
2011 } finally {
2012 Binder.restoreCallingIdentity(origId);
2013 }
2014 }
2015
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002016 @Override
Bo Zhu7f414d92018-02-28 09:28:19 -08002017 public void initRecoveryServiceWithSigFile(@NonNull String rootCertificateAlias,
2018 @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile)
2019 throws RemoteException {
2020 mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(rootCertificateAlias,
2021 recoveryServiceCertFile, recoveryServiceSigFile);
2022 }
2023
2024 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002025 public @NonNull KeyChainSnapshot getKeyChainSnapshot() throws RemoteException {
Dmitry Dementyevb4fb9872018-01-26 11:49:34 -08002026 return mRecoverableKeyStoreManager.getKeyChainSnapshot();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002027 }
2028
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002029 @Override
Dmitry Dementyev14298312018-01-04 15:19:19 -08002030 public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002031 throws RemoteException {
Dmitry Dementyev14298312018-01-04 15:19:19 -08002032 mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent);
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002033 }
2034
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002035 @Override
Dmitry Dementyev7d8c78a2018-01-12 19:14:07 -08002036 public void setServerParams(byte[] serverParams) throws RemoteException {
2037 mRecoverableKeyStoreManager.setServerParams(serverParams);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002038 }
2039
2040 @Override
Robert Berrybbe02ae2018-02-20 19:47:43 +00002041 public void setRecoveryStatus(String alias, int status) throws RemoteException {
2042 mRecoverableKeyStoreManager.setRecoveryStatus(alias, status);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002043 }
2044
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002045 @Override
2046 public @NonNull Map getRecoveryStatus() throws RemoteException {
Robert Berry56f06b42018-02-23 13:31:32 +00002047 return mRecoverableKeyStoreManager.getRecoveryStatus();
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -08002048 }
2049
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002050 @Override
Dmitry Dementyev0916e7c2018-01-23 13:02:08 -08002051 public void setRecoverySecretTypes(@NonNull @KeyChainProtectionParams.UserSecretType
Dmitry Dementyev14298312018-01-04 15:19:19 -08002052 int[] secretTypes) throws RemoteException {
2053 mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002054 }
2055
2056 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002057 public @NonNull int[] getRecoverySecretTypes() throws RemoteException {
Dmitry Dementyev14298312018-01-04 15:19:19 -08002058 return mRecoverableKeyStoreManager.getRecoverySecretTypes();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002059
2060 }
2061
2062 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002063 public @NonNull byte[] startRecoverySessionWithCertPath(@NonNull String sessionId,
Bo Zhub31ab672018-03-20 22:44:18 -07002064 @NonNull String rootCertificateAlias, @NonNull RecoveryCertPath verifierCertPath,
2065 @NonNull byte[] vaultParams, @NonNull byte[] vaultChallenge,
2066 @NonNull List<KeyChainProtectionParams> secrets)
Bo Zhu7c1972f2018-02-22 21:43:52 -08002067 throws RemoteException {
2068 return mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
Bo Zhub31ab672018-03-20 22:44:18 -07002069 sessionId, rootCertificateAlias, verifierCertPath, vaultParams, vaultChallenge,
2070 secrets);
Bo Zhu7c1972f2018-02-22 21:43:52 -08002071 }
2072
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002073 @Override
Robert Berry4a5c87d2018-03-19 18:00:46 +00002074 public Map<String, String> recoverKeyChainSnapshot(
2075 @NonNull String sessionId,
2076 @NonNull byte[] recoveryKeyBlob,
2077 @NonNull List<WrappedApplicationKey> applicationKeys) throws RemoteException {
2078 return mRecoverableKeyStoreManager.recoverKeyChainSnapshot(
2079 sessionId, recoveryKeyBlob, applicationKeys);
2080 }
2081
2082 @Override
Dmitry Dementyev745d2c92018-04-13 14:10:05 -07002083 public void closeSession(@NonNull String sessionId) throws RemoteException {
2084 mRecoverableKeyStoreManager.closeSession(sessionId);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -08002085 }
2086
Robert Berrycfc990a2017-12-22 15:54:30 +00002087 @Override
Robert Berry5daccec2018-01-06 19:16:25 +00002088 public void removeKey(@NonNull String alias) throws RemoteException {
2089 mRecoverableKeyStoreManager.removeKey(alias);
2090 }
2091
2092 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002093 public @Nullable String generateKey(@NonNull String alias) throws RemoteException {
Robert Berrya3b99472018-02-23 15:59:02 +00002094 return mRecoverableKeyStoreManager.generateKey(alias);
Dmitry Dementyev29b9de52018-01-31 16:09:32 -08002095 }
2096
2097 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002098 public @Nullable String importKey(@NonNull String alias, byte[] keyBytes) throws RemoteException {
Bo Zhu2c8e5382018-02-26 15:54:25 -08002099 return mRecoverableKeyStoreManager.importKey(alias, keyBytes);
2100 }
2101
2102 @Override
Dmitry Dementyev4da14e02018-03-23 15:18:33 -07002103 public @Nullable String getKey(@NonNull String alias) throws RemoteException {
Dmitry Dementyev29b9de52018-01-31 16:09:32 -08002104 return mRecoverableKeyStoreManager.getKey(alias);
2105 }
2106
Amith Yamasani52c489c2012-03-28 11:42:42 -07002107 private static final String[] VALID_SETTINGS = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002108 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
Rubin Xu1de89b32016-11-30 20:03:13 +00002109 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
2110 LockPatternUtils.PASSWORD_TYPE_KEY,
2111 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
2112 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2113 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
2114 LockPatternUtils.LOCKSCREEN_OPTIONS,
2115 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
2116 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
2117 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
2118 LockPatternUtils.PASSWORD_HISTORY_KEY,
2119 Secure.LOCK_PATTERN_ENABLED,
2120 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
2121 Secure.LOCK_PATTERN_VISIBLE,
2122 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
Jim Miller187ec582013-04-15 18:27:54 -07002123 };
2124
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +00002125 // Reading these settings needs the contacts permission
2126 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002127 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
2128 Secure.LOCK_SCREEN_OWNER_INFO
Jim Miller187ec582013-04-15 18:27:54 -07002129 };
Paul Lawrence945490c2014-03-27 16:37:28 +00002130
Adrian Roos001b00d2015-02-24 17:08:48 +01002131 // Reading these settings needs the same permission as checking the password
2132 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
2133 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
2134 LockPatternUtils.PASSWORD_HISTORY_KEY,
Adrian Roos855fa302015-04-02 16:01:12 +02002135 LockPatternUtils.PASSWORD_TYPE_KEY,
Ricky Wai7f405f12016-05-31 12:05:05 +01002136 SEPARATE_PROFILE_CHALLENGE_KEY
Adrian Roos001b00d2015-02-24 17:08:48 +01002137 };
2138
Amith Yamasani072543f2015-02-13 11:09:45 -08002139 private static final String[] SETTINGS_TO_BACKUP = new String[] {
Rubin Xu1de89b32016-11-30 20:03:13 +00002140 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
Bryan Mawhinneye483b562017-05-15 14:46:05 +01002141 Secure.LOCK_SCREEN_OWNER_INFO,
2142 Secure.LOCK_PATTERN_VISIBLE,
2143 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
Amith Yamasani072543f2015-02-13 11:09:45 -08002144 };
2145
Andres Morales301ea442015-04-17 09:15:47 -07002146 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
2147 @Override
2148 public void binderDied() {
2149 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
2150 mGateKeeperService = null;
2151 }
2152 }
2153
Rubin Xu3bf722a2016-12-15 16:07:38 +00002154 protected synchronized IGateKeeperService getGateKeeperService()
Andres Morales301ea442015-04-17 09:15:47 -07002155 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -07002156 if (mGateKeeperService != null) {
2157 return mGateKeeperService;
2158 }
2159
Rubin Xu1de89b32016-11-30 20:03:13 +00002160 final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
Andres Morales8fa56652015-03-31 09:19:50 -07002161 if (service != null) {
Andres Morales301ea442015-04-17 09:15:47 -07002162 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
Andres Morales8fa56652015-03-31 09:19:50 -07002163 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
2164 return mGateKeeperService;
2165 }
2166
2167 Slog.e(TAG, "Unable to acquire GateKeeperService");
2168 return null;
2169 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00002170
2171 /**
Andrew Scull1416bd02018-01-05 18:33:58 +00002172 * A user's synthetic password does not change so it must be cached in certain circumstances to
2173 * enable untrusted credential reset.
2174 *
2175 * Untrusted credential reset will be removed in a future version (b/68036371) at which point
2176 * this cache is no longer needed as the SP will always be known when changing the user's
2177 * credential.
2178 */
2179 @GuardedBy("mSpManager")
2180 private SparseArray<AuthenticationToken> mSpCache = new SparseArray();
2181
2182 private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
Andrew Scullede482d2018-01-30 13:54:29 +00002183 // Preemptively cache the SP and then try to remove it in a handler.
2184 Slog.i(TAG, "Caching SP for user " + userId);
2185 synchronized (mSpManager) {
2186 mSpCache.put(userId, auth);
2187 }
2188 tryRemoveUserFromSpCacheLater(userId);
2189
Andrew Sculle6527c12018-01-05 18:33:58 +00002190 // Pass the primary user's auth secret to the HAL
2191 if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
2192 try {
2193 final byte[] rawSecret = auth.deriveVendorAuthSecret();
2194 final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length);
2195 for (int i = 0; i < rawSecret.length; ++i) {
2196 secret.add(rawSecret[i]);
2197 }
2198 mAuthSecretService.primaryUserCredential(secret);
2199 } catch (RemoteException e) {
2200 Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
2201 }
2202 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002203 }
2204
Andrew Scullede482d2018-01-30 13:54:29 +00002205 private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) {
2206 mHandler.post(() -> {
2207 if (!shouldCacheSpForUser(userId)) {
2208 // The transition from 'should not cache' to 'should cache' can only happen if
2209 // certain admin apps are installed after provisioning e.g. via adb. This is not
2210 // a common case and we do not seamlessly support; it may result in the SP not
2211 // being cached when it is needed. The cache can be re-populated by verifying
2212 // the credential again.
2213 Slog.i(TAG, "Removing SP from cache for user " + userId);
2214 synchronized (mSpManager) {
2215 mSpCache.remove(userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002216 }
2217 }
Andrew Scullede482d2018-01-30 13:54:29 +00002218 });
Andrew Scull1416bd02018-01-05 18:33:58 +00002219 }
2220
Andrew Scullede482d2018-01-30 13:54:29 +00002221 /** Do not hold any of the locks from this service when calling. */
Andrew Scull1416bd02018-01-05 18:33:58 +00002222 private boolean shouldCacheSpForUser(@UserIdInt int userId) {
2223 // Before the user setup has completed, an admin could be installed that requires the SP to
2224 // be cached (see below).
2225 if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
2226 Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 0) {
2227 return true;
2228 }
2229
2230 // If the user has an admin which can perform an untrusted credential reset, the SP needs to
2231 // be cached. If there isn't a DevicePolicyManager then there can't be an admin in the first
2232 // place so caching is not necessary.
2233 final DevicePolicyManagerInternal dpmi = LocalServices.getService(
2234 DevicePolicyManagerInternal.class);
2235 if (dpmi == null) {
2236 return false;
2237 }
2238 return dpmi.canUserHaveUntrustedCredentialReset(userId);
2239 }
2240
2241 /**
Rubin Xu3bf722a2016-12-15 16:07:38 +00002242 * Precondition: vold and keystore unlocked.
2243 *
2244 * Create new synthetic password, set up synthetic password blob protected by the supplied
2245 * user credential, and make the newly-created SP blob active.
2246 *
2247 * The invariant under a synthetic password is:
2248 * 1. If user credential exists, then both vold and keystore and protected with keys derived
2249 * from the synthetic password.
2250 * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
2251 * make it consistent with current behaviour. It also allows ActivityManager to call
2252 * unlockUser() with empty secret.
2253 * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
2254 * whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
2255 * lockscreen PIN, we still maintain the existing synthetic password in a password blob
Andrew Scull1416bd02018-01-05 18:33:58 +00002256 * protected by a default PIN.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002257 * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
2258 * clears/re-creates his lockscreen PIN.
2259 *
2260 *
2261 * Different cases of calling this method:
2262 * 1. credentialHash != null
2263 * This implies credential != null, a new SP blob will be provisioned, and existing SID
2264 * migrated to associate with the new SP.
2265 * This happens during a normal migration case when the user currently has password.
2266 *
2267 * 2. credentialhash == null and credential == null
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002268 * A new SP blob and will be created, while the user has no credentials.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002269 * This can happens when we are activating an escrow token on a unsecured device, during
2270 * which we want to create the SP structure with an empty user credential.
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002271 * This could also happen during an untrusted reset to clear password.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002272 *
2273 * 3. credentialhash == null and credential != null
2274 * This is the untrusted credential reset, OR the user sets a new lockscreen password
2275 * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
2276 */
Andrew Scull1416bd02018-01-05 18:33:58 +00002277 @GuardedBy("mSpManager")
Rubin Xu16c823e2017-06-27 14:44:58 +01002278 @VisibleForTesting
2279 protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002280 String credential, int credentialType, int requestedQuality,
2281 int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002282 Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002283 final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
2284 getGateKeeperService(), credentialHash, credential, userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002285 onAuthTokenKnownForUser(userId, auth);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002286 if (auth == null) {
2287 Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
2288 return null;
2289 }
2290 long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
Adrian Roos7374d3a2017-03-31 14:14:53 -07002291 credential, credentialType, auth, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002292 if (credential != null) {
2293 if (credentialHash == null) {
2294 // Since when initializing SP, we didn't provide an existing password handle
2295 // for it to migrate SID, we need to create a new SID for the user.
2296 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2297 }
2298 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2299 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2300 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2301 } else {
2302 clearUserKeyProtection(userId);
2303 setKeystorePassword(null, userId);
2304 getGateKeeperService().clearSecureUserId(userId);
2305 }
2306 fixateNewestUserKeyAuth(userId);
2307 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
2308 return auth;
2309 }
2310
2311 private long getSyntheticPasswordHandleLocked(int userId) {
Adrian Roos60dcbbf2017-08-08 16:19:33 +02002312 return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY,
2313 SyntheticPasswordManager.DEFAULT_HANDLE, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002314 }
2315
Rubin Xufcd49f92017-08-24 18:21:52 +01002316 private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002317 if (userId == USER_FRP) {
2318 final int type = mStorage.readPersistentDataBlock().type;
2319 return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
2320 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00002321 long handle = getSyntheticPasswordHandleLocked(userId);
2322 // This is a global setting
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00002323 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
2324 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002325 return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
2326 }
2327
Rubin Xu16c823e2017-06-27 14:44:58 +01002328 @VisibleForTesting
Rubin Xufcd49f92017-08-24 18:21:52 +01002329 protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002330 long handle = getSyntheticPasswordHandleLocked(userId);
2331 // This is a global setting
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00002332 long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
2333 SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002334 return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
2335 }
2336
Rubin Xufcd49f92017-08-24 18:21:52 +01002337 private void enableSyntheticPasswordLocked() {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002338 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
2339 }
2340
Rubin Xue94a7702017-06-20 17:29:57 +01002341 private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
Rubin Xu3bf722a2016-12-15 16:07:38 +00002342 credentialType, boolean hasChallenge, long challenge, int userId,
2343 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Rubin Xue94a7702017-06-20 17:29:57 +01002344 if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002345 if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
2346 userCredential = null;
2347 }
Rubin Xue94a7702017-06-20 17:29:57 +01002348
2349 final AuthenticationResult authResult;
2350 VerifyCredentialResponse response;
2351 synchronized (mSpManager) {
2352 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
2353 return null;
2354 }
2355 if (userId == USER_FRP) {
2356 return mSpManager.verifyFrpCredential(getGateKeeperService(),
2357 userCredential, credentialType, progressCallback);
2358 }
2359
2360 long handle = getSyntheticPasswordHandleLocked(userId);
2361 authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
Rubin Xucf326f12017-11-15 11:55:35 +00002362 getGateKeeperService(), handle, userCredential, userId, progressCallback);
Rubin Xue94a7702017-06-20 17:29:57 +01002363
Rubin Xu16c823e2017-06-27 14:44:58 +01002364 if (authResult.credentialType != credentialType) {
2365 Slog.e(TAG, "Credential type mismatch.");
2366 return VerifyCredentialResponse.ERROR;
2367 }
Rubin Xue94a7702017-06-20 17:29:57 +01002368 response = authResult.gkResponse;
2369 // credential has matched
2370 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
2371 // perform verifyChallenge with synthetic password which generates the real GK auth
2372 // token and response for the current user
2373 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
2374 challenge, userId);
2375 if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2376 // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
2377 // match the recorded GK password handle.
2378 Slog.wtf(TAG, "verifyChallenge with SP failed.");
2379 return VerifyCredentialResponse.ERROR;
2380 }
2381 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07002382 }
2383
Rubin Xu3bf722a2016-12-15 16:07:38 +00002384 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002385 notifyActivePasswordMetricsAvailable(userCredential, userId);
2386 unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
2387
2388 final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
2389 Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
2390 unlockUser(userId, null, secret);
2391
Rubin Xue94a7702017-06-20 17:29:57 +01002392 activateEscrowTokens(authResult.authToken, userId);
2393
Rubin Xu3bf722a2016-12-15 16:07:38 +00002394 if (isManagedProfileWithSeparatedLock(userId)) {
2395 TrustManager trustManager =
2396 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
2397 trustManager.setDeviceLockedForUser(userId, false);
2398 }
Rubin Xue94a7702017-06-20 17:29:57 +01002399 mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
Andrew Scull1416bd02018-01-05 18:33:58 +00002400
2401 onAuthTokenKnownForUser(userId, authResult.authToken);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002402 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
2403 if (response.getTimeout() > 0) {
2404 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
2405 }
2406 }
2407
2408 return response;
2409 }
2410
2411 /**
2412 * Change the user's lockscreen password by creating a new SP blob and update the handle, based
2413 * on an existing authentication token. Even though a new SP blob is created, the underlying
2414 * synthetic password is never changed.
2415 *
2416 * When clearing credential, we keep the SP unchanged, but clear its password handle so its
2417 * SID is gone. We also clear password from (software-based) keystore and vold, which will be
2418 * added back when new password is set in future.
2419 */
Andrew Scull1416bd02018-01-05 18:33:58 +00002420 @GuardedBy("mSpManager")
Rubin Xu3bf722a2016-12-15 16:07:38 +00002421 private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002422 AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002423 if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
2424 long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
Adrian Roos7374d3a2017-03-31 14:14:53 -07002425 credential, credentialType, auth, requestedQuality, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002426 final Map<Integer, String> profilePasswords;
2427 if (credential != null) {
2428 // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
2429 profilePasswords = null;
2430
2431 if (mSpManager.hasSidForUser(userId)) {
2432 // We are changing password of a secured device, nothing more needed as
2433 // createPasswordBasedSyntheticPassword has already taken care of maintaining
2434 // the password handle and SID unchanged.
2435
2436 //refresh auth token
2437 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2438 } else {
2439 // A new password is set on a previously-unsecured device, we need to generate
2440 // a new SID, and re-add keys to vold and keystore.
2441 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2442 mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
2443 setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
2444 fixateNewestUserKeyAuth(userId);
2445 setKeystorePassword(auth.deriveKeyStorePassword(), userId);
2446 }
2447 } else {
2448 // Cache all profile password if they use unified work challenge. This will later be
2449 // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
2450 profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
2451
2452 // we are clearing password of a secured device, so need to nuke SID as well.
2453 mSpManager.clearSidForUser(userId);
2454 getGateKeeperService().clearSecureUserId(userId);
2455 // Clear key from vold so ActivityManager can just unlock the user with empty secret
2456 // during boot.
2457 clearUserKeyProtection(userId);
2458 fixateNewestUserKeyAuth(userId);
2459 setKeystorePassword(null, userId);
2460 }
2461 setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
2462 synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
Rubin Xu7cf45092017-08-28 11:47:35 +01002463
2464 notifyActivePasswordMetricsAvailable(credential, userId);
Rubin Xu3bf722a2016-12-15 16:07:38 +00002465 return newHandle;
2466 }
2467
Andrew Scull1416bd02018-01-05 18:33:58 +00002468 @GuardedBy("mSpManager")
Rubin Xu3bf722a2016-12-15 16:07:38 +00002469 private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002470 String savedCredential, int requestedQuality, int userId) throws RemoteException {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002471 if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2472 if (isManagedProfileWithUnifiedLock(userId)) {
2473 // get credential from keystore when managed profile has unified lock
2474 try {
2475 savedCredential = getDecryptedPasswordForTiedProfile(userId);
2476 } catch (FileNotFoundException e) {
2477 Slog.i(TAG, "Child profile key not found");
2478 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2479 | NoSuchAlgorithmException | NoSuchPaddingException
2480 | InvalidAlgorithmParameterException | IllegalBlockSizeException
2481 | BadPaddingException | CertificateException | IOException e) {
2482 Slog.e(TAG, "Failed to decrypt child profile key", e);
2483 }
2484 }
2485 long handle = getSyntheticPasswordHandleLocked(userId);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002486 AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
Rubin Xucf326f12017-11-15 11:55:35 +00002487 getGateKeeperService(), handle, savedCredential, userId, null);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002488 VerifyCredentialResponse response = authResult.gkResponse;
2489 AuthenticationToken auth = authResult.authToken;
Rubin Xu16c823e2017-06-27 14:44:58 +01002490
2491 // If existing credential is provided, then it must match.
2492 if (savedCredential != null && auth == null) {
2493 throw new RemoteException("Failed to enroll " +
2494 (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
2495 : "pattern"));
2496 }
2497
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002498 boolean untrustedReset = false;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002499 if (auth != null) {
Andrew Scull1416bd02018-01-05 18:33:58 +00002500 onAuthTokenKnownForUser(userId, auth);
Rubin Xu8b30ec32017-03-05 00:47:09 +00002501 } else if (response != null
Andrew Scull1416bd02018-01-05 18:33:58 +00002502 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002503 // We are performing an untrusted credential change, by DevicePolicyManager or other
2504 // internal callers that don't provide the existing credential
Rubin Xu3bf722a2016-12-15 16:07:38 +00002505 Slog.w(TAG, "Untrusted credential change invoked");
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002506 // Try to get a cached auth token, so we can keep SP unchanged.
2507 auth = mSpCache.get(userId);
2508 untrustedReset = true;
Rubin Xu8b30ec32017-03-05 00:47:09 +00002509 } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
2510 Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
2511 (response != null ? "rate limit exceeded" : "failed"));
2512 return;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002513 }
Rubin Xu9a6d39a52018-02-07 08:52:34 +00002514
2515 if (auth != null) {
2516 if (untrustedReset) {
2517 // Force change the current SID to mantain existing behaviour that an untrusted
2518 // reset leads to a change of SID. If the untrusted reset is for clearing the
2519 // current password, the nuking of the SID will be done in
2520 // setLockCredentialWithAuthTokenLocked next
2521 mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
2522 }
2523 setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
2524 userId);
2525 mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2526 } else {
2527 throw new IllegalStateException(
2528 "Untrusted credential reset not possible without cached SP");
2529 // Could call initializeSyntheticPasswordLocked(null, credential, credentialType,
2530 // requestedQuality, userId) instead if we still allow untrusted reset that changes
2531 // synthetic password. That would invalidate existing escrow tokens though.
2532 }
Dmitry Dementyev6e167242018-01-25 15:29:50 -08002533 mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002534 }
2535
Rubin Xuf01e9072018-03-30 20:59:28 +01002536 /**
2537 * Returns a fixed pseudorandom byte string derived from the user's synthetic password.
2538 * This is used to salt the password history hash to protect the hash against offline
2539 * bruteforcing, since rederiving this value requires a successful authentication.
Rubin Xu4ed98982018-05-23 14:27:53 +01002540 * If user is a managed profile with unified challenge, currentCredential is ignored.
Rubin Xuf01e9072018-03-30 20:59:28 +01002541 */
2542 @Override
2543 public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
2544 checkPasswordReadPermission(userId);
2545 if (TextUtils.isEmpty(currentCredential)) {
2546 currentCredential = null;
2547 }
Rubin Xu4ed98982018-05-23 14:27:53 +01002548 if (isManagedProfileWithUnifiedLock(userId)) {
2549 try {
2550 currentCredential = getDecryptedPasswordForTiedProfile(userId);
2551 } catch (Exception e) {
2552 Slog.e(TAG, "Failed to get work profile credential", e);
2553 return null;
2554 }
2555 }
Rubin Xuf01e9072018-03-30 20:59:28 +01002556 synchronized (mSpManager) {
2557 if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
2558 Slog.w(TAG, "Synthetic password not enabled");
2559 return null;
2560 }
2561 long handle = getSyntheticPasswordHandleLocked(userId);
2562 AuthenticationResult auth = mSpManager.unwrapPasswordBasedSyntheticPassword(
2563 getGateKeeperService(), handle, currentCredential, userId, null);
2564 if (auth.authToken == null) {
2565 Slog.w(TAG, "Current credential is incorrect");
2566 return null;
2567 }
2568 return auth.authToken.derivePasswordHashFactor();
2569 }
2570 }
2571
Rubin Xufcd49f92017-08-24 18:21:52 +01002572 private long addEscrowToken(byte[] token, int userId) throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002573 if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
2574 synchronized (mSpManager) {
2575 enableSyntheticPasswordLocked();
Rubin Xu8b30ec32017-03-05 00:47:09 +00002576 // Migrate to synthetic password based credentials if the user has no password,
Rubin Xuf095f832017-01-31 15:23:34 +00002577 // the token can then be activated immediately.
2578 AuthenticationToken auth = null;
2579 if (!isUserSecure(userId)) {
2580 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2581 auth = initializeSyntheticPasswordLocked(null, null,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002582 LockPatternUtils.CREDENTIAL_TYPE_NONE,
2583 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002584 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
2585 long pwdHandle = getSyntheticPasswordHandleLocked(userId);
2586 auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
Rubin Xucf326f12017-11-15 11:55:35 +00002587 pwdHandle, null, userId, null).authToken;
Rubin Xuf095f832017-01-31 15:23:34 +00002588 }
2589 }
Rubin Xu128180b2017-04-12 18:02:44 +01002590 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2591 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2592 if (!mSpManager.hasEscrowData(userId)) {
2593 throw new SecurityException("Escrow token is disabled on the current user");
2594 }
Rubin Xuf095f832017-01-31 15:23:34 +00002595 }
2596 long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
2597 if (auth != null) {
2598 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2599 }
2600 return handle;
2601 }
2602 }
2603
Rubin Xufcd49f92017-08-24 18:21:52 +01002604 private void activateEscrowTokens(AuthenticationToken auth, int userId) {
Rubin Xuf095f832017-01-31 15:23:34 +00002605 if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
2606 synchronized (mSpManager) {
Rubin Xue94a7702017-06-20 17:29:57 +01002607 disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002608 for (long handle : mSpManager.getPendingTokensForUser(userId)) {
2609 Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
2610 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2611 }
2612 }
2613 }
2614
Rubin Xufcd49f92017-08-24 18:21:52 +01002615 private boolean isEscrowTokenActive(long handle, int userId) {
Rubin Xuf095f832017-01-31 15:23:34 +00002616 synchronized (mSpManager) {
2617 return mSpManager.existsHandle(handle, userId);
2618 }
2619 }
2620
Rubin Xufcd49f92017-08-24 18:21:52 +01002621 private boolean removeEscrowToken(long handle, int userId) {
Rubin Xuf095f832017-01-31 15:23:34 +00002622 synchronized (mSpManager) {
2623 if (handle == getSyntheticPasswordHandleLocked(userId)) {
2624 Slog.w(TAG, "Cannot remove password handle");
2625 return false;
2626 }
2627 if (mSpManager.removePendingToken(handle, userId)) {
2628 return true;
2629 }
2630 if (mSpManager.existsHandle(handle, userId)) {
2631 mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
2632 return true;
2633 } else {
2634 return false;
2635 }
2636 }
2637 }
2638
Rubin Xufcd49f92017-08-24 18:21:52 +01002639 private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002640 byte[] token, int requestedQuality, int userId) throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002641 boolean result;
2642 synchronized (mSpManager) {
2643 if (!mSpManager.hasEscrowData(userId)) {
2644 throw new SecurityException("Escrow token is disabled on the current user");
2645 }
2646 result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002647 requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002648 }
2649 if (result) {
2650 synchronized (mSeparateChallengeLock) {
Pavel Grafov28939982017-10-03 15:11:52 +01002651 setSeparateProfileChallengeEnabledLocked(userId, true, null);
Rubin Xuf095f832017-01-31 15:23:34 +00002652 }
2653 notifyPasswordChanged(userId);
Pavel Grafov28939982017-10-03 15:11:52 +01002654 notifySeparateProfileChallengeChanged(userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002655 }
2656 return result;
2657 }
2658
2659 private boolean setLockCredentialWithTokenInternal(String credential, int type,
Adrian Roos7374d3a2017-03-31 14:14:53 -07002660 long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
Andrew Scull1416bd02018-01-05 18:33:58 +00002661 final AuthenticationResult result;
Rubin Xuf095f832017-01-31 15:23:34 +00002662 synchronized (mSpManager) {
Andrew Scull1416bd02018-01-05 18:33:58 +00002663 result = mSpManager.unwrapTokenBasedSyntheticPassword(
Rubin Xuf095f832017-01-31 15:23:34 +00002664 getGateKeeperService(), tokenHandle, token, userId);
2665 if (result.authToken == null) {
2666 Slog.w(TAG, "Invalid escrow token supplied");
2667 return false;
2668 }
Rubin Xu24570e42017-09-19 15:27:21 +01002669 if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
2670 // Most likely, an untrusted credential reset happened in the past which
2671 // changed the synthetic password
2672 Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
2673 + "verification.");
2674 return false;
2675 }
Rubin Xu7cf45092017-08-28 11:47:35 +01002676 // Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable()
2677 // called by setLockCredentialWithAuthTokenLocked().
2678 // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
2679 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002680 long oldHandle = getSyntheticPasswordHandleLocked(userId);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002681 setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
2682 requestedQuality, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002683 mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00002684 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002685 onAuthTokenKnownForUser(userId, result.authToken);
2686 return true;
Rubin Xuf095f832017-01-31 15:23:34 +00002687 }
2688
Rubin Xufcd49f92017-08-24 18:21:52 +01002689 private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
Rubin Xuf095f832017-01-31 15:23:34 +00002690 throws RemoteException {
Rubin Xuf095f832017-01-31 15:23:34 +00002691 AuthenticationResult authResult;
2692 synchronized (mSpManager) {
2693 if (!mSpManager.hasEscrowData(userId)) {
2694 throw new SecurityException("Escrow token is disabled on the current user");
2695 }
2696 authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
2697 tokenHandle, token, userId);
2698 if (authResult.authToken == null) {
2699 Slog.w(TAG, "Invalid escrow token supplied");
Rubin Xufcd49f92017-08-24 18:21:52 +01002700 return false;
Rubin Xuf095f832017-01-31 15:23:34 +00002701 }
2702 }
2703 unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
Andrew Scull1416bd02018-01-05 18:33:58 +00002704 onAuthTokenKnownForUser(userId, authResult.authToken);
Rubin Xufcd49f92017-08-24 18:21:52 +01002705 return true;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002706 }
2707
2708 @Override
2709 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06002710 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Rubin Xu3bf722a2016-12-15 16:07:38 +00002711
Rubin Xua0a0d352017-05-15 16:18:01 +00002712 pw.println("Current lock settings service state:");
2713 pw.println(String.format("SP Enabled = %b",
2714 mLockPatternUtils.isSyntheticPasswordEnabled()));
Rubin Xu3bf722a2016-12-15 16:07:38 +00002715
Rubin Xua0a0d352017-05-15 16:18:01 +00002716 List<UserInfo> users = mUserManager.getUsers();
2717 for (int user = 0; user < users.size(); user++) {
2718 final int userId = users.get(user).id;
2719 pw.println(" User " + userId);
2720 synchronized (mSpManager) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002721 pw.println(String.format(" SP Handle = %x",
2722 getSyntheticPasswordHandleLocked(userId)));
Rubin Xua0a0d352017-05-15 16:18:01 +00002723 }
2724 try {
2725 pw.println(String.format(" SID = %x",
2726 getGateKeeperService().getSecureUserId(userId)));
2727 } catch (RemoteException e) {
2728 // ignore.
Rubin Xu3bf722a2016-12-15 16:07:38 +00002729 }
2730 }
2731 }
2732
Rubin Xuf095f832017-01-31 15:23:34 +00002733 private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
2734 long ident = Binder.clearCallingIdentity();
2735 try {
2736 // Managed profile should have escrow enabled
2737 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002738 Slog.i(TAG, "Managed profile can have escrow token");
Rubin Xuf095f832017-01-31 15:23:34 +00002739 return;
2740 }
Rubin Xuf34d2f62017-03-20 12:36:35 +00002741 DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
Rubin Xuf095f832017-01-31 15:23:34 +00002742 // Devices with Device Owner should have escrow enabled on all users.
Rubin Xuf34d2f62017-03-20 12:36:35 +00002743 if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002744 Slog.i(TAG, "Corp-owned device can have escrow token");
2745 return;
2746 }
2747 // We could also have a profile owner on the given (non-managed) user for unicorn cases
Rubin Xuf34d2f62017-03-20 12:36:35 +00002748 if (dpm.getProfileOwnerAsUser(userId) != null) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002749 Slog.i(TAG, "User with profile owner can have escrow token");
Rubin Xuf095f832017-01-31 15:23:34 +00002750 return;
2751 }
2752 // If the device is yet to be provisioned (still in SUW), there is still
2753 // a chance that Device Owner will be set on the device later, so postpone
2754 // disabling escrow token for now.
Rubin Xuf34d2f62017-03-20 12:36:35 +00002755 if (!dpm.isDeviceProvisioned()) {
Rubin Xubc7a47c2017-02-22 20:31:57 +00002756 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
Rubin Xuf095f832017-01-31 15:23:34 +00002757 return;
2758 }
Rakesh Iyercb18d562017-03-06 18:05:53 -08002759
2760 // Escrow tokens are enabled on automotive builds.
2761 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
2762 return;
2763 }
2764
Rubin Xuf095f832017-01-31 15:23:34 +00002765 // Disable escrow token permanently on all other device/user types.
2766 Slog.i(TAG, "Disabling escrow token on user " + userId);
2767 if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2768 mSpManager.destroyEscrowData(userId);
2769 }
Rubin Xuf095f832017-01-31 15:23:34 +00002770 } finally {
2771 Binder.restoreCallingIdentity(ident);
2772 }
2773 }
2774
Adrian Roos7374d3a2017-03-31 14:14:53 -07002775 private class DeviceProvisionedObserver extends ContentObserver {
2776 private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
2777 Settings.Global.DEVICE_PROVISIONED);
Andrew Scull1416bd02018-01-05 18:33:58 +00002778 private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor(
2779 Settings.Secure.USER_SETUP_COMPLETE);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002780
2781 private boolean mRegistered;
2782
2783 public DeviceProvisionedObserver() {
2784 super(null);
2785 }
2786
2787 @Override
Andrew Scullede482d2018-01-30 13:54:29 +00002788 public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002789 if (mDeviceProvisionedUri.equals(uri)) {
2790 updateRegistration();
2791
2792 if (isProvisioned()) {
2793 Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
2794 reportDeviceSetupComplete();
Adrian Roos454f53f2017-08-08 14:56:42 +02002795 clearFrpCredentialIfOwnerNotSecure();
Adrian Roos7374d3a2017-03-31 14:14:53 -07002796 }
Andrew Scull1416bd02018-01-05 18:33:58 +00002797 } else if (mUserSetupCompleteUri.equals(uri)) {
Andrew Scullede482d2018-01-30 13:54:29 +00002798 tryRemoveUserFromSpCacheLater(userId);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002799 }
2800 }
2801
2802 public void onSystemReady() {
Adrian Roos2adc2632017-09-05 17:01:42 +02002803 if (frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -07002804 updateRegistration();
2805 } else {
2806 // If we don't intend to use frpCredentials and we're not provisioned yet, send
2807 // deviceSetupComplete immediately, so gatekeeper can discard any lingering
2808 // credentials immediately.
2809 if (!isProvisioned()) {
2810 Slog.i(TAG, "FRP credential disabled, reporting device setup complete "
2811 + "to Gatekeeper immediately");
2812 reportDeviceSetupComplete();
2813 }
2814 }
2815 }
2816
2817 private void reportDeviceSetupComplete() {
2818 try {
2819 getGateKeeperService().reportDeviceSetupComplete();
2820 } catch (RemoteException e) {
2821 Slog.e(TAG, "Failure reporting to IGateKeeperService", e);
2822 }
2823 }
2824
Adrian Roos454f53f2017-08-08 14:56:42 +02002825 /**
2826 * Clears the FRP credential if the user that controls it does not have a secure
2827 * lockscreen.
2828 */
2829 private void clearFrpCredentialIfOwnerNotSecure() {
2830 List<UserInfo> users = mUserManager.getUsers();
2831 for (UserInfo user : users) {
Adrian Roos2adc2632017-09-05 17:01:42 +02002832 if (userOwnsFrpCredential(mContext, user)) {
Adrian Roos454f53f2017-08-08 14:56:42 +02002833 if (!isUserSecure(user.id)) {
2834 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
2835 0, null);
2836 }
2837 return;
2838 }
2839 }
2840 }
2841
Adrian Roos7374d3a2017-03-31 14:14:53 -07002842 private void updateRegistration() {
2843 boolean register = !isProvisioned();
2844 if (register == mRegistered) {
2845 return;
2846 }
2847 if (register) {
2848 mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri,
2849 false, this);
Andrew Scull1416bd02018-01-05 18:33:58 +00002850 mContext.getContentResolver().registerContentObserver(mUserSetupCompleteUri,
2851 false, this, UserHandle.USER_ALL);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002852 } else {
2853 mContext.getContentResolver().unregisterContentObserver(this);
2854 }
2855 mRegistered = register;
2856 }
2857
2858 private boolean isProvisioned() {
2859 return Settings.Global.getInt(mContext.getContentResolver(),
2860 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
2861 }
2862 }
Rubin Xufcd49f92017-08-24 18:21:52 +01002863
2864 private final class LocalService extends LockSettingsInternal {
2865
2866 @Override
2867 public long addEscrowToken(byte[] token, int userId) {
2868 try {
2869 return LockSettingsService.this.addEscrowToken(token, userId);
2870 } catch (RemoteException re) {
2871 throw re.rethrowFromSystemServer();
2872 }
2873 }
2874
2875 @Override
2876 public boolean removeEscrowToken(long handle, int userId) {
2877 return LockSettingsService.this.removeEscrowToken(handle, userId);
2878 }
2879
2880 @Override
2881 public boolean isEscrowTokenActive(long handle, int userId) {
2882 return LockSettingsService.this.isEscrowTokenActive(handle, userId);
2883 }
2884
2885 @Override
2886 public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
2887 byte[] token, int requestedQuality, int userId) {
2888 try {
2889 return LockSettingsService.this.setLockCredentialWithToken(credential, type,
2890 tokenHandle, token, requestedQuality, userId);
2891 } catch (RemoteException re) {
2892 throw re.rethrowFromSystemServer();
2893 }
2894 }
2895
2896 @Override
2897 public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
2898 try {
2899 return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
2900 } catch (RemoteException re) {
2901 throw re.rethrowFromSystemServer();
2902 }
2903 }
2904 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07002905}