diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 5a06f7fe19906..25e1589db74e0 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -54,13 +54,6 @@ interface ILockSettings { void userPresent(int userId); int getStrongAuthForUser(int userId); - long addEscrowToken(in byte[] token, int userId); - boolean removeEscrowToken(long handle, int userId); - boolean isEscrowTokenActive(long handle, int userId); - boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, - in byte[] token, int requestedQuality, int userId); - void unlockUserWithToken(long tokenHandle, in byte[] token, int userId); - // Keystore RecoveryController methods. // {@code ServiceSpecificException} may be thrown to signal an error, which caller can // convert to {@code RecoveryManagerException}. diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 7eb2f38f52873..bf075bf800f47 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -45,6 +45,7 @@ import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.google.android.collect.Lists; import libcore.util.HexEncoding; @@ -1473,6 +1474,13 @@ public class LockPatternUtils { } } + private LockSettingsInternal getLockSettingsInternal() { + LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class); + if (service == null) { + throw new SecurityException("Only available to system server itself"); + } + return service; + } /** * Create an escrow token for the current user, which can later be used to unlock FBE * or change user password. @@ -1481,44 +1489,41 @@ public class LockPatternUtils { * confirm credential operation in order to activate the token for future use. If the user * has no secure lockscreen, then the token is activated immediately. * + *
This method is only available to code running in the system server process itself. + * * @return a unique 64-bit token handle which is needed to refer to this token later. */ public long addEscrowToken(byte[] token, int userId) { - try { - return getLockSettings().addEscrowToken(token, userId); - } catch (RemoteException re) { - return 0L; - } + return getLockSettingsInternal().addEscrowToken(token, userId); } /** * Remove an escrow token. + * + *
This method is only available to code running in the system server process itself. + * * @return true if the given handle refers to a valid token previously returned from * {@link #addEscrowToken}, whether it's active or not. return false otherwise. */ public boolean removeEscrowToken(long handle, int userId) { - try { - return getLockSettings().removeEscrowToken(handle, userId); - } catch (RemoteException re) { - return false; - } + return getLockSettingsInternal().removeEscrowToken(handle, userId); } /** * Check if the given escrow token is active or not. Only active token can be used to call * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken} + * + *
This method is only available to code running in the system server process itself. */ public boolean isEscrowTokenActive(long handle, int userId) { - try { - return getLockSettings().isEscrowTokenActive(handle, userId); - } catch (RemoteException re) { - return false; - } + return getLockSettingsInternal().isEscrowTokenActive(handle, userId); } /** * Change a user's lock credential with a pre-configured escrow token. * + *
This method is only available to code running in the system server process itself. + * * @param credential The new credential to be set * @param type Credential type: password / pattern / none. * @param requestedQuality the requested password quality by DevicePolicyManager. @@ -1530,55 +1535,55 @@ public class LockPatternUtils { */ public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality, long tokenHandle, byte[] token, int userId) { - try { - if (type != CREDENTIAL_TYPE_NONE) { - if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) { - throw new IllegalArgumentException("password must not be null and at least " - + "of length " + MIN_LOCK_PASSWORD_SIZE); - } - final int quality = computePasswordQuality(type, credential, requestedQuality); - if (!getLockSettings().setLockCredentialWithToken(credential, type, tokenHandle, - token, quality, userId)) { - return false; - } - setLong(PASSWORD_TYPE_KEY, quality, userId); - - updateEncryptionPasswordIfNeeded(credential, quality, userId); - updatePasswordHistory(credential, userId); - } else { - if (!TextUtils.isEmpty(credential)) { - throw new IllegalArgumentException("password must be emtpy for NONE type"); - } - if (!getLockSettings().setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, - tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - userId)) { - return false; - } - setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - userId); - - if (userId == UserHandle.USER_SYSTEM) { - // Set the encryption password to default. - updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); - setCredentialRequiredToDecrypt(false); - } + LockSettingsInternal localService = getLockSettingsInternal(); + if (type != CREDENTIAL_TYPE_NONE) { + if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) { + throw new IllegalArgumentException("password must not be null and at least " + + "of length " + MIN_LOCK_PASSWORD_SIZE); + } + final int quality = computePasswordQuality(type, credential, requestedQuality); + if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, + token, quality, userId)) { + return false; + } + setLong(PASSWORD_TYPE_KEY, quality, userId); + + updateEncryptionPasswordIfNeeded(credential, quality, userId); + updatePasswordHistory(credential, userId); + } else { + if (!TextUtils.isEmpty(credential)) { + throw new IllegalArgumentException("password must be emtpy for NONE type"); + } + if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, + tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, + userId)) { + return false; + } + setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, + userId); + + if (userId == UserHandle.USER_SYSTEM) { + // Set the encryption password to default. + updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); + setCredentialRequiredToDecrypt(false); } - onAfterChangingPassword(userId); - return true; - } catch (RemoteException re) { - Log.e(TAG, "Unable to save lock password ", re); - re.rethrowFromSystemServer(); } - return false; + onAfterChangingPassword(userId); + return true; } - public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) { - try { - getLockSettings().unlockUserWithToken(tokenHandle, token, userId); - } catch (RemoteException re) { - Log.e(TAG, "Unable to unlock user with token", re); - re.rethrowFromSystemServer(); - } + /** + * Unlock the specified user by an pre-activated escrow token. This should have the same effect + * on device encryption as the user entering his lockscreen credentials for the first time after + * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore + * + *
This method is only available to code running in the system server process itself.
+ *
+ * @return {@code true} if the supplied token is valid and unlock succeeds,
+ * {@code false} otherwise.
+ */
+ public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+ return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
new file mode 100644
index 0000000000000..9de9ef7f2aeaf
--- /dev/null
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+
+/**
+ * LockSettingsService local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class LockSettingsInternal {
+
+ /**
+ * Create an escrow token for the current user, which can later be used to unlock FBE
+ * or change user password.
+ *
+ * After adding, if the user currently has lockscreen password, he will need to perform a
+ * confirm credential operation in order to activate the token for future use. If the user
+ * has no secure lockscreen, then the token is activated immediately.
+ *
+ * @return a unique 64-bit token handle which is needed to refer to this token later.
+ */
+ public abstract long addEscrowToken(byte[] token, int userId);
+
+ /**
+ * Remove an escrow token.
+ * @return true if the given handle refers to a valid token previously returned from
+ * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
+ */
+ public abstract boolean removeEscrowToken(long handle, int userId);
+
+ /**
+ * Check if the given escrow token is active or not. Only active token can be used to call
+ * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+ */
+ public abstract boolean isEscrowTokenActive(long handle, int userId);
+
+ public abstract boolean setLockCredentialWithToken(String credential, int type,
+ long tokenHandle, byte[] token, int requestedQuality, int userId);
+
+ public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 468ec591caa24..74ebf3e44616d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -102,6 +102,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -436,6 +437,8 @@ public class LockSettingsService extends ILockSettings.Stub {
mStrongAuthTracker.register(mStrongAuth);
mSpManager = injector.getSyntheticPasswordManager(mStorage);
+
+ LocalServices.addService(LockSettingsInternal.class, new LocalService());
}
/**
@@ -1041,14 +1044,10 @@ public class LockSettingsService extends ILockSettings.Stub {
private boolean isUserSecure(int userId) {
synchronized (mSpManager) {
- try {
- if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- long handle = getSyntheticPasswordHandleLocked(userId);
- return mSpManager.getCredentialType(handle, userId) !=
- LockPatternUtils.CREDENTIAL_TYPE_NONE;
- }
- } catch (RemoteException e) {
- // fall through
+ if (isSyntheticPasswordBasedCredentialLocked(userId)) {
+ long handle = getSyntheticPasswordHandleLocked(userId);
+ return mSpManager.getCredentialType(handle, userId) !=
+ LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
}
return mStorage.hasCredential(userId);
@@ -2305,7 +2304,7 @@ public class LockSettingsService extends ILockSettings.Stub {
SyntheticPasswordManager.DEFAULT_HANDLE, userId);
}
- private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
+ private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
if (userId == USER_FRP) {
final int type = mStorage.readPersistentDataBlock().type;
return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
@@ -2318,7 +2317,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@VisibleForTesting
- protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
+ protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
long handle = getSyntheticPasswordHandleLocked(userId);
// This is a global setting
long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
@@ -2326,7 +2325,7 @@ public class LockSettingsService extends ILockSettings.Stub {
return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
}
- private void enableSyntheticPasswordLocked() throws RemoteException {
+ private void enableSyntheticPasswordLocked() {
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
@@ -2525,9 +2524,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
}
- @Override
- public long addEscrowToken(byte[] token, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private long addEscrowToken(byte[] token, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
synchronized (mSpManager) {
enableSyntheticPasswordLocked();
@@ -2559,7 +2556,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
+ private void activateEscrowTokens(AuthenticationToken auth, int userId) {
if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
synchronized (mSpManager) {
disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
@@ -2570,17 +2567,13 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- @Override
- public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private boolean isEscrowTokenActive(long handle, int userId) {
synchronized (mSpManager) {
return mSpManager.existsHandle(handle, userId);
}
}
- @Override
- public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private boolean removeEscrowToken(long handle, int userId) {
synchronized (mSpManager) {
if (handle == getSyntheticPasswordHandleLocked(userId)) {
Slog.w(TAG, "Cannot remove password handle");
@@ -2598,10 +2591,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- @Override
- public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
byte[] token, int requestedQuality, int userId) throws RemoteException {
- ensureCallerSystemUid();
boolean result;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2650,10 +2641,8 @@ public class LockSettingsService extends ILockSettings.Stub {
return true;
}
- @Override
- public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
+ private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
throws RemoteException {
- ensureCallerSystemUid();
AuthenticationResult authResult;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2663,11 +2652,12 @@ public class LockSettingsService extends ILockSettings.Stub {
tokenHandle, token, userId);
if (authResult.authToken == null) {
Slog.w(TAG, "Invalid escrow token supplied");
- return;
+ return false;
}
}
unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
onAuthTokenKnownForUser(userId, authResult.authToken);
+ return true;
}
@Override
@@ -2732,20 +2722,11 @@ public class LockSettingsService extends ILockSettings.Stub {
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
mSpManager.destroyEscrowData(userId);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private void ensureCallerSystemUid() throws SecurityException {
- final int callingUid = mInjector.binderGetCallingUid();
- if (callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("Only system can call this API.");
- }
- }
-
private class DeviceProvisionedObserver extends ContentObserver {
private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
Settings.Global.DEVICE_PROVISIONED);
@@ -2834,4 +2815,46 @@ public class LockSettingsService extends ILockSettings.Stub {
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
}
+
+ private final class LocalService extends LockSettingsInternal {
+
+ @Override
+ public long addEscrowToken(byte[] token, int userId) {
+ try {
+ return LockSettingsService.this.addEscrowToken(token, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean removeEscrowToken(long handle, int userId) {
+ return LockSettingsService.this.removeEscrowToken(handle, userId);
+ }
+
+ @Override
+ public boolean isEscrowTokenActive(long handle, int userId) {
+ return LockSettingsService.this.isEscrowTokenActive(handle, userId);
+ }
+
+ @Override
+ public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ byte[] token, int requestedQuality, int userId) {
+ try {
+ return LockSettingsService.this.setLockCredentialWithToken(credential, type,
+ tokenHandle, token, requestedQuality, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+ try {
+ return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index e8648701bd0dd..96f81606a985c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -43,6 +43,7 @@ import android.test.AndroidTestCase;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.server.LocalServices;
import org.mockito.invocation.InvocationOnMock;
@@ -67,6 +68,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
private ArrayList