blob: 13985304bd877edaf9c3ea553d1336aded103ef8 [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
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server;
Amith Yamasani52c489c2012-03-28 11:42:42 -070018
Sudheer Shankadc589ac2016-11-10 15:30:17 -080019import android.app.ActivityManager;
Kenny Guyb1b30262016-02-09 16:02:35 +000020import android.app.KeyguardManager;
Jim Miller4f93c582016-01-27 19:05:43 -080021import android.app.Notification;
22import android.app.NotificationManager;
23import android.app.PendingIntent;
Adrian Roos230635e2015-01-07 20:50:29 +010024import android.app.admin.DevicePolicyManager;
Amith Yamasani072543f2015-02-13 11:09:45 -080025import android.app.backup.BackupManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070026import android.app.trust.IStrongAuthTracker;
Clara Bayarri56878a92015-10-29 15:43:55 +000027import android.app.trust.TrustManager;
Robin Leef0246a82014-08-13 09:50:25 +010028import android.content.BroadcastReceiver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070029import android.content.ContentResolver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070030import android.content.Context;
Robin Leef0246a82014-08-13 09:50:25 +010031import android.content.Intent;
32import android.content.IntentFilter;
Jim Miller158fe192013-04-17 15:23:55 -070033import android.content.pm.PackageManager;
Jim Miller187ec582013-04-15 18:27:54 -070034import android.content.pm.UserInfo;
Jim Miller4f93c582016-01-27 19:05:43 -080035import android.content.res.Resources;
36
Adrian Roos261d5ab2014-10-29 14:42:38 +010037import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
Kenny Guyb1b30262016-02-09 16:02:35 +000038import static android.content.Context.KEYGUARD_SERVICE;
Jim Miller187ec582013-04-15 18:27:54 -070039import static android.content.Context.USER_SERVICE;
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +000040import static android.Manifest.permission.READ_CONTACTS;
Adrian Roos873010d2015-08-25 15:59:00 -070041import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
42
Amith Yamasani52c489c2012-03-28 11:42:42 -070043import android.database.sqlite.SQLiteDatabase;
Amith Yamasani52c489c2012-03-28 11:42:42 -070044import android.os.Binder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060045import android.os.Bundle;
Ricky Waib0cdf382016-05-16 17:28:04 +010046import android.os.Handler;
Paul Lawrence945490c2014-03-27 16:37:28 +000047import android.os.IBinder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060048import android.os.IProgressListener;
49import android.os.Parcel;
Ricky Wai4613fe42016-05-24 11:11:42 +010050import android.os.Process;
Amith Yamasani52c489c2012-03-28 11:42:42 -070051import android.os.RemoteException;
Jorim Jaggi2fef6f72016-11-01 19:06:25 -070052import android.os.ResultReceiver;
53import android.os.ShellCallback;
Sudheer Shanka2250d562016-11-07 15:41:02 -080054import android.os.storage.IStorageManager;
Jeff Sharkey4a399362016-05-26 09:47:43 -060055import android.os.storage.StorageManager;
Paul Lawrence945490c2014-03-27 16:37:28 +000056import android.os.ServiceManager;
Jeff Sharkeyeddf5182016-08-09 16:36:08 -060057import android.os.StrictMode;
Amith Yamasanid1645f82012-06-12 11:53:26 -070058import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070059import android.os.UserHandle;
Jim Miller187ec582013-04-15 18:27:54 -070060import android.os.UserManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -070061import android.provider.Settings;
62import android.provider.Settings.Secure;
Jim Miller187ec582013-04-15 18:27:54 -070063import android.provider.Settings.SettingNotFoundException;
Jim Millerde1af082013-09-11 14:58:26 -070064import android.security.KeyStore;
Ricky Waidc283a82016-03-24 19:55:08 +000065import android.security.keystore.AndroidKeyStoreProvider;
66import android.security.keystore.KeyProperties;
67import android.security.keystore.KeyProtection;
Andres Morales23974272015-05-14 22:42:26 -070068import android.service.gatekeeper.GateKeeperResponse;
Andres Morales8fa56652015-03-31 09:19:50 -070069import android.service.gatekeeper.IGateKeeperService;
Amith Yamasani52c489c2012-03-28 11:42:42 -070070import android.text.TextUtils;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060071import android.util.Log;
Amith Yamasani52c489c2012-03-28 11:42:42 -070072import android.util.Slog;
73
Amith Yamasani072543f2015-02-13 11:09:45 -080074import com.android.internal.util.ArrayUtils;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070075import com.android.internal.widget.ICheckCredentialProgressCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080076import com.android.internal.widget.ILockSettings;
77import com.android.internal.widget.LockPatternUtils;
Andres Morales23974272015-05-14 22:42:26 -070078import com.android.internal.widget.VerifyCredentialResponse;
Andres Morales8fa56652015-03-31 09:19:50 -070079import com.android.server.LockSettingsStorage.CredentialHash;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080080
Ricky Waidc283a82016-03-24 19:55:08 +000081import libcore.util.HexEncoding;
82
83import java.io.ByteArrayOutputStream;
Jorim Jaggi2fef6f72016-11-01 19:06:25 -070084import java.io.FileDescriptor;
Ricky Waidc283a82016-03-24 19:55:08 +000085import java.io.FileNotFoundException;
86import java.io.IOException;
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +000087import java.nio.charset.StandardCharsets;
Ricky Waidc283a82016-03-24 19:55:08 +000088import java.security.InvalidAlgorithmParameterException;
89import java.security.InvalidKeyException;
90import java.security.KeyStoreException;
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +000091import java.security.MessageDigest;
92import java.security.NoSuchAlgorithmException;
Ricky Waidc283a82016-03-24 19:55:08 +000093import java.security.SecureRandom;
94import java.security.UnrecoverableKeyException;
95import java.security.cert.CertificateException;
Amith Yamasani52c489c2012-03-28 11:42:42 -070096import java.util.Arrays;
Jim Miller187ec582013-04-15 18:27:54 -070097import java.util.List;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060098import java.util.concurrent.CountDownLatch;
99import java.util.concurrent.TimeUnit;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700100
Ricky Waidc283a82016-03-24 19:55:08 +0000101import javax.crypto.BadPaddingException;
102import javax.crypto.Cipher;
103import javax.crypto.IllegalBlockSizeException;
104import javax.crypto.KeyGenerator;
105import javax.crypto.NoSuchPaddingException;
106import javax.crypto.SecretKey;
107import javax.crypto.spec.GCMParameterSpec;
108
Amith Yamasani52c489c2012-03-28 11:42:42 -0700109/**
110 * Keeps the lock pattern/password data and related settings for each user.
111 * Used by LockPatternUtils. Needs to be a service because Settings app also needs
112 * to be able to save lockscreen information for secondary users.
113 * @hide
114 */
115public class LockSettingsService extends ILockSettings.Stub {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700116 private static final String TAG = "LockSettingsService";
Jim Miller4f93c582016-01-27 19:05:43 -0800117 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
118 private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
119 private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
120 private static final boolean DEBUG = false;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700121
Ricky Waidc283a82016-03-24 19:55:08 +0000122 private static final int PROFILE_KEY_IV_SIZE = 12;
123 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
124 private final Object mSeparateChallengeLock = new Object();
125
Amith Yamasani52c489c2012-03-28 11:42:42 -0700126 private final Context mContext;
Ricky Waib0cdf382016-05-16 17:28:04 +0100127 private final Handler mHandler;
Adrian Roos261d5ab2014-10-29 14:42:38 +0100128 private final LockSettingsStorage mStorage;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -0800129 private final LockSettingsStrongAuth mStrongAuth;
Victor Changa0940d32016-05-16 19:36:08 +0100130 private final SynchronizedStrongAuthTracker mStrongAuthTracker;
Adrian Roos261d5ab2014-10-29 14:42:38 +0100131
Jim Millerde1af082013-09-11 14:58:26 -0700132 private LockPatternUtils mLockPatternUtils;
Paul Lawrence945490c2014-03-27 16:37:28 +0000133 private boolean mFirstCallToVold;
Andres Morales8fa56652015-03-31 09:19:50 -0700134 private IGateKeeperService mGateKeeperService;
Jim Miller4f93c582016-01-27 19:05:43 -0800135 private NotificationManager mNotificationManager;
136 private UserManager mUserManager;
137
Ricky Wai4613fe42016-05-24 11:11:42 +0100138 private final KeyStore mKeyStore = KeyStore.getInstance();
139
140 /**
141 * The UIDs that are used for system credential storage in keystore.
142 */
143 private static final int[] SYSTEM_CREDENTIAL_UIDS = {Process.WIFI_UID, Process.VPN_UID,
144 Process.ROOT_UID, Process.SYSTEM_UID};
145
Jim Miller4f93c582016-01-27 19:05:43 -0800146 static {
147 // Just launch the home screen, which happens anyway
148 ACTION_NULL = new Intent(Intent.ACTION_MAIN);
149 ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
150 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700151
Andres Morales23974272015-05-14 22:42:26 -0700152 private interface CredentialUtil {
153 void setCredential(String credential, String savedCredential, int userId)
154 throws RemoteException;
155 byte[] toHash(String credential, int userId);
Andres Morales59ef1262015-06-26 13:56:39 -0700156 String adjustForKeystore(String credential);
Andres Morales23974272015-05-14 22:42:26 -0700157 }
158
Jim Miller4f93c582016-01-27 19:05:43 -0800159 // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
160 // devices. The most basic of these is to show/hide notifications about missing features until
161 // the user unlocks the account and credential-encrypted storage is available.
162 public static final class Lifecycle extends SystemService {
163 private LockSettingsService mLockSettingsService;
164
165 public Lifecycle(Context context) {
166 super(context);
167 }
168
169 @Override
170 public void onStart() {
Ricky Waidc283a82016-03-24 19:55:08 +0000171 AndroidKeyStoreProvider.install();
Jim Miller4f93c582016-01-27 19:05:43 -0800172 mLockSettingsService = new LockSettingsService(getContext());
173 publishBinderService("lock_settings", mLockSettingsService);
174 }
175
176 @Override
177 public void onBootPhase(int phase) {
178 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000179 mLockSettingsService.maybeShowEncryptionNotifications();
Jim Miller4f93c582016-01-27 19:05:43 -0800180 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
181 // TODO
182 }
183 }
184
185 @Override
186 public void onUnlockUser(int userHandle) {
187 mLockSettingsService.onUnlockUser(userHandle);
188 }
189
190 @Override
191 public void onCleanupUser(int userHandle) {
192 mLockSettingsService.onCleanupUser(userHandle);
193 }
194 }
195
Victor Changa0940d32016-05-16 19:36:08 +0100196 private class SynchronizedStrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
197 public SynchronizedStrongAuthTracker(Context context) {
198 super(context);
199 }
200
201 @Override
202 protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
203 synchronized (this) {
204 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
205 }
206 }
207
208 @Override
209 public int getStrongAuthForUser(int userId) {
210 synchronized (this) {
211 return super.getStrongAuthForUser(userId);
212 }
213 }
214
215 void register() {
216 mStrongAuth.registerStrongAuthTracker(this.mStub);
217 }
218 }
219
Ricky Waidc283a82016-03-24 19:55:08 +0000220 /**
221 * Tie managed profile to primary profile if it is in unified mode and not tied before.
222 *
223 * @param managedUserId Managed profile user Id
224 * @param managedUserPassword Managed profile original password (when it has separated lock).
225 * NULL when it does not have a separated lock before.
226 */
227 public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
228 if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
229 // Only for managed profile
230 if (!UserManager.get(mContext).getUserInfo(managedUserId).isManagedProfile()) {
231 return;
232 }
233 // Do not tie managed profile when work challenge is enabled
234 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
235 return;
236 }
237 // Do not tie managed profile to parent when it's done already
238 if (mStorage.hasChildProfileLock(managedUserId)) {
239 return;
240 }
241 // Do not tie it to parent when parent does not have a screen lock
242 final int parentId = mUserManager.getProfileParent(managedUserId).id;
243 if (!mStorage.hasPassword(parentId) && !mStorage.hasPattern(parentId)) {
244 if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
245 return;
246 }
Rubin Xubfc7faaf2016-11-22 15:18:32 +0000247 // Do not tie when the parent has no SID (but does have a screen lock).
248 // This can only happen during an upgrade path where SID is yet to be
249 // generated when the user unlocks for the first time.
250 try {
251 if (getGateKeeperService().getSecureUserId(parentId) == 0) {
252 return;
253 }
254 } catch (RemoteException e) {
255 Slog.e(TAG, "Failed to talk to GateKeeper service", e);
256 return;
257 }
Ricky Waidc283a82016-03-24 19:55:08 +0000258 if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
259 byte[] randomLockSeed = new byte[] {};
260 try {
261 randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
262 String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
263 setLockPasswordInternal(newPassword, managedUserPassword, managedUserId);
Ricky Wai7b9eb412016-05-12 17:29:12 +0100264 // We store a private credential for the managed user that's unlocked by the primary
265 // account holder's credential. As such, the user will never be prompted to enter this
266 // password directly, so we always store a password.
267 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
268 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId);
Zach Jange61672a2016-11-22 17:47:18 +0000269 tieProfileLockToParent(managedUserId, newPassword);
Ricky Waidc283a82016-03-24 19:55:08 +0000270 } catch (NoSuchAlgorithmException | RemoteException e) {
271 Slog.e(TAG, "Fail to tie managed profile", e);
272 // Nothing client can do to fix this issue, so we do not throw exception out
273 }
274 }
275
Amith Yamasani52c489c2012-03-28 11:42:42 -0700276 public LockSettingsService(Context context) {
277 mContext = context;
Ricky Waib0cdf382016-05-16 17:28:04 +0100278 mHandler = new Handler();
Rakesh Iyera7aa4d62016-01-19 17:27:23 -0800279 mStrongAuth = new LockSettingsStrongAuth(context);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700280 // Open the database
Jim Millerde1af082013-09-11 14:58:26 -0700281
282 mLockPatternUtils = new LockPatternUtils(context);
Paul Lawrence945490c2014-03-27 16:37:28 +0000283 mFirstCallToVold = true;
Robin Leef0246a82014-08-13 09:50:25 +0100284
285 IntentFilter filter = new IntentFilter();
286 filter.addAction(Intent.ACTION_USER_ADDED);
Adrian Roos3dcae682014-10-29 14:43:56 +0100287 filter.addAction(Intent.ACTION_USER_STARTING);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100288 filter.addAction(Intent.ACTION_USER_REMOVED);
Robin Leef0246a82014-08-13 09:50:25 +0100289 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100290
291 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
292 @Override
293 public void initialize(SQLiteDatabase db) {
294 // Get the lockscreen default from a system property, if available
295 boolean lockScreenDisable = SystemProperties.getBoolean(
296 "ro.lockscreen.disable.default", false);
297 if (lockScreenDisable) {
298 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
299 }
300 }
301 });
Jim Miller4f93c582016-01-27 19:05:43 -0800302 mNotificationManager = (NotificationManager)
303 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
304 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Victor Changa0940d32016-05-16 19:36:08 +0100305 mStrongAuthTracker = new SynchronizedStrongAuthTracker(mContext);
306 mStrongAuthTracker.register();
307
Jim Miller4f93c582016-01-27 19:05:43 -0800308 }
309
310 /**
311 * If the account is credential-encrypted, show notification requesting the user to unlock
312 * the device.
313 */
Kenny Guyb1b30262016-02-09 16:02:35 +0000314 private void maybeShowEncryptionNotifications() {
315 final List<UserInfo> users = mUserManager.getUsers();
316 for (int i = 0; i < users.size(); i++) {
317 UserInfo user = users.get(i);
318 UserHandle userHandle = user.getUserHandle();
Ricky Waia8e3f772016-06-27 15:51:52 +0100319 final boolean isSecure = mStorage.hasPassword(user.id) || mStorage.hasPattern(user.id);
320 if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000321 if (!user.isManagedProfile()) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600322 // When the user is locked, we communicate it loud-and-clear
323 // on the lockscreen; we only show a notification below for
324 // locked managed profiles.
Kenny Guyb1b30262016-02-09 16:02:35 +0000325 } else {
326 UserInfo parent = mUserManager.getProfileParent(user.id);
Benjamin Franzf52709c2016-04-01 15:49:13 +0100327 if (parent != null &&
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600328 mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
Benjamin Franzf52709c2016-04-01 15:49:13 +0100329 !mUserManager.isQuietModeEnabled(userHandle)) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000330 // Only show notifications for managed profiles once their parent
331 // user is unlocked.
332 showEncryptionNotificationForProfile(userHandle);
333 }
Jim Miller4f93c582016-01-27 19:05:43 -0800334 }
335 }
Jim Miller4f93c582016-01-27 19:05:43 -0800336 }
337 }
338
Kenny Guyb1b30262016-02-09 16:02:35 +0000339 private void showEncryptionNotificationForProfile(UserHandle user) {
340 Resources r = mContext.getResources();
341 CharSequence title = r.getText(
342 com.android.internal.R.string.user_encrypted_title);
343 CharSequence message = r.getText(
344 com.android.internal.R.string.profile_encrypted_message);
345 CharSequence detail = r.getText(
346 com.android.internal.R.string.profile_encrypted_detail);
347
348 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
349 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
350 if (unlockIntent == null) {
351 return;
352 }
353 unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
354 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
355 PendingIntent.FLAG_UPDATE_CURRENT);
356
357 showEncryptionNotification(user, title, message, detail, intent);
358 }
359
Kenny Guyb1b30262016-02-09 16:02:35 +0000360 private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
361 CharSequence detail, PendingIntent intent) {
362 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Jeff Sharkey4a399362016-05-26 09:47:43 -0600363
364 // Suppress all notifications on non-FBE devices for now
365 if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
366
Jim Miller4f93c582016-01-27 19:05:43 -0800367 Notification notification = new Notification.Builder(mContext)
Jim Millerb1135b72016-02-02 17:08:56 -0800368 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
Jim Miller4f93c582016-01-27 19:05:43 -0800369 .setWhen(0)
370 .setOngoing(true)
371 .setTicker(title)
372 .setDefaults(0) // please be quiet
373 .setPriority(Notification.PRIORITY_MAX)
374 .setColor(mContext.getColor(
375 com.android.internal.R.color.system_notification_accent_color))
376 .setContentTitle(title)
377 .setContentText(message)
Selim Cinek0f9dd1e2016-04-05 17:03:40 -0700378 .setSubText(detail)
Jim Miller4f93c582016-01-27 19:05:43 -0800379 .setVisibility(Notification.VISIBILITY_PUBLIC)
380 .setContentIntent(intent)
381 .build();
382 mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
383 }
384
385 public void hideEncryptionNotification(UserHandle userHandle) {
386 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
387 mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
388 }
389
390 public void onCleanupUser(int userId) {
391 hideEncryptionNotification(new UserHandle(userId));
392 }
393
Ricky Waib0cdf382016-05-16 17:28:04 +0100394 public void onUnlockUser(final int userId) {
Ricky Wai84812582016-05-10 20:11:59 +0100395 // Hide notification first, as tie managed profile lock takes time
Kenny Guyb1b30262016-02-09 16:02:35 +0000396 hideEncryptionNotification(new UserHandle(userId));
Ricky Waib0cdf382016-05-16 17:28:04 +0100397
398 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
399 // As tieManagedProfileLockIfNecessary() may try to unlock user, we should not do it
400 // in onUnlockUser() synchronously, otherwise it may cause a deadlock
401 mHandler.post(new Runnable() {
402 @Override
403 public void run() {
404 tieManagedProfileLockIfNecessary(userId, null);
405 }
406 });
407 }
Kenny Guyb1b30262016-02-09 16:02:35 +0000408
409 // Now we have unlocked the parent user we should show notifications
410 // about any profiles that exist.
411 List<UserInfo> profiles = mUserManager.getProfiles(userId);
412 for (int i = 0; i < profiles.size(); i++) {
413 UserInfo profile = profiles.get(i);
Ricky Waia8e3f772016-06-27 15:51:52 +0100414 final boolean isSecure =
415 mStorage.hasPassword(profile.id) || mStorage.hasPattern(profile.id);
416 if (isSecure && profile.isManagedProfile()) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000417 UserHandle userHandle = profile.getUserHandle();
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600418 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
Benjamin Franzf52709c2016-04-01 15:49:13 +0100419 !mUserManager.isQuietModeEnabled(userHandle)) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000420 showEncryptionNotificationForProfile(userHandle);
421 }
422 }
423 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700424 }
425
Robin Leef0246a82014-08-13 09:50:25 +0100426 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
427 @Override
428 public void onReceive(Context context, Intent intent) {
Robin Lee1096cf82014-09-01 16:52:47 +0100429 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
Chad Brubaker83ce0952015-05-12 13:00:02 -0700430 // Notify keystore that a new user was added.
Robin Leef0246a82014-08-13 09:50:25 +0100431 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Amith Yamasanif11a5742016-06-16 08:20:07 -0700432 if (userHandle > UserHandle.USER_SYSTEM) {
433 removeUser(userHandle, /* unknownUser= */ true);
434 }
Robin Lee49d810c2014-09-23 13:50:22 +0100435 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +0000436 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
Chad Brubaker83ce0952015-05-12 13:00:02 -0700437 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
438 ks.onUserAdded(userHandle, parentHandle);
Adrian Roos3dcae682014-10-29 14:43:56 +0100439 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
440 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
441 mStorage.prefetchUser(userHandle);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100442 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
443 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
444 if (userHandle > 0) {
Amith Yamasanif11a5742016-06-16 08:20:07 -0700445 removeUser(userHandle, /* unknownUser= */ false);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100446 }
Robin Leef0246a82014-08-13 09:50:25 +0100447 }
448 }
449 };
450
Jim Miller4f93c582016-01-27 19:05:43 -0800451 @Override // binder interface
Amith Yamasani52c489c2012-03-28 11:42:42 -0700452 public void systemReady() {
453 migrateOldData();
Andres Morales301ea442015-04-17 09:15:47 -0700454 try {
455 getGateKeeperService();
456 } catch (RemoteException e) {
457 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
458 }
Xiaohui Chen7c696362015-09-16 09:56:14 -0700459 // TODO: maybe skip this for split system user mode.
460 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700461 }
462
463 private void migrateOldData() {
464 try {
Jim Miller187ec582013-04-15 18:27:54 -0700465 // These Settings moved before multi-user was enabled, so we only have to do it for the
466 // root user.
467 if (getString("migrated", null, 0) == null) {
468 final ContentResolver cr = mContext.getContentResolver();
469 for (String validSetting : VALID_SETTINGS) {
470 String value = Settings.Secure.getString(cr, validSetting);
471 if (value != null) {
472 setString(validSetting, value, 0);
473 }
474 }
475 // No need to move the password / pattern files. They're already in the right place.
476 setString("migrated", "true", 0);
477 Slog.i(TAG, "Migrated lock settings to new location");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700478 }
479
Jim Miller187ec582013-04-15 18:27:54 -0700480 // These Settings changed after multi-user was enabled, hence need to be moved per user.
481 if (getString("migrated_user_specific", null, 0) == null) {
Jim Miller187ec582013-04-15 18:27:54 -0700482 final ContentResolver cr = mContext.getContentResolver();
Ricky Waidc283a82016-03-24 19:55:08 +0000483 List<UserInfo> users = mUserManager.getUsers();
Jim Miller187ec582013-04-15 18:27:54 -0700484 for (int user = 0; user < users.size(); user++) {
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700485 // Migrate owner info
486 final int userId = users.get(user).id;
487 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
488 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
Jim Miller325c5672016-03-01 19:21:47 -0800489 if (!TextUtils.isEmpty(ownerInfo)) {
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700490 setString(OWNER_INFO, ownerInfo, userId);
Jim Miller325c5672016-03-01 19:21:47 -0800491 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700492 }
Jim Miller187ec582013-04-15 18:27:54 -0700493
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700494 // Migrate owner info enabled. Note there was a bug where older platforms only
495 // stored this value if the checkbox was toggled at least once. The code detects
496 // this case by handling the exception.
497 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
498 boolean enabled;
499 try {
500 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
501 enabled = ivalue != 0;
502 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
503 } catch (SettingNotFoundException e) {
504 // Setting was never stored. Store it if the string is not empty.
505 if (!TextUtils.isEmpty(ownerInfo)) {
506 setLong(OWNER_INFO_ENABLED, 1, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700507 }
508 }
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700509 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700510 }
Jim Miller187ec582013-04-15 18:27:54 -0700511 // No need to move the password / pattern files. They're already in the right place.
512 setString("migrated_user_specific", "true", 0);
513 Slog.i(TAG, "Migrated per-user lock settings to new location");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700514 }
Adrian Roos230635e2015-01-07 20:50:29 +0100515
516 // Migrates biometric weak such that the fallback mechanism becomes the primary.
517 if (getString("migrated_biometric_weak", null, 0) == null) {
Ricky Waidc283a82016-03-24 19:55:08 +0000518 List<UserInfo> users = mUserManager.getUsers();
Adrian Roos230635e2015-01-07 20:50:29 +0100519 for (int i = 0; i < users.size(); i++) {
520 int userId = users.get(i).id;
521 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
522 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
523 userId);
524 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
525 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
526 userId);
527 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
528 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
529 alternateType,
530 userId);
531 }
532 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
533 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
534 userId);
535 }
536 setString("migrated_biometric_weak", "true", 0);
537 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
538 }
Adrian Roos43830582015-04-21 16:04:43 -0700539
540 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
541 // user was present on the system, so if we're upgrading to M and there is more than one
542 // user we disable the flag to remain consistent.
543 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
Ricky Waidc283a82016-03-24 19:55:08 +0000544 final List<UserInfo> users = mUserManager.getUsers();
Adrian Roos43830582015-04-21 16:04:43 -0700545 final int userCount = users.size();
546 int switchableUsers = 0;
547 for (int i = 0; i < userCount; i++) {
548 if (users.get(i).supportsSwitchTo()) {
549 switchableUsers++;
550 }
551 }
552
553 if (switchableUsers > 1) {
554 for (int i = 0; i < userCount; i++) {
555 int id = users.get(i).id;
556
557 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
558 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
559 }
560 }
561 }
562
563 setString("migrated_lockscreen_disabled", "true", 0);
564 Slog.i(TAG, "Migrated lockscreen disabled flag");
565 }
Ricky Wai7b9eb412016-05-12 17:29:12 +0100566
567 final List<UserInfo> users = mUserManager.getUsers();
568 for (int i = 0; i < users.size(); i++) {
569 final UserInfo userInfo = users.get(i);
570 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
571 // When managed profile has a unified lock, the password quality stored has 2
572 // possibilities only.
573 // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
574 // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
575 // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
576 // unified lock.
577 final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
578 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
579 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
580 // Only possible when it's upgraded from nyc dp3
581 Slog.i(TAG, "Migrated tied profile lock type");
582 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
583 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
584 } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
585 // It should not happen
586 Slog.e(TAG, "Invalid tied profile lock type: " + quality);
587 }
588 }
Ricky Wai97c8f8d2016-07-13 17:57:45 +0100589 try {
590 final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
591 java.security.KeyStore keyStore =
592 java.security.KeyStore.getInstance("AndroidKeyStore");
593 keyStore.load(null);
594 if (keyStore.containsAlias(alias)) {
595 keyStore.deleteEntry(alias);
596 }
597 } catch (KeyStoreException | NoSuchAlgorithmException |
598 CertificateException | IOException e) {
599 Slog.e(TAG, "Unable to remove tied profile key", e);
600 }
Ricky Wai7b9eb412016-05-12 17:29:12 +0100601 }
Greg Plesureb2e4532016-11-02 17:10:27 -0400602
603 boolean isWatch = mContext.getPackageManager().hasSystemFeature(
604 PackageManager.FEATURE_WATCH);
605 // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
606 // and device management the lockscreen must be re-enabled now for users that upgrade.
607 if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
608 final int userCount = users.size();
609 for (int i = 0; i < userCount; i++) {
610 int id = users.get(i).id;
611 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
612 }
613 setString("migrated_wear_lockscreen_disabled", "true", 0);
614 Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
615 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700616 } catch (RemoteException re) {
Jim Miller187ec582013-04-15 18:27:54 -0700617 Slog.e(TAG, "Unable to migrate old data", re);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700618 }
619 }
620
Jim Miller5ecd8112013-01-09 18:50:26 -0800621 private final void checkWritePermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800622 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700623 }
624
Jim Miller5ecd8112013-01-09 18:50:26 -0800625 private final void checkPasswordReadPermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800626 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700627 }
628
Jim Miller158fe192013-04-17 15:23:55 -0700629 private final void checkReadPermission(String requestedKey, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700630 final int callingUid = Binder.getCallingUid();
Adrian Roos001b00d2015-02-24 17:08:48 +0100631
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000632 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
633 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
634 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
Jim Miller158fe192013-04-17 15:23:55 -0700635 != PackageManager.PERMISSION_GRANTED) {
636 throw new SecurityException("uid=" + callingUid
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000637 + " needs permission " + READ_CONTACTS + " to read "
Jim Miller158fe192013-04-17 15:23:55 -0700638 + requestedKey + " for user " + userId);
639 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700640 }
Adrian Roos001b00d2015-02-24 17:08:48 +0100641
642 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
643 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
644 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
645 != PackageManager.PERMISSION_GRANTED) {
646 throw new SecurityException("uid=" + callingUid
647 + " needs permission " + PERMISSION + " to read "
648 + requestedKey + " for user " + userId);
649 }
650 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700651 }
652
653 @Override
Ricky Waidc283a82016-03-24 19:55:08 +0000654 public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
Ricky Wai7f405f12016-05-31 12:05:05 +0100655 checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000656 synchronized (mSeparateChallengeLock) {
657 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
658 }
659 }
660
661 @Override
662 public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
663 String managedUserPassword) throws RemoteException {
Ricky Wai7f405f12016-05-31 12:05:05 +0100664 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000665 synchronized (mSeparateChallengeLock) {
666 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
667 if (enabled) {
668 mStorage.removeChildProfileLock(userId);
669 removeKeystoreProfileKey(userId);
670 } else {
671 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
672 }
673 }
674 }
675
676 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -0700677 public void setBoolean(String key, boolean value, int userId) throws RemoteException {
678 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100679 setStringUnchecked(key, userId, value ? "1" : "0");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700680 }
681
682 @Override
683 public void setLong(String key, long value, int userId) throws RemoteException {
684 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100685 setStringUnchecked(key, userId, Long.toString(value));
Amith Yamasani52c489c2012-03-28 11:42:42 -0700686 }
687
688 @Override
689 public void setString(String key, String value, int userId) throws RemoteException {
690 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100691 setStringUnchecked(key, userId, value);
692 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700693
Adrian Roos261d5ab2014-10-29 14:42:38 +0100694 private void setStringUnchecked(String key, int userId, String value) {
695 mStorage.writeKeyValue(key, value, userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800696 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
697 BackupManager.dataChanged("com.android.providers.settings");
698 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700699 }
700
701 @Override
702 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700703 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100704 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700705 return TextUtils.isEmpty(value) ?
706 defaultValue : (value.equals("1") || value.equals("true"));
707 }
708
709 @Override
710 public long getLong(String key, long defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700711 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100712 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700713 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
714 }
715
716 @Override
717 public String getString(String key, String defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700718 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100719 return getStringUnchecked(key, defaultValue, userId);
720 }
721
722 public String getStringUnchecked(String key, String defaultValue, int userId) {
723 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
Adrian Roos7811d9f2015-07-27 15:10:13 -0700724 long ident = Binder.clearCallingIdentity();
725 try {
726 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
727 } finally {
728 Binder.restoreCallingIdentity(ident);
729 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100730 }
731
Bryce Lee46145962015-12-14 14:39:10 -0800732 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
733 key = Settings.Secure.LOCK_PATTERN_ENABLED;
734 }
735
Adrian Roos261d5ab2014-10-29 14:42:38 +0100736 return mStorage.readKeyValue(key, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700737 }
738
Adrian Roos4f788452014-05-22 20:45:59 +0200739 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -0700740 public boolean havePassword(int userId) throws RemoteException {
741 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +0100742 return mStorage.hasPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700743 }
744
745 @Override
746 public boolean havePattern(int userId) throws RemoteException {
747 // Do we need a permissions check here?
Adrian Roos261d5ab2014-10-29 14:42:38 +0100748 return mStorage.hasPattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700749 }
750
Chad Brubakera91a8502015-05-07 10:02:22 -0700751 private void setKeystorePassword(String password, int userHandle) {
Robin Leef0246a82014-08-13 09:50:25 +0100752 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +0000753 ks.onUserPasswordChanged(userHandle, password);
Chad Brubakera91a8502015-05-07 10:02:22 -0700754 }
755
756 private void unlockKeystore(String password, int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +0000757 if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
Chad Brubakera91a8502015-05-07 10:02:22 -0700758 final KeyStore ks = KeyStore.getInstance();
Ricky Waidc283a82016-03-24 19:55:08 +0000759 ks.unlock(userHandle, password);
760 }
Chad Brubakera91a8502015-05-07 10:02:22 -0700761
Ricky Waidc283a82016-03-24 19:55:08 +0000762 private String getDecryptedPasswordForTiedProfile(int userId)
763 throws KeyStoreException, UnrecoverableKeyException,
764 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
765 InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
766 CertificateException, IOException {
Ricky Wai4613fe42016-05-24 11:11:42 +0100767 if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
Ricky Waidc283a82016-03-24 19:55:08 +0000768 byte[] storedData = mStorage.readChildProfileLock(userId);
769 if (storedData == null) {
770 throw new FileNotFoundException("Child profile lock file not found");
771 }
772 byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
773 byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
774 storedData.length);
775 byte[] decryptionResult;
776 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
777 keyStore.load(null);
778 SecretKey decryptionKey = (SecretKey) keyStore.getKey(
Ricky Waid3982442016-05-24 19:27:08 +0100779 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
Ricky Waidc283a82016-03-24 19:55:08 +0000780
781 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
782 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
783
784 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
785 decryptionResult = cipher.doFinal(encryptedPassword);
786 return new String(decryptionResult, StandardCharsets.UTF_8);
787 }
788
789 private void unlockChildProfile(int profileHandle) throws RemoteException {
790 try {
791 doVerifyPassword(getDecryptedPasswordForTiedProfile(profileHandle), false,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700792 0 /* no challenge */, profileHandle, null /* progressCallback */);
Ricky Waidc283a82016-03-24 19:55:08 +0000793 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
794 | NoSuchAlgorithmException | NoSuchPaddingException
795 | InvalidAlgorithmParameterException | IllegalBlockSizeException
796 | BadPaddingException | CertificateException | IOException e) {
797 if (e instanceof FileNotFoundException) {
798 Slog.i(TAG, "Child profile key not found");
Clara Bayarri0a587d22016-02-23 14:49:41 -0800799 } else {
Ricky Waidc283a82016-03-24 19:55:08 +0000800 Slog.e(TAG, "Failed to decrypt child profile key", e);
Clara Bayarri0a587d22016-02-23 14:49:41 -0800801 }
Jim Millerde1af082013-09-11 14:58:26 -0700802 }
803 }
804
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000805 private void unlockUser(int userId, byte[] token, byte[] secret) {
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600806 // TODO: make this method fully async so we can update UI with progress strings
807 final CountDownLatch latch = new CountDownLatch(1);
808 final IProgressListener listener = new IProgressListener.Stub() {
809 @Override
810 public void onStarted(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -0600811 Log.d(TAG, "unlockUser started");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600812 }
813
814 @Override
815 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -0600816 Log.d(TAG, "unlockUser progress " + progress);
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600817 }
818
819 @Override
820 public void onFinished(int id, Bundle extras) throws RemoteException {
Jeff Sharkeyfd241082016-04-19 15:58:24 -0600821 Log.d(TAG, "unlockUser finished");
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600822 latch.countDown();
823 }
824 };
825
Jeff Sharkey8924e872015-11-30 12:52:10 -0700826 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800827 ActivityManager.getService().unlockUser(userId, token, secret, listener);
Jeff Sharkey8924e872015-11-30 12:52:10 -0700828 } catch (RemoteException e) {
829 throw e.rethrowAsRuntimeException();
830 }
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600831
832 try {
833 latch.await(15, TimeUnit.SECONDS);
834 } catch (InterruptedException e) {
835 Thread.currentThread().interrupt();
836 }
Ricky Waidc283a82016-03-24 19:55:08 +0000837 try {
838 if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
839 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
840 for (UserInfo pi : profiles) {
841 // Unlock managed profile with unified lock
842 if (pi.isManagedProfile()
843 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
844 && mStorage.hasChildProfileLock(pi.id)) {
845 unlockChildProfile(pi.id);
846 }
847 }
848 }
849 } catch (RemoteException e) {
850 Log.d(TAG, "Failed to unlock child profile", e);
851 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700852 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700853
Andres Morales8fa56652015-03-31 09:19:50 -0700854 private byte[] getCurrentHandle(int userId) {
855 CredentialHash credential;
856 byte[] currentHandle;
Jim Millerde1af082013-09-11 14:58:26 -0700857
Andres Morales8fa56652015-03-31 09:19:50 -0700858 int currentHandleType = mStorage.getStoredCredentialType(userId);
859 switch (currentHandleType) {
860 case CredentialHash.TYPE_PATTERN:
861 credential = mStorage.readPatternHash(userId);
862 currentHandle = credential != null
863 ? credential.hash
864 : null;
865 break;
866 case CredentialHash.TYPE_PASSWORD:
867 credential = mStorage.readPasswordHash(userId);
868 currentHandle = credential != null
869 ? credential.hash
870 : null;
871 break;
872 case CredentialHash.TYPE_NONE:
873 default:
874 currentHandle = null;
875 break;
876 }
877
878 // sanity check
879 if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
880 Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
881 }
882
883 return currentHandle;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700884 }
885
Ricky Waidc283a82016-03-24 19:55:08 +0000886 private void onUserLockChanged(int userId) throws RemoteException {
887 if (mUserManager.getUserInfo(userId).isManagedProfile()) {
888 return;
889 }
890 final boolean isSecure = mStorage.hasPassword(userId) || mStorage.hasPattern(userId);
891 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
892 final int size = profiles.size();
893 for (int i = 0; i < size; i++) {
894 final UserInfo profile = profiles.get(i);
895 if (profile.isManagedProfile()) {
896 final int managedUserId = profile.id;
897 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
898 continue;
899 }
900 if (isSecure) {
901 tieManagedProfileLockIfNecessary(managedUserId, null);
902 } else {
Paul Crowleycc701552016-05-17 14:18:49 -0700903 clearUserKeyProtection(managedUserId);
Ricky Waidc283a82016-03-24 19:55:08 +0000904 getGateKeeperService().clearSecureUserId(managedUserId);
905 mStorage.writePatternHash(null, managedUserId);
906 setKeystorePassword(null, managedUserId);
Paul Crowleycc701552016-05-17 14:18:49 -0700907 fixateNewestUserKeyAuth(managedUserId);
Ricky Waidc283a82016-03-24 19:55:08 +0000908 mStorage.removeChildProfileLock(managedUserId);
909 removeKeystoreProfileKey(managedUserId);
910 }
911 }
912 }
913 }
Andres Morales8fa56652015-03-31 09:19:50 -0700914
Ricky Waidc283a82016-03-24 19:55:08 +0000915 private boolean isManagedProfileWithUnifiedLock(int userId) {
916 return mUserManager.getUserInfo(userId).isManagedProfile()
917 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
918 }
919
920 private boolean isManagedProfileWithSeparatedLock(int userId) {
921 return mUserManager.getUserInfo(userId).isManagedProfile()
922 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
923 }
924
925 // This method should be called by LockPatternUtil only, all internal methods in this class
926 // should call setLockPatternInternal.
Amith Yamasani52c489c2012-03-28 11:42:42 -0700927 @Override
Andres Morales8fa56652015-03-31 09:19:50 -0700928 public void setLockPattern(String pattern, String savedCredential, int userId)
929 throws RemoteException {
Jim Millere484eaf2016-04-13 16:35:36 -0700930 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000931 synchronized (mSeparateChallengeLock) {
932 setLockPatternInternal(pattern, savedCredential, userId);
933 setSeparateProfileChallengeEnabled(userId, true, null);
934 }
935 }
936
Ricky Wai7f405f12016-05-31 12:05:05 +0100937 private void setLockPatternInternal(String pattern, String savedCredential, int userId)
Ricky Waidc283a82016-03-24 19:55:08 +0000938 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -0700939 byte[] currentHandle = getCurrentHandle(userId);
940
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700941 if (pattern == null) {
Paul Crowleycc701552016-05-17 14:18:49 -0700942 clearUserKeyProtection(userId);
Andres Moralescfb61602015-04-16 16:31:15 -0700943 getGateKeeperService().clearSecureUserId(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700944 mStorage.writePatternHash(null, userId);
Chad Brubakera91a8502015-05-07 10:02:22 -0700945 setKeystorePassword(null, userId);
Paul Crowleycc701552016-05-17 14:18:49 -0700946 fixateNewestUserKeyAuth(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000947 onUserLockChanged(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700948 return;
949 }
950
Ricky Waidc283a82016-03-24 19:55:08 +0000951 if (isManagedProfileWithUnifiedLock(userId)) {
952 // get credential from keystore when managed profile has unified lock
953 try {
954 savedCredential = getDecryptedPasswordForTiedProfile(userId);
955 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
956 | NoSuchAlgorithmException | NoSuchPaddingException
957 | InvalidAlgorithmParameterException | IllegalBlockSizeException
958 | BadPaddingException | CertificateException | IOException e) {
959 if (e instanceof FileNotFoundException) {
960 Slog.i(TAG, "Child profile key not found");
961 } else {
962 Slog.e(TAG, "Failed to decrypt child profile key", e);
963 }
Andres Morales8fa56652015-03-31 09:19:50 -0700964 }
Ricky Waidc283a82016-03-24 19:55:08 +0000965 } else {
966 if (currentHandle == null) {
967 if (savedCredential != null) {
968 Slog.w(TAG, "Saved credential provided, but none stored");
969 }
970 savedCredential = null;
971 }
Andres Morales8fa56652015-03-31 09:19:50 -0700972 }
973
974 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
975 if (enrolledHandle != null) {
Paul Crowleycc701552016-05-17 14:18:49 -0700976 CredentialHash willStore
977 = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
978 setUserKeyProtection(userId, pattern,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700979 doVerifyPattern(pattern, willStore, true, 0, userId, null /* progressCallback */));
Andres Morales8fa56652015-03-31 09:19:50 -0700980 mStorage.writePatternHash(enrolledHandle, userId);
Paul Crowleycc701552016-05-17 14:18:49 -0700981 fixateNewestUserKeyAuth(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000982 onUserLockChanged(userId);
Andres Morales8fa56652015-03-31 09:19:50 -0700983 } else {
Andres Morales2c4a5732015-07-09 16:11:00 -0700984 throw new RemoteException("Failed to enroll pattern");
Andres Morales8fa56652015-03-31 09:19:50 -0700985 }
986 }
987
Ricky Waidc283a82016-03-24 19:55:08 +0000988 // This method should be called by LockPatternUtil only, all internal methods in this class
989 // should call setLockPasswordInternal.
Andres Morales8fa56652015-03-31 09:19:50 -0700990 @Override
991 public void setLockPassword(String password, String savedCredential, int userId)
992 throws RemoteException {
Jim Millere484eaf2016-04-13 16:35:36 -0700993 checkWritePermission(userId);
Ricky Waidc283a82016-03-24 19:55:08 +0000994 synchronized (mSeparateChallengeLock) {
995 setLockPasswordInternal(password, savedCredential, userId);
996 setSeparateProfileChallengeEnabled(userId, true, null);
997 }
998 }
Andres Morales8fa56652015-03-31 09:19:50 -0700999
Ricky Wai7f405f12016-05-31 12:05:05 +01001000 private void setLockPasswordInternal(String password, String savedCredential, int userId)
Ricky Waidc283a82016-03-24 19:55:08 +00001001 throws RemoteException {
1002 byte[] currentHandle = getCurrentHandle(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001003 if (password == null) {
Paul Crowleycc701552016-05-17 14:18:49 -07001004 clearUserKeyProtection(userId);
Andres Moralescfb61602015-04-16 16:31:15 -07001005 getGateKeeperService().clearSecureUserId(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001006 mStorage.writePasswordHash(null, userId);
Chad Brubakera91a8502015-05-07 10:02:22 -07001007 setKeystorePassword(null, userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001008 fixateNewestUserKeyAuth(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001009 onUserLockChanged(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001010 return;
1011 }
1012
Ricky Waidc283a82016-03-24 19:55:08 +00001013 if (isManagedProfileWithUnifiedLock(userId)) {
1014 // get credential from keystore when managed profile has unified lock
1015 try {
1016 savedCredential = getDecryptedPasswordForTiedProfile(userId);
Ricky Waide3a0682016-05-03 14:50:03 +01001017 } catch (FileNotFoundException e) {
1018 Slog.i(TAG, "Child profile key not found");
Ricky Waidc283a82016-03-24 19:55:08 +00001019 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1020 | NoSuchAlgorithmException | NoSuchPaddingException
1021 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1022 | BadPaddingException | CertificateException | IOException e) {
Ricky Waide3a0682016-05-03 14:50:03 +01001023 Slog.e(TAG, "Failed to decrypt child profile key", e);
Andres Morales8fa56652015-03-31 09:19:50 -07001024 }
Ricky Waidc283a82016-03-24 19:55:08 +00001025 } else {
1026 if (currentHandle == null) {
1027 if (savedCredential != null) {
1028 Slog.w(TAG, "Saved credential provided, but none stored");
1029 }
1030 savedCredential = null;
1031 }
Andres Morales8fa56652015-03-31 09:19:50 -07001032 }
1033
1034 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
1035 if (enrolledHandle != null) {
Paul Crowleycc701552016-05-17 14:18:49 -07001036 CredentialHash willStore
1037 = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
1038 setUserKeyProtection(userId, password,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001039 doVerifyPassword(password, willStore, true, 0, userId,
1040 null /* progressCallback */));
Andres Morales8fa56652015-03-31 09:19:50 -07001041 mStorage.writePasswordHash(enrolledHandle, userId);
Paul Crowleycc701552016-05-17 14:18:49 -07001042 fixateNewestUserKeyAuth(userId);
Ricky Waidc283a82016-03-24 19:55:08 +00001043 onUserLockChanged(userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001044 } else {
Andres Morales2c4a5732015-07-09 16:11:00 -07001045 throw new RemoteException("Failed to enroll password");
Andres Morales8fa56652015-03-31 09:19:50 -07001046 }
1047 }
1048
Zach Jange61672a2016-11-22 17:47:18 +00001049 private void tieProfileLockToParent(int userId, String password) {
Ricky Waidc283a82016-03-24 19:55:08 +00001050 if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1051 byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1052 byte[] encryptionResult;
1053 byte[] iv;
1054 try {
1055 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1056 keyGenerator.init(new SecureRandom());
1057 SecretKey secretKey = keyGenerator.generateKey();
Ricky Waidc283a82016-03-24 19:55:08 +00001058 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1059 keyStore.load(null);
Ricky Wai97c8f8d2016-07-13 17:57:45 +01001060 try {
1061 keyStore.setEntry(
1062 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1063 new java.security.KeyStore.SecretKeyEntry(secretKey),
1064 new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1065 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1066 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1067 .build());
1068 keyStore.setEntry(
1069 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1070 new java.security.KeyStore.SecretKeyEntry(secretKey),
1071 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1072 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1073 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1074 .setUserAuthenticationRequired(true)
1075 .setUserAuthenticationValidityDurationSeconds(30)
1076 .build());
1077 // Key imported, obtain a reference to it.
1078 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1079 LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1080 Cipher cipher = Cipher.getInstance(
1081 KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1082 + KeyProperties.ENCRYPTION_PADDING_NONE);
1083 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1084 encryptionResult = cipher.doFinal(randomLockSeed);
1085 iv = cipher.getIV();
1086 } finally {
1087 // The original key can now be discarded.
1088 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1089 }
Ricky Waidc283a82016-03-24 19:55:08 +00001090 } catch (CertificateException | UnrecoverableKeyException
Zach Jange61672a2016-11-22 17:47:18 +00001091 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
Ricky Waidc283a82016-03-24 19:55:08 +00001092 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1093 throw new RuntimeException("Failed to encrypt key", e);
1094 }
1095 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1096 try {
1097 if (iv.length != PROFILE_KEY_IV_SIZE) {
1098 throw new RuntimeException("Invalid iv length: " + iv.length);
1099 }
1100 outputStream.write(iv);
1101 outputStream.write(encryptionResult);
1102 } catch (IOException e) {
1103 throw new RuntimeException("Failed to concatenate byte arrays", e);
1104 }
1105 mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1106 }
1107
Andres Morales8fa56652015-03-31 09:19:50 -07001108 private byte[] enrollCredential(byte[] enrolledHandle,
1109 String enrolledCredential, String toEnroll, int userId)
1110 throws RemoteException {
Jim Millerde1af082013-09-11 14:58:26 -07001111 checkWritePermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -07001112 byte[] enrolledCredentialBytes = enrolledCredential == null
1113 ? null
1114 : enrolledCredential.getBytes();
1115 byte[] toEnrollBytes = toEnroll == null
1116 ? null
1117 : toEnroll.getBytes();
Andres Morales23974272015-05-14 22:42:26 -07001118 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1119 enrolledCredentialBytes, toEnrollBytes);
Jim Millerde1af082013-09-11 14:58:26 -07001120
Andres Morales23974272015-05-14 22:42:26 -07001121 if (response == null) {
1122 return null;
Andres Morales8fa56652015-03-31 09:19:50 -07001123 }
Jim Millerde1af082013-09-11 14:58:26 -07001124
Andres Morales23974272015-05-14 22:42:26 -07001125 byte[] hash = response.getPayload();
1126 if (hash != null) {
1127 setKeystorePassword(toEnroll, userId);
1128 } else {
1129 // Should not happen
1130 Slog.e(TAG, "Throttled while enrolling a password");
1131 }
Andres Morales8fa56652015-03-31 09:19:50 -07001132 return hash;
Jim Millerde1af082013-09-11 14:58:26 -07001133 }
1134
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001135 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1136 throws RemoteException {
1137 if (vcr == null) {
1138 throw new RemoteException("Null response verifying a credential we just set");
1139 }
1140 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1141 throw new RemoteException("Non-OK response verifying a credential we just set: "
1142 + vcr.getResponseCode());
1143 }
1144 byte[] token = vcr.getPayload();
1145 if (token == null) {
1146 throw new RemoteException("Empty payload verifying a credential we just set");
1147 }
Paul Crowleycc701552016-05-17 14:18:49 -07001148 addUserKeyAuth(userId, token, secretFromCredential(credential));
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001149 }
1150
1151 private void clearUserKeyProtection(int userId) throws RemoteException {
Paul Crowleycc701552016-05-17 14:18:49 -07001152 addUserKeyAuth(userId, null, null);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001153 }
1154
1155 private static byte[] secretFromCredential(String credential) throws RemoteException {
1156 try {
1157 MessageDigest digest = MessageDigest.getInstance("SHA-512");
1158 // Personalize the hash
1159 byte[] personalization = "Android FBE credential hash"
1160 .getBytes(StandardCharsets.UTF_8);
1161 // Pad it to the block size of the hash function
1162 personalization = Arrays.copyOf(personalization, 128);
1163 digest.update(personalization);
1164 digest.update(credential.getBytes(StandardCharsets.UTF_8));
1165 return digest.digest();
1166 } catch (NoSuchAlgorithmException e) {
1167 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1168 }
1169 }
1170
Paul Crowleycc701552016-05-17 14:18:49 -07001171 private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001172 throws RemoteException {
1173 final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
Sudheer Shanka2250d562016-11-07 15:41:02 -08001174 final IStorageManager storageManager = getStorageManager();
Paul Crowley815036f2016-03-29 14:14:48 -07001175 final long callingId = Binder.clearCallingIdentity();
1176 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001177 storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
Paul Crowley815036f2016-03-29 14:14:48 -07001178 } finally {
1179 Binder.restoreCallingIdentity(callingId);
1180 }
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001181 }
1182
Paul Crowleycc701552016-05-17 14:18:49 -07001183 private void fixateNewestUserKeyAuth(int userId)
1184 throws RemoteException {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001185 final IStorageManager storageManager = getStorageManager();
Toni Barzic6c818722016-05-27 09:18:39 -07001186 final long callingId = Binder.clearCallingIdentity();
1187 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001188 storageManager.fixateNewestUserKeyAuth(userId);
Toni Barzic6c818722016-05-27 09:18:39 -07001189 } finally {
1190 Binder.restoreCallingIdentity(callingId);
1191 }
Paul Crowleycc701552016-05-17 14:18:49 -07001192 }
1193
Jim Millerde1af082013-09-11 14:58:26 -07001194 @Override
Ricky Wai4613fe42016-05-24 11:11:42 +01001195 public void resetKeyStore(int userId) throws RemoteException {
Ricky Wai7f405f12016-05-31 12:05:05 +01001196 checkWritePermission(userId);
Ricky Wai4613fe42016-05-24 11:11:42 +01001197 if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1198 int managedUserId = -1;
1199 String managedUserDecryptedPassword = null;
1200 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1201 for (UserInfo pi : profiles) {
1202 // Unlock managed profile with unified lock
1203 if (pi.isManagedProfile()
1204 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1205 && mStorage.hasChildProfileLock(pi.id)) {
1206 try {
1207 if (managedUserId == -1) {
1208 managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1209 managedUserId = pi.id;
1210 } else {
1211 // Should not happen
1212 Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1213 + ", uid2:" + pi.id);
1214 }
1215 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1216 | NoSuchAlgorithmException | NoSuchPaddingException
1217 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1218 | BadPaddingException | CertificateException | IOException e) {
1219 Slog.e(TAG, "Failed to decrypt child profile key", e);
1220 }
1221 }
1222 }
1223 try {
1224 // Clear all the users credentials could have been installed in for this user.
1225 for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1226 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1227 mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1228 }
1229 }
1230 } finally {
1231 if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1232 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
Zach Jange61672a2016-11-22 17:47:18 +00001233 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
Ricky Wai4613fe42016-05-24 11:11:42 +01001234 }
1235 }
1236 }
1237
1238 @Override
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001239 public VerifyCredentialResponse checkPattern(String pattern, int userId,
1240 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1241 return doVerifyPattern(pattern, false, 0, userId, progressCallback);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001242 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001243
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001244 @Override
Andres Morales23974272015-05-14 22:42:26 -07001245 public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001246 throws RemoteException {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001247 return doVerifyPattern(pattern, true, challenge, userId, null /* progressCallback */);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001248 }
1249
Andres Moralese40bad82015-05-28 14:21:36 -07001250 private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001251 long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
1252 throws RemoteException {
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001253 checkPasswordReadPermission(userId);
Jim Miller2d71384a2016-08-10 15:43:17 -07001254 if (TextUtils.isEmpty(pattern)) {
1255 throw new IllegalArgumentException("Pattern can't be null or empty");
1256 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001257 CredentialHash storedHash = mStorage.readPatternHash(userId);
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001258 return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId,
1259 progressCallback);
Paul Crowleycc701552016-05-17 14:18:49 -07001260 }
1261
1262 private VerifyCredentialResponse doVerifyPattern(String pattern, CredentialHash storedHash,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001263 boolean hasChallenge, long challenge, int userId,
1264 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Jim Miller29d157b2016-07-15 17:24:08 -07001265
1266 if (TextUtils.isEmpty(pattern)) {
1267 throw new IllegalArgumentException("Pattern can't be null or empty");
1268 }
Andres Moralese40bad82015-05-28 14:21:36 -07001269 boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
1270
1271 String patternToVerify;
1272 if (shouldReEnrollBaseZero) {
1273 patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
1274 } else {
1275 patternToVerify = pattern;
1276 }
1277
1278 VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
1279 hasChallenge, challenge,
Andres Morales23974272015-05-14 22:42:26 -07001280 new CredentialUtil() {
1281 @Override
1282 public void setCredential(String pattern, String oldPattern, int userId)
1283 throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001284 setLockPatternInternal(pattern, oldPattern, userId);
Andres Morales23974272015-05-14 22:42:26 -07001285 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001286
Andres Morales23974272015-05-14 22:42:26 -07001287 @Override
1288 public byte[] toHash(String pattern, int userId) {
Andres Moralese40bad82015-05-28 14:21:36 -07001289 return LockPatternUtils.patternToHash(
1290 LockPatternUtils.stringToPattern(pattern));
Andres Morales23974272015-05-14 22:42:26 -07001291 }
Andres Morales59ef1262015-06-26 13:56:39 -07001292
1293 @Override
1294 public String adjustForKeystore(String pattern) {
1295 return LockPatternUtils.patternStringToBaseZero(pattern);
1296 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001297 },
1298 progressCallback
Andres Morales23974272015-05-14 22:42:26 -07001299 );
Andres Moralese40bad82015-05-28 14:21:36 -07001300
1301 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
1302 && shouldReEnrollBaseZero) {
Ricky Waidc283a82016-03-24 19:55:08 +00001303 setLockPatternInternal(pattern, patternToVerify, userId);
Andres Moralese40bad82015-05-28 14:21:36 -07001304 }
1305
1306 return response;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001307 }
1308
1309 @Override
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001310 public VerifyCredentialResponse checkPassword(String password, int userId,
1311 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1312 return doVerifyPassword(password, false, 0, userId, progressCallback);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001313 }
1314
Andres Morales23974272015-05-14 22:42:26 -07001315 @Override
1316 public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
1317 throws RemoteException {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001318 return doVerifyPassword(password, true, challenge, userId, null /* progressCallback */);
Andres Morales23974272015-05-14 22:42:26 -07001319 }
1320
Ricky Wai53940d42016-04-05 15:29:24 +01001321 @Override
1322 public VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern,
1323 long challenge, int userId) throws RemoteException {
1324 checkPasswordReadPermission(userId);
1325 if (!isManagedProfileWithUnifiedLock(userId)) {
1326 throw new RemoteException("User id must be managed profile with unified lock");
1327 }
1328 final int parentProfileId = mUserManager.getProfileParent(userId).id;
1329 // Unlock parent by using parent's challenge
1330 final VerifyCredentialResponse parentResponse = isPattern
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001331 ? doVerifyPattern(password, true, challenge, parentProfileId,
1332 null /* progressCallback */)
1333 : doVerifyPassword(password, true, challenge, parentProfileId,
1334 null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001335 if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1336 // Failed, just return parent's response
1337 return parentResponse;
1338 }
1339
1340 try {
1341 // Unlock work profile, and work profile with unified lock must use password only
1342 return doVerifyPassword(getDecryptedPasswordForTiedProfile(userId), true,
1343 challenge,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001344 userId, null /* progressCallback */);
Ricky Wai53940d42016-04-05 15:29:24 +01001345 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1346 | NoSuchAlgorithmException | NoSuchPaddingException
1347 | InvalidAlgorithmParameterException | IllegalBlockSizeException
1348 | BadPaddingException | CertificateException | IOException e) {
1349 Slog.e(TAG, "Failed to decrypt child profile key", e);
1350 throw new RemoteException("Unable to get tied profile token");
1351 }
1352 }
1353
Andres Morales23974272015-05-14 22:42:26 -07001354 private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001355 long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
1356 throws RemoteException {
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001357 checkPasswordReadPermission(userId);
Jim Miller2d71384a2016-08-10 15:43:17 -07001358 if (TextUtils.isEmpty(password)) {
1359 throw new IllegalArgumentException("Password can't be null or empty");
1360 }
Andres Morales8fa56652015-03-31 09:19:50 -07001361 CredentialHash storedHash = mStorage.readPasswordHash(userId);
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001362 return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId,
1363 progressCallback);
Paul Crowleycc701552016-05-17 14:18:49 -07001364 }
1365
1366 private VerifyCredentialResponse doVerifyPassword(String password, CredentialHash storedHash,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001367 boolean hasChallenge, long challenge, int userId,
1368 ICheckCredentialProgressCallback progressCallback) throws RemoteException {
Jim Miller29d157b2016-07-15 17:24:08 -07001369 if (TextUtils.isEmpty(password)) {
1370 throw new IllegalArgumentException("Password can't be null or empty");
1371 }
Andres Morales23974272015-05-14 22:42:26 -07001372 return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
1373 new CredentialUtil() {
1374 @Override
1375 public void setCredential(String password, String oldPassword, int userId)
1376 throws RemoteException {
Ricky Waidc283a82016-03-24 19:55:08 +00001377 setLockPasswordInternal(password, oldPassword, userId);
Andres Morales23974272015-05-14 22:42:26 -07001378 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001379
Andres Morales23974272015-05-14 22:42:26 -07001380 @Override
1381 public byte[] toHash(String password, int userId) {
1382 return mLockPatternUtils.passwordToHash(password, userId);
1383 }
Andres Morales59ef1262015-06-26 13:56:39 -07001384
1385 @Override
1386 public String adjustForKeystore(String password) {
1387 return password;
1388 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001389 }, progressCallback);
Andres Morales23974272015-05-14 22:42:26 -07001390 }
1391
1392 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001393 String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil,
1394 ICheckCredentialProgressCallback progressCallback)
Andres Morales23974272015-05-14 22:42:26 -07001395 throws RemoteException {
1396 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1397 // don't need to pass empty credentials to GateKeeper
1398 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001399 }
1400
Andres Morales23974272015-05-14 22:42:26 -07001401 if (TextUtils.isEmpty(credential)) {
1402 return VerifyCredentialResponse.ERROR;
Amith Yamasani52c489c2012-03-28 11:42:42 -07001403 }
Adrian Roos261d5ab2014-10-29 14:42:38 +01001404
Jeff Sharkeyeddf5182016-08-09 16:36:08 -06001405 // We're potentially going to be doing a bunch of disk I/O below as part
1406 // of unlocking the user, so yell if calling from the main thread.
1407 StrictMode.noteDiskRead();
1408
Andres Morales8fa56652015-03-31 09:19:50 -07001409 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
Andres Morales23974272015-05-14 22:42:26 -07001410 byte[] hash = credentialUtil.toHash(credential, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001411 if (Arrays.equals(hash, storedHash.hash)) {
Andres Morales59ef1262015-06-26 13:56:39 -07001412 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001413
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001414 // Users with legacy credentials don't have credential-backed
1415 // FBE keys, so just pass through a fake token/secret
1416 Slog.i(TAG, "Unlocking user with fake token: " + userId);
1417 final byte[] fakeToken = String.valueOf(userId).getBytes();
1418 unlockUser(userId, fakeToken, fakeToken);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001419
Andres Morales23974272015-05-14 22:42:26 -07001420 // migrate credential to GateKeeper
1421 credentialUtil.setCredential(credential, null, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001422 if (!hasChallenge) {
Andres Morales23974272015-05-14 22:42:26 -07001423 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001424 }
1425 // Fall through to get the auth token. Technically this should never happen,
Andres Morales23974272015-05-14 22:42:26 -07001426 // as a user that had a legacy credential would have to unlock their device
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001427 // before getting to a flow with a challenge, but supporting for consistency.
1428 } else {
Andres Morales23974272015-05-14 22:42:26 -07001429 return VerifyCredentialResponse.ERROR;
Andres Morales8fa56652015-03-31 09:19:50 -07001430 }
Andres Morales8fa56652015-03-31 09:19:50 -07001431 }
1432
Andres Morales23974272015-05-14 22:42:26 -07001433 VerifyCredentialResponse response;
Paul Crowley98e0a262016-02-04 09:41:53 +00001434 boolean shouldReEnroll = false;
1435 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1436 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
1437 int responseCode = gateKeeperResponse.getResponseCode();
1438 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1439 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
1440 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1441 byte[] token = gateKeeperResponse.getPayload();
1442 if (token == null) {
1443 // something's wrong if there's no payload with a challenge
1444 Slog.e(TAG, "verifyChallenge response had no associated payload");
Andres Morales23974272015-05-14 22:42:26 -07001445 response = VerifyCredentialResponse.ERROR;
Paul Crowley98e0a262016-02-04 09:41:53 +00001446 } else {
1447 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
1448 response = new VerifyCredentialResponse(token);
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001449 }
Andres Morales23974272015-05-14 22:42:26 -07001450 } else {
Paul Crowley98e0a262016-02-04 09:41:53 +00001451 response = VerifyCredentialResponse.ERROR;
Adrian Roos261d5ab2014-10-29 14:42:38 +01001452 }
Andres Morales8fa56652015-03-31 09:19:50 -07001453
Andres Morales23974272015-05-14 22:42:26 -07001454 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001455
1456
Andres Morales23974272015-05-14 22:42:26 -07001457 // credential has matched
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001458
1459 if (progressCallback != null) {
1460 progressCallback.onCredentialVerified();
1461 }
Andres Morales23974272015-05-14 22:42:26 -07001462 unlockKeystore(credential, userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001463
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001464 Slog.i(TAG, "Unlocking user " + userId +
1465 " with token length " + response.getPayload().length);
1466 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001467
Ricky Waidc283a82016-03-24 19:55:08 +00001468 if (isManagedProfileWithSeparatedLock(userId)) {
Clara Bayarri56878a92015-10-29 15:43:55 +00001469 TrustManager trustManager =
1470 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1471 trustManager.setDeviceLockedForUser(userId, false);
1472 }
Andres Morales23974272015-05-14 22:42:26 -07001473 if (shouldReEnroll) {
1474 credentialUtil.setCredential(credential, credential, userId);
1475 }
Adrian Roos873010d2015-08-25 15:59:00 -07001476 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1477 if (response.getTimeout() > 0) {
1478 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1479 }
Andres Morales23974272015-05-14 22:42:26 -07001480 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001481
Andres Morales23974272015-05-14 22:42:26 -07001482 return response;
1483 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -07001484
Amith Yamasani52c489c2012-03-28 11:42:42 -07001485 @Override
Adrian Roos261d5ab2014-10-29 14:42:38 +01001486 public boolean checkVoldPassword(int userId) throws RemoteException {
Paul Lawrence945490c2014-03-27 16:37:28 +00001487 if (!mFirstCallToVold) {
1488 return false;
1489 }
1490 mFirstCallToVold = false;
1491
1492 checkPasswordReadPermission(userId);
1493
1494 // There's no guarantee that this will safely connect, but if it fails
1495 // we will simply show the lock screen when we shouldn't, so relatively
1496 // benign. There is an outside chance something nasty would happen if
1497 // this service restarted before vold stales out the password in this
1498 // case. The nastiness is limited to not showing the lock screen when
1499 // we should, within the first minute of decrypting the phone if this
1500 // service can't connect to vold, it restarts, and then the new instance
1501 // does successfully connect.
Sudheer Shanka2250d562016-11-07 15:41:02 -08001502 final IStorageManager service = getStorageManager();
Paul Lawrence0bbd1082016-04-26 15:21:02 -07001503 String password;
1504 long identity = Binder.clearCallingIdentity();
1505 try {
1506 password = service.getPassword();
1507 service.clearPassword();
1508 } finally {
1509 Binder.restoreCallingIdentity(identity);
1510 }
Paul Lawrence945490c2014-03-27 16:37:28 +00001511 if (password == null) {
1512 return false;
1513 }
1514
1515 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001516 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001517 if (checkPattern(password, userId, null /* progressCallback */).getResponseCode()
Andres Morales23974272015-05-14 22:42:26 -07001518 == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001519 return true;
1520 }
1521 }
1522 } catch (Exception e) {
1523 }
1524
1525 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001526 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001527 if (checkPassword(password, userId, null /* progressCallback */).getResponseCode()
Andres Morales23974272015-05-14 22:42:26 -07001528 == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001529 return true;
1530 }
1531 }
1532 } catch (Exception e) {
1533 }
1534
1535 return false;
1536 }
1537
Amith Yamasanif11a5742016-06-16 08:20:07 -07001538 private void removeUser(int userId, boolean unknownUser) {
Adrian Roos261d5ab2014-10-29 14:42:38 +01001539 mStorage.removeUser(userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001540 mStrongAuth.removeUser(userId);
Robin Lee49d810c2014-09-23 13:50:22 +01001541
1542 final KeyStore ks = KeyStore.getInstance();
Chad Brubaker83ce0952015-05-12 13:00:02 -07001543 ks.onUserRemoved(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001544
1545 try {
1546 final IGateKeeperService gk = getGateKeeperService();
1547 if (gk != null) {
1548 gk.clearSecureUserId(userId);
1549 }
1550 } catch (RemoteException ex) {
1551 Slog.w(TAG, "unable to clear GK secure user id");
1552 }
Amith Yamasanif11a5742016-06-16 08:20:07 -07001553 if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
Ricky Waidc283a82016-03-24 19:55:08 +00001554 removeKeystoreProfileKey(userId);
1555 }
1556 }
1557
1558 private void removeKeystoreProfileKey(int targetUserId) {
1559 if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1560 try {
1561 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1562 keyStore.load(null);
Ricky Waid3982442016-05-24 19:27:08 +01001563 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1564 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
Ricky Waidc283a82016-03-24 19:55:08 +00001565 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1566 | IOException e) {
1567 // We have tried our best to remove all keys
1568 Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1569 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001570 }
1571
Adrian Roosb5e47222015-08-14 15:53:06 -07001572 @Override
1573 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1574 checkPasswordReadPermission(UserHandle.USER_ALL);
1575 mStrongAuth.registerStrongAuthTracker(tracker);
1576 }
1577
1578 @Override
1579 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1580 checkPasswordReadPermission(UserHandle.USER_ALL);
1581 mStrongAuth.unregisterStrongAuthTracker(tracker);
1582 }
1583
1584 @Override
1585 public void requireStrongAuth(int strongAuthReason, int userId) {
1586 checkWritePermission(userId);
1587 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1588 }
1589
Adrian Roos4ab7e592016-04-13 15:38:13 -07001590 @Override
1591 public void userPresent(int userId) {
1592 checkWritePermission(userId);
1593 mStrongAuth.reportUnlock(userId);
1594 }
1595
Victor Changa0940d32016-05-16 19:36:08 +01001596 @Override
1597 public int getStrongAuthForUser(int userId) {
1598 checkPasswordReadPermission(userId);
1599 return mStrongAuthTracker.getStrongAuthForUser(userId);
1600 }
1601
Jorim Jaggi2fef6f72016-11-01 19:06:25 -07001602 private boolean isCallerShell() {
1603 final int callingUid = Binder.getCallingUid();
1604 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1605 }
1606
1607 private void enforceShell() {
1608 if (!isCallerShell()) {
1609 throw new SecurityException("Caller must be shell");
1610 }
1611 }
1612
1613 @Override
1614 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1615 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1616 throws RemoteException {
1617 enforceShell();
1618 final long origId = Binder.clearCallingIdentity();
1619 try {
1620 (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
1621 this, in, out, err, args, callback, resultReceiver);
1622 } finally {
1623 Binder.restoreCallingIdentity(origId);
1624 }
1625 }
1626
Amith Yamasani52c489c2012-03-28 11:42:42 -07001627 private static final String[] VALID_SETTINGS = new String[] {
1628 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
1629 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
1630 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
1631 LockPatternUtils.PASSWORD_TYPE_KEY,
1632 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
1633 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1634 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
1635 LockPatternUtils.LOCKSCREEN_OPTIONS,
1636 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
1637 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
1638 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
1639 LockPatternUtils.PASSWORD_HISTORY_KEY,
1640 Secure.LOCK_PATTERN_ENABLED,
1641 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
1642 Secure.LOCK_PATTERN_VISIBLE,
1643 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
Jim Miller187ec582013-04-15 18:27:54 -07001644 };
1645
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +00001646 // Reading these settings needs the contacts permission
1647 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
Jim Miller187ec582013-04-15 18:27:54 -07001648 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1649 Secure.LOCK_SCREEN_OWNER_INFO
1650 };
Paul Lawrence945490c2014-03-27 16:37:28 +00001651
Adrian Roos001b00d2015-02-24 17:08:48 +01001652 // Reading these settings needs the same permission as checking the password
1653 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
1654 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1655 LockPatternUtils.PASSWORD_HISTORY_KEY,
Adrian Roos855fa302015-04-02 16:01:12 +02001656 LockPatternUtils.PASSWORD_TYPE_KEY,
Ricky Wai7f405f12016-05-31 12:05:05 +01001657 SEPARATE_PROFILE_CHALLENGE_KEY
Adrian Roos001b00d2015-02-24 17:08:48 +01001658 };
1659
Amith Yamasani072543f2015-02-13 11:09:45 -08001660 private static final String[] SETTINGS_TO_BACKUP = new String[] {
1661 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1662 Secure.LOCK_SCREEN_OWNER_INFO
1663 };
1664
Sudheer Shanka2250d562016-11-07 15:41:02 -08001665 private IStorageManager getStorageManager() {
Paul Lawrence945490c2014-03-27 16:37:28 +00001666 final IBinder service = ServiceManager.getService("mount");
1667 if (service != null) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001668 return IStorageManager.Stub.asInterface(service);
Paul Lawrence945490c2014-03-27 16:37:28 +00001669 }
1670 return null;
1671 }
Andres Morales8fa56652015-03-31 09:19:50 -07001672
Andres Morales301ea442015-04-17 09:15:47 -07001673 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
1674 @Override
1675 public void binderDied() {
1676 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
1677 mGateKeeperService = null;
1678 }
1679 }
1680
1681 private synchronized IGateKeeperService getGateKeeperService()
1682 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -07001683 if (mGateKeeperService != null) {
1684 return mGateKeeperService;
1685 }
1686
1687 final IBinder service =
Amith Yamasanid04aaa32016-06-13 12:09:36 -07001688 ServiceManager.getService(Context.GATEKEEPER_SERVICE);
Andres Morales8fa56652015-03-31 09:19:50 -07001689 if (service != null) {
Andres Morales301ea442015-04-17 09:15:47 -07001690 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
Andres Morales8fa56652015-03-31 09:19:50 -07001691 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
1692 return mGateKeeperService;
1693 }
1694
1695 Slog.e(TAG, "Unable to acquire GateKeeperService");
1696 return null;
1697 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001698}