Home | History | Annotate | Download | only in functional
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "KeymasterHidlTest.h"
     18 
     19 namespace android {
     20 namespace hardware {
     21 namespace keymaster {
     22 namespace V4_0 {
     23 namespace test {
     24 
     25 /**
     26  * HmacKeySharingTest extends KeymasterHidlTest with some utilities that make writing HMAC sharing
     27  * tests easier.
     28  */
     29 class HmacKeySharingTest : public KeymasterHidlTest {
     30    protected:
     31     struct GetParamsResult {
     32         ErrorCode error;
     33         HmacSharingParameters params;
     34         auto tie() { return std::tie(error, params); }
     35     };
     36 
     37     struct ComputeHmacResult {
     38         ErrorCode error;
     39         HidlBuf sharing_check;
     40         auto tie() { return std::tie(error, sharing_check); }
     41     };
     42 
     43     using KeymasterVec = std::vector<sp<IKeymasterDevice>>;
     44     using ByteString = std::basic_string<uint8_t>;
     45     // using NonceVec = std::vector<HidlBuf>;
     46 
     47     GetParamsResult getHmacSharingParameters(IKeymasterDevice& keymaster) {
     48         GetParamsResult result;
     49         EXPECT_TRUE(keymaster
     50                         .getHmacSharingParameters([&](auto error, auto params) {
     51                             result.tie() = std::tie(error, params);
     52                         })
     53                         .isOk());
     54         return result;
     55     }
     56 
     57     hidl_vec<HmacSharingParameters> getHmacSharingParameters(const KeymasterVec& keymasters) {
     58         std::vector<HmacSharingParameters> paramsVec;
     59         for (auto& keymaster : keymasters) {
     60             auto result = getHmacSharingParameters(*keymaster);
     61             EXPECT_EQ(ErrorCode::OK, result.error);
     62             if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
     63         }
     64         return paramsVec;
     65     }
     66 
     67     ComputeHmacResult computeSharedHmac(IKeymasterDevice& keymaster,
     68                                         const hidl_vec<HmacSharingParameters>& params) {
     69         ComputeHmacResult result;
     70         EXPECT_TRUE(keymaster
     71                         .computeSharedHmac(params,
     72                                            [&](auto error, auto params) {
     73                                                result.tie() = std::tie(error, params);
     74                                            })
     75                         .isOk());
     76         return result;
     77     }
     78 
     79     std::vector<ComputeHmacResult> computeSharedHmac(
     80         const KeymasterVec& keymasters, const hidl_vec<HmacSharingParameters>& paramsVec) {
     81         std::vector<ComputeHmacResult> resultVec;
     82         for (auto& keymaster : keymasters) {
     83             resultVec.push_back(computeSharedHmac(*keymaster, paramsVec));
     84         }
     85         return resultVec;
     86     }
     87 
     88     std::vector<ByteString> copyNonces(const hidl_vec<HmacSharingParameters>& paramsVec) {
     89         std::vector<ByteString> nonces;
     90         for (auto& param : paramsVec) {
     91             nonces.emplace_back(param.nonce.data(), param.nonce.size());
     92         }
     93         return nonces;
     94     }
     95 
     96     void verifyResponses(const HidlBuf& expected, const std::vector<ComputeHmacResult>& responses) {
     97         for (auto& response : responses) {
     98             EXPECT_EQ(ErrorCode::OK, response.error);
     99             EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
    100         }
    101     }
    102 };
    103 
    104 TEST_F(HmacKeySharingTest, GetParameters) {
    105     auto result1 = getHmacSharingParameters(keymaster());
    106     EXPECT_EQ(ErrorCode::OK, result1.error);
    107 
    108     auto result2 = getHmacSharingParameters(keymaster());
    109     EXPECT_EQ(ErrorCode::OK, result2.error);
    110 
    111     ASSERT_EQ(result1.params.seed, result2.params.seed)
    112         << "A given keymaster should always return the same seed.";
    113     ASSERT_EQ(result1.params.nonce, result2.params.nonce)
    114         << "A given keymaster should always return the same nonce until restart.";
    115 }
    116 
    117 TEST_F(HmacKeySharingTest, ComputeSharedHmac) {
    118     auto params = getHmacSharingParameters(all_keymasters());
    119     ASSERT_EQ(all_keymasters().size(), params.size())
    120         << "One or more keymasters failed to provide parameters.";
    121 
    122     auto nonces = copyNonces(params);
    123     EXPECT_EQ(all_keymasters().size(), nonces.size());
    124     std::sort(nonces.begin(), nonces.end());
    125     std::unique(nonces.begin(), nonces.end());
    126     EXPECT_EQ(all_keymasters().size(), nonces.size());
    127 
    128     auto responses = computeSharedHmac(all_keymasters(), params);
    129     ASSERT_GT(responses.size(), 0U);
    130     verifyResponses(responses[0].sharing_check, responses);
    131 
    132     // Do it a second time.  Should get the same answers.
    133     params = getHmacSharingParameters(all_keymasters());
    134     ASSERT_EQ(all_keymasters().size(), params.size())
    135         << "One or more keymasters failed to provide parameters.";
    136 
    137     responses = computeSharedHmac(all_keymasters(), params);
    138     ASSERT_GT(responses.size(), 0U);
    139     ASSERT_EQ(32U, responses[0].sharing_check.size());
    140     verifyResponses(responses[0].sharing_check, responses);
    141 }
    142 
    143 template <class F>
    144 class final_action {
    145    public:
    146     explicit final_action(F f) : f_(move(f)) {}
    147     ~final_action() { f_(); }
    148 
    149    private:
    150     F f_;
    151 };
    152 
    153 template <class F>
    154 inline final_action<F> finally(const F& f) {
    155     return final_action<F>(f);
    156 }
    157 
    158 TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
    159     // Important: The execution of this test gets the keymaster implementations on the device out of
    160     // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
    161     // devices, this still has the potential to cause confusion.  To mitigate that, we always
    162     // (barring crashes :-/) re-run the unmodified agreement process on our way out.
    163     auto fixup_hmac = finally(
    164         [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
    165 
    166     auto params = getHmacSharingParameters(all_keymasters());
    167     ASSERT_EQ(all_keymasters().size(), params.size())
    168         << "One or more keymasters failed to provide parameters.";
    169 
    170     // All should be well in the normal case
    171     auto responses = computeSharedHmac(all_keymasters(), params);
    172 
    173     ASSERT_GT(responses.size(), 0U);
    174     HidlBuf correct_response = responses[0].sharing_check;
    175     verifyResponses(correct_response, responses);
    176 
    177     // Pick a random param, a random byte within the param's nonce, and a random bit within
    178     // the byte.  Flip that bit.
    179     size_t param_to_tweak = rand() % params.size();
    180     uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
    181     uint8_t bit_to_tweak = rand() % 8;
    182     params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
    183 
    184     responses = computeSharedHmac(all_keymasters(), params);
    185     for (size_t i = 0; i < responses.size(); ++i) {
    186         if (i == param_to_tweak) {
    187             EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
    188                 << "Keymaster that provided tweaked param should fail to compute HMAC key";
    189         } else {
    190             EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
    191             EXPECT_NE(correct_response, responses[i].sharing_check)
    192                 << "Others should calculate a different HMAC key, due to the tweaked nonce.";
    193         }
    194     }
    195 }
    196 
    197 TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
    198     // Important: The execution of this test gets the keymaster implementations on the device out of
    199     // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
    200     // devices, this still has the potential to cause confusion.  To mitigate that, we always
    201     // (barring crashes :-/) re-run the unmodified agreement process on our way out.
    202     auto fixup_hmac = finally(
    203         [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
    204 
    205     auto params = getHmacSharingParameters(all_keymasters());
    206     ASSERT_EQ(all_keymasters().size(), params.size())
    207         << "One or more keymasters failed to provide parameters.";
    208 
    209     // All should be well in the normal case
    210     auto responses = computeSharedHmac(all_keymasters(), params);
    211 
    212     ASSERT_GT(responses.size(), 0U);
    213     HidlBuf correct_response = responses[0].sharing_check;
    214     verifyResponses(correct_response, responses);
    215 
    216     // Pick a random param and modify the seed.  We just increase the seed length by 1.  It doesn't
    217     // matter what value is in the additional byte; it changes the seed regardless.
    218     auto param_to_tweak = rand() % params.size();
    219     auto& to_tweak = params[param_to_tweak].seed;
    220     ASSERT_TRUE(to_tweak.size() == 32 || to_tweak.size() == 0);
    221     if (!to_tweak.size()) {
    222         to_tweak.resize(32);  // Contents don't matter; a little randomization is nice.
    223     }
    224     to_tweak[0]++;
    225 
    226     responses = computeSharedHmac(all_keymasters(), params);
    227     for (size_t i = 0; i < responses.size(); ++i) {
    228         if (i == param_to_tweak) {
    229             EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
    230                 << "Keymaster that provided tweaked param should fail to compute HMAC key ";
    231         } else {
    232             EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
    233             EXPECT_NE(correct_response, responses[i].sharing_check)
    234                 << "Others should calculate a different HMAC key, due to the tweaked nonce.";
    235         }
    236     }
    237 }
    238 
    239 }  // namespace test
    240 }  // namespace V4_0
    241 }  // namespace keymaster
    242 }  // namespace hardware
    243 }  // namespace android
    244