blob: 842612087f7e60a3afb769a4570fc17ff33dcbe7 [file] [log] [blame]
Chirag Pathak8960aae2021-01-25 21:37:06 +00001/*
2 * Copyright (C) 2020 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#define LOG_TAG "sharedsecret_test"
18#include <android-base/logging.h>
19
20#include <aidl/Vintf.h>
21#include <aidl/android/hardware/security/keymint/ErrorCode.h>
22#include <aidl/android/hardware/security/sharedsecret/ISharedSecret.h>
23#include <android/binder_manager.h>
24#include <gtest/gtest.h>
25#include <vector>
26
27namespace aidl::android::hardware::security::sharedsecret::test {
28using ::aidl::android::hardware::security::keymint::ErrorCode;
29using ::std::shared_ptr;
30using ::std::vector;
31using Status = ::ndk::ScopedAStatus;
32
33class SharedSecretAidlTest : public ::testing::Test {
34 public:
35 struct GetParamsResult {
36 ErrorCode error;
37 SharedSecretParameters params;
38 auto tie() { return std::tie(error, params); }
39 };
40
41 struct ComputeResult {
42 ErrorCode error;
43 vector<uint8_t> sharing_check;
44 auto tie() { return std::tie(error, sharing_check); }
45 };
46
47 GetParamsResult getSharedSecretParameters(shared_ptr<ISharedSecret>& sharedSecret) {
48 SharedSecretParameters params;
49 auto error = GetReturnErrorCode(sharedSecret->getSharedSecretParameters(&params));
50 EXPECT_EQ(ErrorCode::OK, error);
51 GetParamsResult result;
52 result.tie() = std::tie(error, params);
53 return result;
54 }
55
56 vector<SharedSecretParameters> getAllSharedSecretParameters() {
57 vector<SharedSecretParameters> paramsVec;
58 for (auto& sharedSecret : allSharedSecrets_) {
59 auto result = getSharedSecretParameters(sharedSecret);
60 EXPECT_EQ(ErrorCode::OK, result.error);
61 if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
62 }
63 return paramsVec;
64 }
65
66 ComputeResult computeSharedSecret(shared_ptr<ISharedSecret>& sharedSecret,
67 const vector<SharedSecretParameters>& params) {
68 std::vector<uint8_t> sharingCheck;
69 auto error = GetReturnErrorCode(sharedSecret->computeSharedSecret(params, &sharingCheck));
70 ComputeResult result;
71 result.tie() = std::tie(error, sharingCheck);
72 return result;
73 }
74
75 vector<ComputeResult> computeAllSharedSecrets(const vector<SharedSecretParameters>& params) {
76 vector<ComputeResult> result;
77 for (auto& sharedSecret : allSharedSecrets_) {
78 result.push_back(computeSharedSecret(sharedSecret, params));
79 }
80 return result;
81 }
82
83 vector<vector<uint8_t>> copyNonces(const vector<SharedSecretParameters>& paramsVec) {
84 vector<vector<uint8_t>> nonces;
85 for (auto& param : paramsVec) {
86 nonces.push_back(param.nonce);
87 }
88 return nonces;
89 }
90
91 void verifyResponses(const vector<uint8_t>& expected, const vector<ComputeResult>& responses) {
92 for (auto& response : responses) {
93 EXPECT_EQ(ErrorCode::OK, response.error);
94 EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
95 }
96 }
97
98 ErrorCode GetReturnErrorCode(const Status& result) {
99 if (result.isOk()) return ErrorCode::OK;
100 if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
101 return static_cast<ErrorCode>(result.getServiceSpecificError());
102 }
103 return ErrorCode::UNKNOWN_ERROR;
104 }
105
106 static shared_ptr<ISharedSecret> getSharedSecretService(const char* name) {
107 if (AServiceManager_isDeclared(name)) {
108 ::ndk::SpAIBinder binder(AServiceManager_waitForService(name));
109 return ISharedSecret::fromBinder(binder);
110 }
111 return nullptr;
112 }
113
114 const vector<shared_ptr<ISharedSecret>>& allSharedSecrets() { return allSharedSecrets_; }
115
116 static void SetUpTestCase() {
Chirag Pathakf29ce362021-03-17 18:34:59 +0000117 ASSERT_TRUE(allSharedSecrets_.empty()) << "The Shared Secret vector is not empty.";
118 auto names = ::android::getAidlHalInstanceNames(ISharedSecret::descriptor);
119 for (const auto& name : names) {
120 auto servicePtr = getSharedSecretService(name.c_str());
121 if (servicePtr != nullptr) allSharedSecrets_.push_back(std::move(servicePtr));
Chirag Pathak8960aae2021-01-25 21:37:06 +0000122 }
123 }
Chirag Pathakf29ce362021-03-17 18:34:59 +0000124
Chirag Pathak8960aae2021-01-25 21:37:06 +0000125 static void TearDownTestCase() {}
126 void SetUp() override {}
127 void TearDown() override {}
128
129 private:
130 static vector<shared_ptr<ISharedSecret>> allSharedSecrets_;
131};
132
133vector<shared_ptr<ISharedSecret>> SharedSecretAidlTest::allSharedSecrets_;
134
135TEST_F(SharedSecretAidlTest, GetParameters) {
136 auto sharedSecrets = allSharedSecrets();
Chirag Pathakf29ce362021-03-17 18:34:59 +0000137 if (sharedSecrets.empty()) {
138 GTEST_SKIP() << "Skipping the test because no shared secret service is found.";
139 }
Chirag Pathak8960aae2021-01-25 21:37:06 +0000140 for (auto sharedSecret : sharedSecrets) {
141 auto result1 = getSharedSecretParameters(sharedSecret);
142 EXPECT_EQ(ErrorCode::OK, result1.error);
143 auto result2 = getSharedSecretParameters(sharedSecret);
144 EXPECT_EQ(ErrorCode::OK, result2.error);
145 ASSERT_EQ(result1.params.seed, result2.params.seed)
146 << "A given shared secret service should always return the same seed.";
147 ASSERT_EQ(result1.params.nonce, result2.params.nonce)
148 << "A given shared secret service should always return the same nonce until "
149 "restart.";
150 }
151}
152
153TEST_F(SharedSecretAidlTest, ComputeSharedSecret) {
Chirag Pathakf29ce362021-03-17 18:34:59 +0000154 auto sharedSecrets = allSharedSecrets();
155 if (sharedSecrets.empty()) {
156 GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
157 }
Chirag Pathak8960aae2021-01-25 21:37:06 +0000158 auto params = getAllSharedSecretParameters();
Chirag Pathakf29ce362021-03-17 18:34:59 +0000159 ASSERT_EQ(sharedSecrets.size(), params.size())
Chirag Pathak8960aae2021-01-25 21:37:06 +0000160 << "One or more shared secret services failed to provide parameters.";
161 auto nonces = copyNonces(params);
Chirag Pathakf29ce362021-03-17 18:34:59 +0000162 EXPECT_EQ(sharedSecrets.size(), nonces.size());
Chirag Pathak8960aae2021-01-25 21:37:06 +0000163 std::sort(nonces.begin(), nonces.end());
164 std::unique(nonces.begin(), nonces.end());
Chirag Pathakf29ce362021-03-17 18:34:59 +0000165 EXPECT_EQ(sharedSecrets.size(), nonces.size());
Chirag Pathak8960aae2021-01-25 21:37:06 +0000166
167 auto responses = computeAllSharedSecrets(params);
168 ASSERT_GT(responses.size(), 0U);
169 verifyResponses(responses[0].sharing_check, responses);
170
171 // Do it a second time. Should get the same answers.
172 params = getAllSharedSecretParameters();
Chirag Pathakf29ce362021-03-17 18:34:59 +0000173 ASSERT_EQ(sharedSecrets.size(), params.size())
Chirag Pathak8960aae2021-01-25 21:37:06 +0000174 << "One or more shared secret services failed to provide parameters.";
175
176 responses = computeAllSharedSecrets(params);
177 ASSERT_GT(responses.size(), 0U);
178 ASSERT_EQ(32U, responses[0].sharing_check.size());
179 verifyResponses(responses[0].sharing_check, responses);
180}
181
182template <class F>
183class final_action {
184 public:
185 explicit final_action(F f) : f_(std::move(f)) {}
186 ~final_action() { f_(); }
187
188 private:
189 F f_;
190};
191
192template <class F>
193inline final_action<F> finally(const F& f) {
194 return final_action<F>(f);
195}
196
197TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptNonce) {
Chirag Pathakf29ce362021-03-17 18:34:59 +0000198 auto sharedSecrets = allSharedSecrets();
199 if (sharedSecrets.empty()) {
200 GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
201 }
Chirag Pathak8960aae2021-01-25 21:37:06 +0000202 auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
203
204 auto params = getAllSharedSecretParameters();
Chirag Pathakf29ce362021-03-17 18:34:59 +0000205 ASSERT_EQ(sharedSecrets.size(), params.size())
Chirag Pathak8960aae2021-01-25 21:37:06 +0000206 << "One or more shared secret services failed to provide parameters.";
207
208 // All should be well in the normal case
209 auto responses = computeAllSharedSecrets(params);
210
211 ASSERT_GT(responses.size(), 0U);
212 vector<uint8_t> correct_response = responses[0].sharing_check;
213 verifyResponses(correct_response, responses);
214
215 // Pick a random param, a random byte within the param's nonce, and a random bit within
216 // the byte. Flip that bit.
217 size_t param_to_tweak = rand() % params.size();
218 uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
219 uint8_t bit_to_tweak = rand() % 8;
220 params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
221
222 responses = computeAllSharedSecrets(params);
223 for (size_t i = 0; i < responses.size(); ++i) {
224 if (i == param_to_tweak) {
225 EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
226 << "Shared secret service that provided tweaked param should fail to compute "
227 "shared secret";
228 } else {
229 EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
230 EXPECT_NE(correct_response, responses[i].sharing_check)
231 << "Others should calculate a different shared secret, due to the tweaked "
232 "nonce.";
233 }
234 }
235}
236
237TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptSeed) {
Chirag Pathakf29ce362021-03-17 18:34:59 +0000238 auto sharedSecrets = allSharedSecrets();
239 if (sharedSecrets.empty()) {
240 GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
241 }
Chirag Pathak8960aae2021-01-25 21:37:06 +0000242 auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
243 auto params = getAllSharedSecretParameters();
Chirag Pathakf29ce362021-03-17 18:34:59 +0000244 ASSERT_EQ(sharedSecrets.size(), params.size())
Chirag Pathak8960aae2021-01-25 21:37:06 +0000245 << "One or more shared secret service failed to provide parameters.";
246
247 // All should be well in the normal case
248 auto responses = computeAllSharedSecrets(params);
249
250 ASSERT_GT(responses.size(), 0U);
251 vector<uint8_t> correct_response = responses[0].sharing_check;
252 verifyResponses(correct_response, responses);
253
254 // Pick a random param and modify the seed. We just increase the seed length by 1. It doesn't
255 // matter what value is in the additional byte; it changes the seed regardless.
256 auto param_to_tweak = rand() % params.size();
257 auto& to_tweak = params[param_to_tweak].seed;
258 ASSERT_TRUE(to_tweak.size() == 32 || to_tweak.size() == 0);
259 if (!to_tweak.size()) {
260 to_tweak.resize(32); // Contents don't matter; a little randomization is nice.
261 }
262 to_tweak[0]++;
263
264 responses = computeAllSharedSecrets(params);
265 for (size_t i = 0; i < responses.size(); ++i) {
266 if (i == param_to_tweak) {
267 EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
268 << "Shared secret service that provided tweaked param should fail to compute "
269 "shared secret";
270 } else {
271 EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
272 EXPECT_NE(correct_response, responses[i].sharing_check)
273 << "Others should calculate a different shared secret, due to the tweaked "
274 "nonce.";
275 }
276 }
277}
278} // namespace aidl::android::hardware::security::sharedsecret::test
279
280int main(int argc, char** argv) {
281 ::testing::InitGoogleTest(&argc, argv);
282 return RUN_ALL_TESTS();
283}