• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
tieandroid::hardware::keymaster::V4_0::test::HmacKeySharingTest::GetParamsResult34         auto tie() { return std::tie(error, params); }
35     };
36 
37     struct ComputeHmacResult {
38         ErrorCode error;
39         HidlBuf sharing_check;
tieandroid::hardware::keymaster::V4_0::test::HmacKeySharingTest::ComputeHmacResult40         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 
getHmacSharingParameters(IKeymasterDevice & keymaster)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 
getHmacSharingParameters(const KeymasterVec & keymasters)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 
computeSharedHmac(IKeymasterDevice & keymaster,const hidl_vec<HmacSharingParameters> & params)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 
computeSharedHmac(const KeymasterVec & keymasters,const hidl_vec<HmacSharingParameters> & paramsVec)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 
copyNonces(const hidl_vec<HmacSharingParameters> & paramsVec)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 
verifyResponses(const HidlBuf & expected,const std::vector<ComputeHmacResult> & responses)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 
TEST_F(HmacKeySharingTest,GetParameters)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 
TEST_F(HmacKeySharingTest,ComputeSharedHmac)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:
final_action(F f)146     explicit final_action(F f) : f_(move(f)) {}
~final_action()147     ~final_action() { f_(); }
148 
149    private:
150     F f_;
151 };
152 
153 template <class F>
finally(const F & f)154 inline final_action<F> finally(const F& f) {
155     return final_action<F>(f);
156 }
157 
TEST_F(HmacKeySharingTest,ComputeSharedHmacCorruptNonce)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 
TEST_F(HmacKeySharingTest,ComputeSharedHmacCorruptSeed)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