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

Commit e40dcabb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move escrow APIs into LockSettingsInternal" into pi-dev

parents 7b97503c fcd49f99
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