blob: 96c47a8d905e77c3066f0c9ba1e4df9e6b6336cf [file] [log] [blame]
Shawn Willden3d943322018-01-02 18:55:47 -07001/*
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
19namespace android {
20namespace hardware {
21namespace keymaster {
22namespace V4_0 {
23namespace test {
24
25/**
26 * HmacKeySharingTest extends KeymasterHidlTest with some utilities that make writing HMAC sharing
27 * tests easier.
28 */
29class 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
104TEST_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
117TEST_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 verifyResponses(responses[0].sharing_check, responses);
140}
141
142template <class F>
143class final_action {
144 public:
145 explicit final_action(F f) : f_(move(f)) {}
146 ~final_action() { f_(); }
147
148 private:
149 F f_;
150};
151
152template <class F>
153inline final_action<F> finally(const F& f) {
154 return final_action<F>(f);
155}
156
157TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
158 // Important: The execution of this test gets the keymaster implementations on the device out of
159 // sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
160 // devices, this still has the potential to cause confusion. To mitigate that, we always
161 // (barring crashes :-/) re-run the unmodified agreement process on our way out.
162 auto fixup_hmac = finally(
163 [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
164
165 auto params = getHmacSharingParameters(all_keymasters());
166 ASSERT_EQ(all_keymasters().size(), params.size())
167 << "One or more keymasters failed to provide parameters.";
168
169 // All should be well in the normal case
170 auto responses = computeSharedHmac(all_keymasters(), params);
171
172 ASSERT_GT(responses.size(), 0U);
173 HidlBuf correct_response = responses[0].sharing_check;
174 verifyResponses(correct_response, responses);
175
176 // Pick a random param, a random byte within the param's nonce, and a random bit within
177 // the byte. Flip that bit.
178 size_t param_to_tweak = rand() % params.size();
179 uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
180 uint8_t bit_to_tweak = rand() % 8;
181 params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
182
183 responses = computeSharedHmac(all_keymasters(), params);
184 for (size_t i = 0; i < responses.size(); ++i) {
185 if (i == param_to_tweak) {
186 EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
187 << "Keymaster that provided tweaked param should fail to compute HMAC key";
188 } else {
189 EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
190 EXPECT_NE(correct_response, responses[i].sharing_check)
191 << "Others should calculate a different HMAC key, due to the tweaked nonce.";
192 }
193 }
194}
195
196TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
197 // Important: The execution of this test gets the keymaster implementations on the device out of
198 // sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
199 // devices, this still has the potential to cause confusion. To mitigate that, we always
200 // (barring crashes :-/) re-run the unmodified agreement process on our way out.
201 auto fixup_hmac = finally(
202 [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
203
204 auto params = getHmacSharingParameters(all_keymasters());
205 ASSERT_EQ(all_keymasters().size(), params.size())
206 << "One or more keymasters failed to provide parameters.";
207
208 // All should be well in the normal case
209 auto responses = computeSharedHmac(all_keymasters(), params);
210
211 ASSERT_GT(responses.size(), 0U);
212 HidlBuf correct_response = responses[0].sharing_check;
213 verifyResponses(correct_response, responses);
214
215 // Pick a random param and modify the seed. We just increase the seed length by 1. It doesn't
216 // matter what value is in the additional byte; it changes the seed regardless.
217 auto param_to_tweak = rand() % params.size();
218 auto& to_tweak = params[param_to_tweak].seed;
219 to_tweak.resize(to_tweak.size() + 1);
220
221 responses = computeSharedHmac(all_keymasters(), params);
222 for (size_t i = 0; i < responses.size(); ++i) {
223 if (i == param_to_tweak) {
224 EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
225 << "Keymaster that provided tweaked param should fail to compute HMAC key ";
226 } else {
227 EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
228 EXPECT_NE(correct_response, responses[i].sharing_check)
229 << "Others should calculate a different HMAC key, due to the tweaked nonce.";
230 }
231 }
232}
233
234} // namespace test
235} // namespace V4_0
236} // namespace keymaster
237} // namespace hardware
238} // namespace android