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

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

Merge "Add utility method to perform HMAC agreement" into pi-dev

parents 7a53d3e9 f0f05d40
Loading
Loading
Loading
Loading
+102 −9
Original line number Diff line number Diff line
@@ -16,24 +16,73 @@

#include <keymasterV4_0/Keymaster.h>

#include <iomanip>

#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <keymasterV4_0/Keymaster3.h>
#include <keymasterV4_0/Keymaster4.h>
#include <keymasterV4_0/key_param_output.h>
#include <keymasterV4_0/keymaster_utils.h>

namespace android {
namespace hardware {

template <class T>
std::ostream& operator<<(std::ostream& os, const hidl_vec<T>& vec) {
    os << "{ ";
    if (vec.size()) {
        for (size_t i = 0; i < vec.size() - 1; ++i) os << vec[i] << ", ";
        os << vec[vec.size() - 1];
    }
    os << " }";
    return os;
}

std::ostream& operator<<(std::ostream& os, const hidl_vec<uint8_t>& vec) {
    std::ios_base::fmtflags flags(os.flags());
    os << std::setw(2) << std::setfill('0') << std::hex;
    for (uint8_t c : vec) os << static_cast<int>(c);
    os.flags(flags);
    return os;
}

template <size_t N>
std::ostream& operator<<(std::ostream& os, const hidl_array<uint8_t, N>& vec) {
    std::ios_base::fmtflags flags(os.flags());
    os << std::setw(2) << std::setfill('0') << std::hex;
    for (size_t i = 0; i < N; ++i) os << static_cast<int>(vec[i]);
    os.flags(flags);
    return os;
}

namespace keymaster {
namespace V4_0 {

std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) {
    // Note that by design, although seed and nonce are used to compute a secret, they are
    // not secrets and it's just fine to log them.
    os << "(seed: " << params.seed << ", nonce: " << params.nonce << ')';
    return os;
}

namespace support {

using ::android::sp;
using ::android::hidl::manager::V1_0::IServiceManager;

std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster) {
    auto& version = keymaster.halVersion();
    os << version.keymasterName << " from " << version.authorName
       << " SecurityLevel: " << toString(version.securityLevel)
       << " HAL: " << keymaster.descriptor() << "/" << keymaster.instanceName();
    return os;
}

template <typename Wrapper>
std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
    const sp<IServiceManager>& serviceManager) {
    std::vector<std::unique_ptr<Keymaster>> result;
    Keymaster::KeymasterSet result;

    bool foundDefault = false;
    auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
@@ -57,7 +106,7 @@ std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
    return result;
}

std::vector<std::unique_ptr<Keymaster>> Keymaster::enumerateAvailableDevices() {
Keymaster::KeymasterSet Keymaster::enumerateAvailableDevices() {
    auto serviceManager = IServiceManager::getService();
    CHECK(serviceManager) << "Could not retrieve ServiceManager";

@@ -73,18 +122,62 @@ std::vector<std::unique_ptr<Keymaster>> Keymaster::enumerateAvailableDevices() {

    size_t i = 1;
    LOG(INFO) << "List of Keymaster HALs found:";
    for (auto& hal : result) {
        auto& version = hal->halVersion();
        LOG(INFO) << "Keymaster HAL #" << i << ": " << version.keymasterName << " from "
                  << version.authorName << " SecurityLevel: " << toString(version.securityLevel)
                  << " HAL : " << hal->descriptor() << " instance " << hal->instanceName();
    }
    for (auto& hal : result) LOG(INFO) << "Keymaster HAL #" << i++ << ": " << *hal;

    return result;
}

static hidl_vec<HmacSharingParameters> getHmacParameters(
    const Keymaster::KeymasterSet& keymasters) {
    std::vector<HmacSharingParameters> params_vec;
    params_vec.reserve(keymasters.size());
    for (auto& keymaster : keymasters) {
        if (keymaster->halVersion().majorVersion < 4) continue;
        auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) {
            CHECK(error == ErrorCode::OK)
                << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
            params_vec.push_back(params);
        });
        CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
                         << " error: " << rc.description();
    }
    std::sort(params_vec.begin(), params_vec.end());

    return params_vec;
}

static void computeHmac(const Keymaster::KeymasterSet& keymasters,
                        const hidl_vec<HmacSharingParameters>& params) {
    if (!params.size()) return;

    hidl_vec<uint8_t> sharingCheck;
    bool firstKeymaster = true;
    LOG(DEBUG) << "Computing HMAC with params " << params;
    for (auto& keymaster : keymasters) {
        if (keymaster->halVersion().majorVersion < 4) continue;
        LOG(DEBUG) << "Computing HMAC for " << *keymaster;
        auto rc = keymaster->computeSharedHmac(params, [&](auto error, auto& curSharingCheck) {
            CHECK(error == ErrorCode::OK)
                << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
            if (firstKeymaster) {
                sharingCheck = curSharingCheck;
                firstKeymaster = false;
            }
            // TODO: Validate that curSharingCheck == sharingCheck.  b/77588764
            // CHECK(curSharingCheck == sharingCheck) << "HMAC computation failed for " <<
            // *keymaster;
        });
        CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
                         << " error: " << rc.description();
    }
}

void Keymaster::performHmacKeyAgreement(const KeymasterSet& keymasters) {
    computeHmac(keymasters, getHmacParameters(keymasters));
}

}  // namespace support
}  // namespace V4_0
}  // namespace keymaster
}  // namespace hardware
};  // namespace android
}  // namespace android
+18 −4
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ namespace support {
 */
class Keymaster : public IKeymasterDevice {
   public:
    using KeymasterSet = std::vector<std::unique_ptr<Keymaster>>;

    Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
        : descriptor_(descriptor), instanceName_(instanceName) {}
    virtual ~Keymaster() {}
@@ -55,21 +57,33 @@ class Keymaster : public IKeymasterDevice {
        }
    };

    virtual const VersionResult& halVersion() = 0;
    const hidl_string& descriptor() { return descriptor_; }
    const hidl_string& instanceName() { return instanceName_; }
    virtual const VersionResult& halVersion() const = 0;
    const hidl_string& descriptor() const { return descriptor_; }
    const hidl_string& instanceName() const { return instanceName_; }

    /**
     * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
     * secure (as defined by VersionResult::operator<).
     */
    static std::vector<std::unique_ptr<Keymaster>> enumerateAvailableDevices();
    static KeymasterSet enumerateAvailableDevices();

    /**
     * Ask provided Keymaster instances to compute a shared HMAC key using
     * getHmacSharingParameters() and computeSharedHmac().  This computation is idempotent as long
     * as the same set of Keymaster instances is used each time (and if all of the instances work
     * correctly).  It must be performed once per boot, but should do no harm to be repeated.
     *
     * If key agreement fails, this method will crash the process (with CHECK).
     */
    static void performHmacKeyAgreement(const KeymasterSet& keymasters);

   private:
    hidl_string descriptor_;
    hidl_string instanceName_;
};

std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster);

}  // namespace support
}  // namespace V4_0
}  // namespace keymaster
+2 −2
Original line number Diff line number Diff line
@@ -45,8 +45,8 @@ class Keymaster3 : public Keymaster {
          km3_dev_(km3_dev),
          haveVersion_(false) {}

    const VersionResult& halVersion() override {
        getVersionIfNeeded();
    const VersionResult& halVersion() const override {
        const_cast<Keymaster3*>(this)->getVersionIfNeeded();
        return version_;
    }

+2 −2
Original line number Diff line number Diff line
@@ -37,8 +37,8 @@ class Keymaster4 : public Keymaster {
          haveVersion_(false),
          dev_(km4_dev) {}

    const VersionResult& halVersion() override {
        getVersionIfNeeded();
    const VersionResult& halVersion() const override {
        const_cast<Keymaster4*>(this)->getVersionIfNeeded();
        return version_;
    }

+8 −0
Original line number Diff line number Diff line
@@ -23,6 +23,14 @@ namespace android {
namespace hardware {
namespace keymaster {
namespace V4_0 {

/**
 * Define a lexicographical ordering on HmacSharingParameters.  The parameters to
 * IKeymasterDevice::computeSharedHmac are required to be delivered in the order specified by this
 * comparison operator.
 */
bool operator<(const HmacSharingParameters& a, const HmacSharingParameters& b);

namespace support {

inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
Loading