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

Commit 22897e8a authored by Devin Moore's avatar Devin Moore Committed by Android (Google) Code Review
Browse files

Merge "locksettings: Add AIDL weaver HAL support"

parents d39590ae af014899
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ java_library_static {
        "android.hardware.tv.cec-V1-java",
        "android.hardware.tv.hdmi-V1-java",
        "android.hardware.weaver-V1.0-java",
        "android.hardware.weaver-V2-java",
        "android.hardware.biometrics.face-V1.0-java",
        "android.hardware.biometrics.fingerprint-V2.3-java",
        "android.hardware.oemlock-V1.0-java",
+101 −82
Original line number Diff line number Diff line
@@ -24,13 +24,14 @@ import android.annotation.Nullable;
import android.app.admin.PasswordMetrics;
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.weaver.V1_0.IWeaver;
import android.hardware.weaver.V1_0.WeaverConfig;
import android.hardware.weaver.V1_0.WeaverReadResponse;
import android.hardware.weaver.V1_0.WeaverReadStatus;
import android.hardware.weaver.V1_0.WeaverStatus;
import android.hardware.weaver.IWeaver;
import android.hardware.weaver.WeaverConfig;
import android.hardware.weaver.WeaverReadResponse;
import android.hardware.weaver.WeaverReadStatus;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.UserManager;
import android.provider.Settings;
import android.security.GateKeeper;
@@ -60,7 +61,6 @@ import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@@ -464,37 +464,67 @@ public class SyntheticPasswordManager {
    }

    @VisibleForTesting
    protected IWeaver getWeaverService() throws RemoteException {
    protected android.hardware.weaver.V1_0.IWeaver getWeaverHidlService() throws RemoteException {
        try {
            return IWeaver.getService(/* retry */ true);
            return android.hardware.weaver.V1_0.IWeaver.getService(/* retry */ true);
        } catch (NoSuchElementException e) {
            Slog.i(TAG, "Device does not support weaver");
            return null;
        }
    }

    public synchronized void initWeaverService() {
        if (mWeaver != null) {
            return;
    private IWeaver getWeaverService() {
        // Try to get the AIDL service first
        try {
            IWeaver aidlWeaver = IWeaver.Stub.asInterface(
                    ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default"));
            if (aidlWeaver != null) {
                Slog.i(TAG, "Using AIDL weaver service");
                return aidlWeaver;
            }
        } catch (SecurityException e) {
            Slog.w(TAG, "Does not have permissions to get AIDL weaver service");
        }

        // If the AIDL service can't be found, look for the HIDL service
        try {
            mWeaverConfig = null;
            mWeaver = getWeaverService();
            android.hardware.weaver.V1_0.IWeaver hidlWeaver = getWeaverHidlService();
            if (hidlWeaver != null) {
                Slog.i(TAG, "Using HIDL weaver service");
                return new WeaverHidlWrapper(hidlWeaver);
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Failed to get HIDL weaver service.", e);
        }
        Slog.w(TAG, "Device does not support weaver");
        return null;
    }

    public synchronized void initWeaverService() {
        if (mWeaver != null) {
                mWeaver.getConfig((int status, WeaverConfig config) -> {
                    if (status == WeaverStatus.OK && config.slots > 0) {
                        mWeaverConfig = config;
                    } else {
                        Slog.e(TAG, "Failed to get weaver config, status " + status
                                + " slots: " + config.slots);
                        mWeaver = null;
            return;
        }
                });
                mPasswordSlotManager.refreshActiveSlots(getUsedWeaverSlots());

        IWeaver weaver = getWeaverService();
        if (weaver == null) {
            return;
        }

        // Get the config
        WeaverConfig weaverConfig = null;
        try {
            weaverConfig = weaver.getConfig();
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to get weaver service", e);
            Slog.e(TAG, "Failed to get weaver config", e);
        }
        if (weaverConfig == null || weaverConfig.slots <= 0) {
            Slog.e(TAG, "Failed to initialize weaver config");
            return;
        }

        mWeaver = weaver;
        mWeaverConfig = weaverConfig;
        mPasswordSlotManager.refreshActiveSlots(getUsedWeaverSlots());
        Slog.i(TAG, "Weaver service initialized");
    }

    private synchronized boolean isWeaverAvailable() {
@@ -525,18 +555,30 @@ public class SyntheticPasswordManager {
            value = secureRandom(mWeaverConfig.valueSize);
        }
        try {
            int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value));
            if (writeStatus != WeaverStatus.OK) {
                Slog.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
                return null;
            }
            mWeaver.write(slot, key, value);
        } catch (RemoteException e) {
            Slog.e(TAG, "weaver write failed", e);
            Slog.e(TAG, "weaver write binder call failed, slot: " + slot, e);
            return null;
        } catch (ServiceSpecificException e) {
            Slog.e(TAG, "weaver write failed, slot: " + slot, e);
            return null;
        }
        return value;
    }

    /**
     * Create a VerifyCredentialResponse from a timeout base on the WeaverReadResponse.
     * This checks the received timeout(long) to make sure it sure it fits in an int before
     * using it. If it doesn't fit, we use Integer.MAX_VALUE.
     */
    private static VerifyCredentialResponse responseFromTimeout(WeaverReadResponse response) {
        int timeout =
                response.timeout > Integer.MAX_VALUE || response.timeout < 0
                ? Integer.MAX_VALUE
                : (int) response.timeout;
        return VerifyCredentialResponse.fromTimeout(timeout);
    }

    /**
     * Verify the supplied key against a weaver slot, returning a response indicating whether
     * the verification is successful, throttled or failed. If successful, the bound secret
@@ -551,46 +593,39 @@ public class SyntheticPasswordManager {
        } else if (key.length != mWeaverConfig.keySize) {
            throw new IllegalArgumentException("Invalid key size for weaver");
        }
        final VerifyCredentialResponse[] response = new VerifyCredentialResponse[1];
        final WeaverReadResponse readResponse;
        try {
            mWeaver.read(slot, toByteArrayList(key),
                    (int status, WeaverReadResponse readResponse) -> {
                    switch (status) {
            readResponse = mWeaver.read(slot, key);
        } catch (RemoteException e) {
            Slog.e(TAG, "weaver read failed, slot: " + slot, e);
            return VerifyCredentialResponse.ERROR;
        }

        switch (readResponse.status) {
            case WeaverReadStatus.OK:
                            response[0] = new VerifyCredentialResponse.Builder().setGatekeeperHAT(
                                    fromByteArrayList(readResponse.value)).build();
                            break;
                return new VerifyCredentialResponse.Builder()
                                      .setGatekeeperHAT(readResponse.value)
                                      .build();
            case WeaverReadStatus.THROTTLE:
                            response[0] = VerifyCredentialResponse
                                    .fromTimeout(readResponse.timeout);
                Slog.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
                            break;
                return responseFromTimeout(readResponse);
            case WeaverReadStatus.INCORRECT_KEY:
                if (readResponse.timeout == 0) {
                                response[0] = VerifyCredentialResponse.ERROR;
                    Slog.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
                    return VerifyCredentialResponse.ERROR;
                } else {
                                response[0] = VerifyCredentialResponse
                                        .fromTimeout(readResponse.timeout);
                                Slog.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: "
                                        + slot);
                    Slog.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: " + slot);
                    return responseFromTimeout(readResponse);
                }
                            break;
            case WeaverReadStatus.FAILED:
                            response[0] = VerifyCredentialResponse.ERROR;
                Slog.e(TAG, "weaver read failed (FAILED), slot: " + slot);
                            break;
                return VerifyCredentialResponse.ERROR;
            default:
                            response[0] = VerifyCredentialResponse.ERROR;
                            Slog.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
                            break;
                    }
                });
        } catch (RemoteException e) {
            response[0] = VerifyCredentialResponse.ERROR;
            Slog.e(TAG, "weaver read failed, slot: " + slot, e);
                Slog.e(TAG,
                        "weaver read unknown status " + readResponse.status
                                + ", slot: " + slot);
                return VerifyCredentialResponse.ERROR;
        }
        return response[0];
    }

    public void removeUser(IGateKeeperService gatekeeper, int userId) {
@@ -1660,22 +1695,6 @@ public class SyntheticPasswordManager {

    native long nativeSidFromPasswordHandle(byte[] handle);

    protected static ArrayList<Byte> toByteArrayList(byte[] data) {
        ArrayList<Byte> result = new ArrayList<Byte>(data.length);
        for (int i = 0; i < data.length; i++) {
            result.add(data[i]);
        }
        return result;
    }

    protected static byte[] fromByteArrayList(ArrayList<Byte> data) {
        byte[] result = new byte[data.size()];
        for (int i = 0; i < data.size(); i++) {
            result[i] = data.get(i);
        }
        return result;
    }

    @VisibleForTesting
    static byte[] bytesToHex(byte[] bytes) {
        return HexEncoding.encodeToString(bytes).getBytes();
+143 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.server.locksettings;

import android.hardware.weaver.V1_0.IWeaver;
import android.hardware.weaver.V1_0.WeaverConfig;
import android.hardware.weaver.V1_0.WeaverReadResponse;
import android.hardware.weaver.V1_0.WeaverReadStatus;
import android.hardware.weaver.V1_0.WeaverStatus;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Slog;

import java.util.ArrayList;

/**
 * Implement the AIDL IWeaver interface wrapping the HIDL implementation
 */
class WeaverHidlWrapper implements android.hardware.weaver.IWeaver {
    private static final String TAG = "WeaverHidlWrapper";
    private final IWeaver mImpl;

    WeaverHidlWrapper(IWeaver impl) {
        mImpl = impl;
    }

    private static ArrayList<Byte> toByteArrayList(byte[] data) {
        ArrayList<Byte> result = new ArrayList<Byte>(data.length);
        for (int i = 0; i < data.length; i++) {
            result.add(data[i]);
        }
        return result;
    }

    private static byte[] fromByteArrayList(ArrayList<Byte> data) {
        byte[] result = new byte[data.size()];
        for (int i = 0; i < data.size(); i++) {
            result[i] = data.get(i);
        }
        return result;
    }

    @Override
    public String getInterfaceHash() {
        // We do not require the interface hash as the client.
        throw new UnsupportedOperationException(
            "WeaverHidlWrapper does not support getInterfaceHash");
    }
    @Override
    public int getInterfaceVersion() {
        // Supports only V2 which is at feature parity.
        return 2;
    }
    @Override
    public android.os.IBinder asBinder() {
        // There is no IHwBinder to IBinder. Not required as the client.
        throw new UnsupportedOperationException("WeaverHidlWrapper does not support asBinder");
    }

    @Override
    public android.hardware.weaver.WeaverConfig getConfig() throws RemoteException {
        final WeaverConfig[] res = new WeaverConfig[1];
        mImpl.getConfig((int status, WeaverConfig config) -> {
            if (status == WeaverStatus.OK && config.slots > 0) {
                res[0] = config;
            } else {
                res[0] = null;
                Slog.e(TAG,
                        "Failed to get HIDL weaver config. status: " + status
                                + ", slots: " + config.slots);
            }
        });

        if (res[0] == null) {
            return null;
        }
        android.hardware.weaver.WeaverConfig config = new android.hardware.weaver.WeaverConfig();
        config.slots = res[0].slots;
        config.keySize = res[0].keySize;
        config.valueSize = res[0].valueSize;
        return config;
    }

    @Override
    public android.hardware.weaver.WeaverReadResponse read(int slotId, byte[] key)
            throws RemoteException {
        final WeaverReadResponse[] res = new WeaverReadResponse[1];
        final int[] status = new int[1];
        mImpl.read(
                slotId, toByteArrayList(key), (int inStatus, WeaverReadResponse readResponse) -> {
                    status[0] = inStatus;
                    res[0] = readResponse;
                });

        android.hardware.weaver.WeaverReadResponse aidlRes =
                new android.hardware.weaver.WeaverReadResponse();
        switch (status[0]) {
            case WeaverReadStatus.OK:
                aidlRes.status = android.hardware.weaver.WeaverReadStatus.OK;
                break;
            case WeaverReadStatus.THROTTLE:
                aidlRes.status = android.hardware.weaver.WeaverReadStatus.THROTTLE;
                break;
            case WeaverReadStatus.INCORRECT_KEY:
                aidlRes.status = android.hardware.weaver.WeaverReadStatus.INCORRECT_KEY;
                break;
            case WeaverReadStatus.FAILED:
                aidlRes.status = android.hardware.weaver.WeaverReadStatus.FAILED;
                break;
            default:
                aidlRes.status = android.hardware.weaver.WeaverReadStatus.FAILED;
                break;
        }
        if (res[0] != null) {
            aidlRes.timeout = res[0].timeout;
            aidlRes.value = fromByteArrayList(res[0].value);
        }
        return aidlRes;
    }

    @Override
    public void write(int slotId, byte[] key, byte[] value) throws RemoteException {
        int writeStatus = mImpl.write(slotId, toByteArrayList(key), toByteArrayList(value));
        if (writeStatus != WeaverStatus.OK) {
            throw new ServiceSpecificException(
                android.hardware.weaver.IWeaver.STATUS_FAILED, "Failed IWeaver.write call");
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager {
    }

    @Override
    protected IWeaver getWeaverService() throws RemoteException {
    protected IWeaver getWeaverHidlService() throws RemoteException {
        return mWeaverService;
    }