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

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

Merge changes I9da12a70,Idd147d20

* changes:
  Add HMAC key sharing tests
  Refactor VTS tests a bit, to enable adding tests in separate files.
parents 32f4103d 3d943326
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@ cc_test {
    name: "VtsHalKeymasterV4_0TargetTest",
    name: "VtsHalKeymasterV4_0TargetTest",
    defaults: ["VtsHalTargetTestDefaults"],
    defaults: ["VtsHalTargetTestDefaults"],
    srcs: [
    srcs: [
        "HmacKeySharingTest.cpp",
        "KeymasterHidlTest.cpp",
        "keymaster_hidl_hal_test.cpp",
        "keymaster_hidl_hal_test.cpp",
    ],
    ],
    static_libs: [
    static_libs: [
+238 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

#include "KeymasterHidlTest.h"

namespace android {
namespace hardware {
namespace keymaster {
namespace V4_0 {
namespace test {

/**
 * HmacKeySharingTest extends KeymasterHidlTest with some utilities that make writing HMAC sharing
 * tests easier.
 */
class HmacKeySharingTest : public KeymasterHidlTest {
   protected:
    struct GetParamsResult {
        ErrorCode error;
        HmacSharingParameters params;
        auto tie() { return std::tie(error, params); }
    };

    struct ComputeHmacResult {
        ErrorCode error;
        HidlBuf sharing_check;
        auto tie() { return std::tie(error, sharing_check); }
    };

    using KeymasterVec = std::vector<sp<IKeymasterDevice>>;
    using ByteString = std::basic_string<uint8_t>;
    // using NonceVec = std::vector<HidlBuf>;

    GetParamsResult getHmacSharingParameters(IKeymasterDevice& keymaster) {
        GetParamsResult result;
        EXPECT_TRUE(keymaster
                        .getHmacSharingParameters([&](auto error, auto params) {
                            result.tie() = std::tie(error, params);
                        })
                        .isOk());
        return result;
    }

    hidl_vec<HmacSharingParameters> getHmacSharingParameters(const KeymasterVec& keymasters) {
        std::vector<HmacSharingParameters> paramsVec;
        for (auto& keymaster : keymasters) {
            auto result = getHmacSharingParameters(*keymaster);
            EXPECT_EQ(ErrorCode::OK, result.error);
            if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
        }
        return paramsVec;
    }

    ComputeHmacResult computeSharedHmac(IKeymasterDevice& keymaster,
                                        const hidl_vec<HmacSharingParameters>& params) {
        ComputeHmacResult result;
        EXPECT_TRUE(keymaster
                        .computeSharedHmac(params,
                                           [&](auto error, auto params) {
                                               result.tie() = std::tie(error, params);
                                           })
                        .isOk());
        return result;
    }

    std::vector<ComputeHmacResult> computeSharedHmac(
        const KeymasterVec& keymasters, const hidl_vec<HmacSharingParameters>& paramsVec) {
        std::vector<ComputeHmacResult> resultVec;
        for (auto& keymaster : keymasters) {
            resultVec.push_back(computeSharedHmac(*keymaster, paramsVec));
        }
        return resultVec;
    }

    std::vector<ByteString> copyNonces(const hidl_vec<HmacSharingParameters>& paramsVec) {
        std::vector<ByteString> nonces;
        for (auto& param : paramsVec) {
            nonces.emplace_back(param.nonce.data(), param.nonce.size());
        }
        return nonces;
    }

    void verifyResponses(const HidlBuf& expected, const std::vector<ComputeHmacResult>& responses) {
        for (auto& response : responses) {
            EXPECT_EQ(ErrorCode::OK, response.error);
            EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
        }
    }
};

TEST_F(HmacKeySharingTest, GetParameters) {
    auto result1 = getHmacSharingParameters(keymaster());
    EXPECT_EQ(ErrorCode::OK, result1.error);

    auto result2 = getHmacSharingParameters(keymaster());
    EXPECT_EQ(ErrorCode::OK, result2.error);

    ASSERT_EQ(result1.params.seed, result2.params.seed)
        << "A given keymaster should always return the same seed.";
    ASSERT_EQ(result1.params.nonce, result2.params.nonce)
        << "A given keymaster should always return the same nonce until restart.";
}

TEST_F(HmacKeySharingTest, ComputeSharedHmac) {
    auto params = getHmacSharingParameters(all_keymasters());
    ASSERT_EQ(all_keymasters().size(), params.size())
        << "One or more keymasters failed to provide parameters.";

    auto nonces = copyNonces(params);
    EXPECT_EQ(all_keymasters().size(), nonces.size());
    std::sort(nonces.begin(), nonces.end());
    std::unique(nonces.begin(), nonces.end());
    EXPECT_EQ(all_keymasters().size(), nonces.size());

    auto responses = computeSharedHmac(all_keymasters(), params);
    ASSERT_GT(responses.size(), 0U);
    verifyResponses(responses[0].sharing_check, responses);

    // Do it a second time.  Should get the same answers.
    params = getHmacSharingParameters(all_keymasters());
    ASSERT_EQ(all_keymasters().size(), params.size())
        << "One or more keymasters failed to provide parameters.";

    responses = computeSharedHmac(all_keymasters(), params);
    ASSERT_GT(responses.size(), 0U);
    verifyResponses(responses[0].sharing_check, responses);
}

template <class F>
class final_action {
   public:
    explicit final_action(F f) : f_(move(f)) {}
    ~final_action() { f_(); }

   private:
    F f_;
};

template <class F>
inline final_action<F> finally(const F& f) {
    return final_action<F>(f);
}

TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
    // Important: The execution of this test gets the keymaster implementations on the device out of
    // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
    // devices, this still has the potential to cause confusion.  To mitigate that, we always
    // (barring crashes :-/) re-run the unmodified agreement process on our way out.
    auto fixup_hmac = finally(
        [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });

    auto params = getHmacSharingParameters(all_keymasters());
    ASSERT_EQ(all_keymasters().size(), params.size())
        << "One or more keymasters failed to provide parameters.";

    // All should be well in the normal case
    auto responses = computeSharedHmac(all_keymasters(), params);

    ASSERT_GT(responses.size(), 0U);
    HidlBuf correct_response = responses[0].sharing_check;
    verifyResponses(correct_response, responses);

    // Pick a random param, a random byte within the param's nonce, and a random bit within
    // the byte.  Flip that bit.
    size_t param_to_tweak = rand() % params.size();
    uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
    uint8_t bit_to_tweak = rand() % 8;
    params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);

    responses = computeSharedHmac(all_keymasters(), params);
    for (size_t i = 0; i < responses.size(); ++i) {
        if (i == param_to_tweak) {
            EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
                << "Keymaster that provided tweaked param should fail to compute HMAC key";
        } else {
            EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
            EXPECT_NE(correct_response, responses[i].sharing_check)
                << "Others should calculate a different HMAC key, due to the tweaked nonce.";
        }
    }
}

TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
    // Important: The execution of this test gets the keymaster implementations on the device out of
    // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
    // devices, this still has the potential to cause confusion.  To mitigate that, we always
    // (barring crashes :-/) re-run the unmodified agreement process on our way out.
    auto fixup_hmac = finally(
        [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });

    auto params = getHmacSharingParameters(all_keymasters());
    ASSERT_EQ(all_keymasters().size(), params.size())
        << "One or more keymasters failed to provide parameters.";

    // All should be well in the normal case
    auto responses = computeSharedHmac(all_keymasters(), params);

    ASSERT_GT(responses.size(), 0U);
    HidlBuf correct_response = responses[0].sharing_check;
    verifyResponses(correct_response, responses);

    // Pick a random param and modify the seed.  We just increase the seed length by 1.  It doesn't
    // matter what value is in the additional byte; it changes the seed regardless.
    auto param_to_tweak = rand() % params.size();
    auto& to_tweak = params[param_to_tweak].seed;
    to_tweak.resize(to_tweak.size() + 1);

    responses = computeSharedHmac(all_keymasters(), params);
    for (size_t i = 0; i < responses.size(); ++i) {
        if (i == param_to_tweak) {
            EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
                << "Keymaster that provided tweaked param should fail to compute HMAC key ";
        } else {
            EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
            EXPECT_NE(correct_response, responses[i].sharing_check)
                << "Others should calculate a different HMAC key, due to the tweaked nonce.";
        }
    }
}

}  // namespace test
}  // namespace V4_0
}  // namespace keymaster
}  // namespace hardware
}  // namespace android
+589 −0

File added.

Preview size limit exceeded, changes collapsed.

+230 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_

#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
#include <android/hardware/keymaster/4.0/types.h>

#include <VtsHalHidlTargetTestBase.h>

#include <keymaster/keymaster_configuration.h>

#include <keymasterV4_0/authorization_set.h>

namespace android {
namespace hardware {
namespace keymaster {
namespace V4_0 {

::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);

namespace test {

using ::android::sp;
using ::std::string;

class HidlBuf : public hidl_vec<uint8_t> {
    typedef hidl_vec<uint8_t> super;

   public:
    HidlBuf() {}
    HidlBuf(const super& other) : super(other) {}
    HidlBuf(super&& other) : super(std::move(other)) {}
    explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }

    HidlBuf& operator=(const super& other) {
        super::operator=(other);
        return *this;
    }

    HidlBuf& operator=(super&& other) {
        super::operator=(std::move(other));
        return *this;
    }

    HidlBuf& operator=(const string& other) {
        resize(other.size());
        std::copy(other.begin(), other.end(), begin());
        return *this;
    }

    string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
};

constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;

class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
   public:
    // get the test environment singleton
    static KeymasterHidlEnvironment* Instance() {
        static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
        return instance;
    }

    void registerTestServices() override { registerTestService<IKeymasterDevice>(); }

   private:
    KeymasterHidlEnvironment(){};

    GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
};

class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
   public:
    void TearDown() override {
        if (key_blob_.size()) {
            CheckedDeleteKey();
        }
        AbortIfNeeded();
    }

    // SetUpTestCase runs only once per test case, not once per test.
    static void SetUpTestCase();
    static void TearDownTestCase() {
        keymaster_.clear();
        all_keymasters_.clear();
    }

    static IKeymasterDevice& keymaster() { return *keymaster_; }
    static const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
    static uint32_t os_version() { return os_version_; }
    static uint32_t os_patch_level() { return os_patch_level_; }

    ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
                          KeyCharacteristics* key_characteristics);
    ErrorCode GenerateKey(const AuthorizationSet& key_desc);

    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
                        const string& key_material, HidlBuf* key_blob,
                        KeyCharacteristics* key_characteristics);
    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
                        const string& key_material);

    ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key,
                               const AuthorizationSet& wrapping_key_desc, string masking_key);

    ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
                        const HidlBuf& app_data, HidlBuf* key_material);
    ErrorCode ExportKey(KeyFormat format, HidlBuf* key_material);

    ErrorCode DeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
    ErrorCode DeleteKey(bool keep_key_blob = false);

    ErrorCode DeleteAllKeys();

    void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
    void CheckedDeleteKey();

    ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
                                 const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
    ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics);

    ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
                    AuthorizationSet* out_params, OperationHandle* op_handle);
    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
                    AuthorizationSet* out_params);
    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params);

    ErrorCode Update(OperationHandle op_handle, const AuthorizationSet& in_params,
                     const string& input, AuthorizationSet* out_params, string* output,
                     size_t* input_consumed);
    ErrorCode Update(const string& input, string* out, size_t* input_consumed);

    ErrorCode Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
                     const string& input, const string& signature, AuthorizationSet* out_params,
                     string* output);
    ErrorCode Finish(const string& message, string* output);
    ErrorCode Finish(const string& message, const string& signature, string* output);
    ErrorCode Finish(string* output) { return Finish(string(), output); }

    ErrorCode Abort(OperationHandle op_handle);

    void AbortIfNeeded();

    ErrorCode AttestKey(const HidlBuf& key_blob, const AuthorizationSet& attest_params,
                        hidl_vec<hidl_vec<uint8_t>>* cert_chain);
    ErrorCode AttestKey(const AuthorizationSet& attest_params,
                        hidl_vec<hidl_vec<uint8_t>>* cert_chain);

    string ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const string& message,
                          const AuthorizationSet& in_params, AuthorizationSet* out_params);

    string SignMessage(const HidlBuf& key_blob, const string& message,
                       const AuthorizationSet& params);
    string SignMessage(const string& message, const AuthorizationSet& params);

    string MacMessage(const string& message, Digest digest, size_t mac_length);

    void CheckHmacTestVector(const string& key, const string& message, Digest digest,
                             const string& expected_mac);

    void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
                               const string& expected_ciphertext);

    void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
                                  PaddingMode padding_mode, const string& key, const string& iv,
                                  const string& input, const string& expected_output);

    void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
                       const AuthorizationSet& params);
    void VerifyMessage(const string& message, const string& signature,
                       const AuthorizationSet& params);

    string EncryptMessage(const HidlBuf& key_blob, const string& message,
                          const AuthorizationSet& in_params, AuthorizationSet* out_params);
    string EncryptMessage(const string& message, const AuthorizationSet& params,
                          AuthorizationSet* out_params);
    string EncryptMessage(const string& message, const AuthorizationSet& params);
    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding);
    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
                          HidlBuf* iv_out);
    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
                          const HidlBuf& iv_in);

    string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
                          const AuthorizationSet& params);
    string DecryptMessage(const string& ciphertext, const AuthorizationSet& params);
    string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode,
                          const HidlBuf& iv);

    std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob);

    static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }

    HidlBuf key_blob_;
    KeyCharacteristics key_characteristics_;
    OperationHandle op_handle_ = kOpHandleSentinel;

   private:
    static sp<IKeymasterDevice> keymaster_;
    static std::vector<sp<IKeymasterDevice>> all_keymasters_;
    static uint32_t os_version_;
    static uint32_t os_patch_level_;

    static SecurityLevel securityLevel_;
    static hidl_string name_;
    static hidl_string author_;
};

}  // namespace test
}  // namespace V4_0
}  // namespace keymaster
}  // namespace hardware
}  // namespace android

#endif  // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+1 −627

File changed.

Preview size limit exceeded, changes collapsed.