Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcd49f99 authored by Rubin Xu's avatar Rubin Xu
Browse files

Move escrow APIs into LockSettingsInternal

Remove the IPC interfaces so these APIs are only available to other
services running inside system server process only.

Bug: 62264551
Test: runtest frameworks-services -p com.android.server.locksettings
Change-Id: Ic7ac5df5fb977bc68a2c4daafaa3cdaf3ba66fcd
parent f8a69fdd
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -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}.
+63 −58
Original line number Diff line number Diff line
@@ -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.
     *
     * <p>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.
     *
     * <p>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}
     *
     * <p>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.
     *
     * <p>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,14 +1535,14 @@ public class LockPatternUtils {
     */
    public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
            long tokenHandle, byte[] token, int userId) {
        try {
        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 (!getLockSettings().setLockCredentialWithToken(credential, type, tokenHandle,
            if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
                    token, quality, userId)) {
                return false;
            }
@@ -1549,7 +1554,7 @@ public class LockPatternUtils {
            if (!TextUtils.isEmpty(credential)) {
                throw new IllegalArgumentException("password must be emtpy for NONE type");
            }
                if (!getLockSettings().setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
            if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
                    tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
                    userId)) {
                return false;
@@ -1565,20 +1570,20 @@ public class LockPatternUtils {
        }
        onAfterChangingPassword(userId);
        return true;
        } catch (RemoteException re) {
            Log.e(TAG, "Unable to save lock password ", re);
            re.rethrowFromSystemServer();
        }
        return false;
    }

    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
     *
     * <p>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);
    }


+56 −0
Original line number Diff line number Diff line
/*
 * 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);
}
+60 −37
Original line number Diff line number Diff line
@@ -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,15 +1044,11 @@ 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
            }
        }
        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();
            }
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -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<UserInfo> mPrimaryUserProfiles = new ArrayList<>();

    LockSettingsService mService;
    LockSettingsInternal mLocalService;

    MockLockSettingsContext mContext;
    LockSettingsStorageTestable mStorage;
@@ -95,6 +97,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
        mDevicePolicyManager = mock(DevicePolicyManager.class);
        mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class);

        LocalServices.removeServiceForTest(LockSettingsInternal.class);
        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
        LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);

@@ -146,6 +149,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
        // Adding a fake Device Owner app which will enable escrow token support in LSS.
        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
                new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
        mLocalService = LocalServices.getService(LockSettingsInternal.class);
    }

    private UserInfo installChildProfile(int profileId) {
Loading