1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16
17 #include "tink/primitive_set.h"
18
19 #include <memory>
20 #include <string>
21 #include <thread> // NOLINT(build/c++11)
22 #include <utility>
23 #include <vector>
24
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "tink/cleartext_keyset_handle.h"
28 #include "tink/crypto_format.h"
29 #include "tink/keyderivation/keyset_deriver.h"
30 #include "tink/mac.h"
31 #include "tink/util/test_matchers.h"
32 #include "tink/util/test_util.h"
33 #include "proto/tink.pb.h"
34
35 using ::crypto::tink::test::DummyMac;
36 using ::crypto::tink::test::IsOk;
37 using ::google::crypto::tink::Keyset;
38 using ::google::crypto::tink::KeysetInfo;
39 using ::google::crypto::tink::KeyStatusType;
40 using ::google::crypto::tink::OutputPrefixType;
41 using ::testing::Eq;
42 using ::testing::SizeIs;
43 using ::testing::UnorderedElementsAreArray;
44
45 namespace crypto {
46 namespace tink {
47 namespace {
48
49 class PrimitiveSetTest : public ::testing::Test {};
50
add_primitives(PrimitiveSet<Mac> * primitive_set,int key_id_offset,int primitives_count)51 void add_primitives(PrimitiveSet<Mac>* primitive_set, int key_id_offset,
52 int primitives_count) {
53 for (int i = 0; i < primitives_count; i++) {
54 int key_id = key_id_offset + i;
55 KeysetInfo::KeyInfo key_info;
56 key_info.set_output_prefix_type(OutputPrefixType::TINK);
57 key_info.set_key_id(key_id);
58 key_info.set_status(KeyStatusType::ENABLED);
59 std::unique_ptr<Mac> mac(new DummyMac("dummy MAC"));
60 auto add_result = primitive_set->AddPrimitive(std::move(mac), key_info);
61 EXPECT_TRUE(add_result.ok()) << add_result.status();
62 }
63 }
64
add_primitives(PrimitiveSet<Mac>::Builder * primitive_set_builder,int key_id_offset,int primitives_count)65 void add_primitives(PrimitiveSet<Mac>::Builder* primitive_set_builder,
66 int key_id_offset, int primitives_count) {
67 for (int i = 0; i < primitives_count; i++) {
68 int key_id = key_id_offset + i;
69 KeysetInfo::KeyInfo key_info;
70 key_info.set_output_prefix_type(OutputPrefixType::TINK);
71 key_info.set_key_id(key_id);
72 key_info.set_status(KeyStatusType::ENABLED);
73 std::unique_ptr<Mac> mac(new DummyMac("dummy MAC"));
74 primitive_set_builder->AddPrimitive(std::move(mac), key_info);
75 }
76 }
77
access_primitives(PrimitiveSet<Mac> * primitive_set,int key_id_offset,int primitives_count)78 void access_primitives(PrimitiveSet<Mac>* primitive_set, int key_id_offset,
79 int primitives_count) {
80 for (int i = 0; i < primitives_count; i++) {
81 int key_id = key_id_offset + i;
82 KeysetInfo::KeyInfo key_info;
83 key_info.set_output_prefix_type(OutputPrefixType::TINK);
84 key_info.set_key_id(key_id);
85 key_info.set_status(KeyStatusType::ENABLED);
86 std::string prefix = CryptoFormat::GetOutputPrefix(key_info).value();
87 auto get_result = primitive_set->get_primitives(prefix);
88 EXPECT_TRUE(get_result.ok()) << get_result.status();
89 EXPECT_GE(get_result.value()->size(), 1);
90 }
91 }
92
TEST_F(PrimitiveSetTest,ConcurrentOperations)93 TEST_F(PrimitiveSetTest, ConcurrentOperations) {
94 PrimitiveSet<Mac>::Builder mac_set_builder;
95 int offset_a = 100;
96 int offset_b = 150;
97 int count = 100;
98
99 // Add some primitives.
100 // See go/totw/133 on why we use a lambda here.
101 std::thread add_primitives_a(
102 [&]() { add_primitives(&mac_set_builder, offset_a, count); });
103 std::thread add_primitives_b(
104 [&]() { add_primitives(&mac_set_builder, offset_b, count); });
105 add_primitives_a.join();
106 add_primitives_b.join();
107
108 auto mac_set_result = std::move(mac_set_builder).Build();
109 ASSERT_TRUE(mac_set_result.ok()) << mac_set_result.status();
110 PrimitiveSet<Mac> mac_set = std::move(mac_set_result.value());
111
112 // Access primitives.
113 std::thread access_primitives_a(access_primitives, &mac_set, offset_a, count);
114 std::thread access_primitives_b(access_primitives, &mac_set, offset_b, count);
115 access_primitives_a.join();
116 access_primitives_b.join();
117
118 // Verify the common key ids added by both threads.
119 for (int key_id = offset_a; key_id < offset_b + count; key_id++) {
120 KeysetInfo::KeyInfo key_info;
121 key_info.set_output_prefix_type(OutputPrefixType::TINK);
122 key_info.set_key_id(key_id);
123 key_info.set_status(KeyStatusType::ENABLED);
124 std::string prefix = CryptoFormat::GetOutputPrefix(key_info).value();
125 auto get_result = mac_set.get_primitives(prefix);
126 EXPECT_TRUE(get_result.ok()) << get_result.status();
127 auto macs = get_result.value();
128 if (key_id >= offset_b && key_id < offset_a + count) {
129 EXPECT_EQ(2, macs->size()); // overlapping key_id range
130 } else {
131 EXPECT_EQ(1, macs->size());
132 }
133 }
134 }
135
TEST_F(PrimitiveSetTest,Basic)136 TEST_F(PrimitiveSetTest, Basic) {
137 std::string mac_name_1 = "MAC#1";
138 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
139 std::string mac_name_2 = "MAC#2";
140 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
141 std::string mac_name_3 = "MAC#3";
142 std::unique_ptr<Mac> mac_3(new DummyMac(mac_name_3));
143 std::string mac_name_4 = "MAC#3";
144 std::unique_ptr<Mac> mac_4(new DummyMac(mac_name_4));
145 std::string mac_name_5 = "MAC#3";
146 std::unique_ptr<Mac> mac_5(new DummyMac(mac_name_5));
147 std::string mac_name_6 = "MAC#3";
148 std::unique_ptr<Mac> mac_6(new DummyMac(mac_name_6));
149
150 uint32_t key_id_1 = 1234543;
151 KeysetInfo::KeyInfo key_1;
152 key_1.set_output_prefix_type(OutputPrefixType::TINK);
153 key_1.set_key_id(key_id_1);
154 key_1.set_status(KeyStatusType::ENABLED);
155
156 uint32_t key_id_2 = 7213743;
157 KeysetInfo::KeyInfo key_2;
158 key_2.set_output_prefix_type(OutputPrefixType::LEGACY);
159 key_2.set_key_id(key_id_2);
160 key_2.set_status(KeyStatusType::ENABLED);
161
162 uint32_t key_id_3 = key_id_2; // same id as key_2
163 KeysetInfo::KeyInfo key_3;
164 key_3.set_output_prefix_type(OutputPrefixType::TINK);
165 key_3.set_key_id(key_id_3);
166 key_3.set_status(KeyStatusType::ENABLED);
167
168 uint32_t key_id_4 = 947327;
169 KeysetInfo::KeyInfo key_4;
170 key_4.set_output_prefix_type(OutputPrefixType::RAW);
171 key_4.set_key_id(key_id_4);
172 key_4.set_status(KeyStatusType::ENABLED);
173
174 uint32_t key_id_5 = 529472;
175 KeysetInfo::KeyInfo key_5;
176 key_5.set_output_prefix_type(OutputPrefixType::RAW);
177 key_5.set_key_id(key_id_5);
178 key_5.set_status(KeyStatusType::ENABLED);
179
180 uint32_t key_id_6 = key_id_1; // same id as key_1
181 KeysetInfo::KeyInfo key_6;
182 key_6.set_output_prefix_type(OutputPrefixType::TINK);
183 key_6.set_key_id(key_id_6);
184 key_6.set_status(KeyStatusType::ENABLED);
185
186 PrimitiveSet<Mac>::Builder primitive_set_builder;
187
188 // Add all the primitives.
189 auto primitive_set_result = PrimitiveSet<Mac>::Builder{}
190 .AddPrimitive(std::move(mac_1), key_1)
191 .AddPrimitive(std::move(mac_2), key_2)
192 .AddPrimaryPrimitive(std::move(mac_3), key_3)
193 .AddPrimitive(std::move(mac_4), key_4)
194 .AddPrimitive(std::move(mac_5), key_5)
195 .AddPrimitive(std::move(mac_6), key_6)
196 .Build();
197
198 ASSERT_TRUE(primitive_set_result.ok()) << primitive_set_result.status();
199 PrimitiveSet<Mac> primitive_set = std::move(primitive_set_result.value());
200
201 std::string data = "some data";
202
203 { // Check the primary.
204 auto primary = primitive_set.get_primary();
205 EXPECT_FALSE(primary == nullptr);
206 EXPECT_EQ(KeyStatusType::ENABLED, primary->get_status());
207 EXPECT_EQ(DummyMac(mac_name_3).ComputeMac(data).value(),
208 primary->get_primitive().ComputeMac(data).value());
209 }
210
211 { // Check raw primitives.
212 auto& primitives = *(primitive_set.get_raw_primitives().value());
213 EXPECT_EQ(2, primitives.size());
214 EXPECT_EQ(DummyMac(mac_name_4).ComputeMac(data).value(),
215 primitives[0]->get_primitive().ComputeMac(data).value());
216 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
217 EXPECT_EQ(key_4.key_id(), primitives[0]->get_key_id());
218 EXPECT_EQ(OutputPrefixType::RAW, primitives[0]->get_output_prefix_type());
219 EXPECT_EQ(DummyMac(mac_name_5).ComputeMac(data).value(),
220 primitives[1]->get_primitive().ComputeMac(data).value());
221 EXPECT_EQ(KeyStatusType::ENABLED, primitives[1]->get_status());
222 EXPECT_EQ(key_5.key_id(), primitives[1]->get_key_id());
223 EXPECT_EQ(OutputPrefixType::RAW, primitives[1]->get_output_prefix_type());
224 }
225
226 { // Check Tink primitives.
227 std::string prefix = CryptoFormat::GetOutputPrefix(key_1).value();
228 auto& primitives = *(primitive_set.get_primitives(prefix).value());
229 EXPECT_EQ(2, primitives.size());
230 EXPECT_EQ(DummyMac(mac_name_1).ComputeMac(data).value(),
231 primitives[0]->get_primitive().ComputeMac(data).value());
232 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
233 EXPECT_EQ(key_1.key_id(), primitives[0]->get_key_id());
234 EXPECT_EQ(OutputPrefixType::TINK, primitives[0]->get_output_prefix_type());
235 EXPECT_EQ(DummyMac(mac_name_6).ComputeMac(data).value(),
236 primitives[1]->get_primitive().ComputeMac(data).value());
237 EXPECT_EQ(KeyStatusType::ENABLED, primitives[1]->get_status());
238 EXPECT_EQ(key_1.key_id(), primitives[1]->get_key_id());
239 EXPECT_EQ(OutputPrefixType::TINK, primitives[1]->get_output_prefix_type());
240 }
241
242 { // Check another Tink primitive.
243 std::string prefix = CryptoFormat::GetOutputPrefix(key_3).value();
244 auto& primitives = *(primitive_set.get_primitives(prefix).value());
245 EXPECT_EQ(1, primitives.size());
246 EXPECT_EQ(DummyMac(mac_name_3).ComputeMac(data).value(),
247 primitives[0]->get_primitive().ComputeMac(data).value());
248 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
249 EXPECT_EQ(key_3.key_id(), primitives[0]->get_key_id());
250 EXPECT_EQ(OutputPrefixType::TINK, primitives[0]->get_output_prefix_type());
251 }
252
253 { // Check legacy primitive.
254 std::string prefix = CryptoFormat::GetOutputPrefix(key_2).value();
255 auto& primitives = *(primitive_set.get_primitives(prefix).value());
256 EXPECT_EQ(1, primitives.size());
257 EXPECT_EQ(DummyMac(mac_name_2).ComputeMac(data).value(),
258 primitives[0]->get_primitive().ComputeMac(data).value());
259 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
260 EXPECT_EQ(key_2.key_id(), primitives[0]->get_key_id());
261 EXPECT_EQ(OutputPrefixType::LEGACY,
262 primitives[0]->get_output_prefix_type());
263 }
264 }
265
TEST_F(PrimitiveSetTest,PrimaryKeyWithIdCollisions)266 TEST_F(PrimitiveSetTest, PrimaryKeyWithIdCollisions) {
267 std::string mac_name_1 = "MAC#1";
268 std::string mac_name_2 = "MAC#2";
269
270 uint32_t key_id_1 = 1234543;
271 KeysetInfo::KeyInfo key_info_1;
272 key_info_1.set_key_id(key_id_1);
273 key_info_1.set_status(KeyStatusType::ENABLED);
274
275 uint32_t key_id_2 = key_id_1; // same id as key_2
276 KeysetInfo::KeyInfo key_info_2;
277 key_info_2.set_key_id(key_id_2);
278 key_info_2.set_status(KeyStatusType::ENABLED);
279
280 { // Test with RAW-keys.
281 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
282 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
283 key_info_1.set_output_prefix_type(OutputPrefixType::RAW);
284 key_info_2.set_output_prefix_type(OutputPrefixType::RAW);
285 PrimitiveSet<Mac>::Builder primitive_set_builder;
286
287 // Add the first primitive, and set it as primary.
288 primitive_set_builder.AddPrimaryPrimitive(std::move(mac_1), key_info_1);
289
290 auto primitive_set_result = std::move(primitive_set_builder).Build();
291 ASSERT_TRUE(primitive_set_result.ok()) << primitive_set_result.status();
292 PrimitiveSet<Mac> primitive_set = std::move(primitive_set_result.value());
293
294 std::string identifier = "";
295 const auto& primitives =
296 *(primitive_set.get_primitives(identifier).value());
297 EXPECT_EQ(1, primitives.size());
298 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
299 }
300
301 { // Test with TINK-keys.
302 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
303 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
304 key_info_1.set_output_prefix_type(OutputPrefixType::TINK);
305 key_info_2.set_output_prefix_type(OutputPrefixType::TINK);
306 PrimitiveSet<Mac>::Builder primitive_set_builder;
307
308 // Add the first primitive, and set it as primary.
309 primitive_set_builder.AddPrimaryPrimitive(std::move(mac_1), key_info_1);
310
311 auto primitive_set_result = std::move(primitive_set_builder).Build();
312 ASSERT_TRUE(primitive_set_result.ok()) << primitive_set_result.status();
313 PrimitiveSet<Mac> primitive_set = std::move(primitive_set_result.value());
314 std::string identifier = CryptoFormat::GetOutputPrefix(key_info_1).value();
315 const auto& primitives =
316 *(primitive_set.get_primitives(identifier).value());
317 EXPECT_EQ(1, primitives.size());
318 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
319 }
320
321 { // Test with LEGACY-keys.
322 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
323 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
324 key_info_1.set_output_prefix_type(OutputPrefixType::LEGACY);
325 key_info_2.set_output_prefix_type(OutputPrefixType::LEGACY);
326 PrimitiveSet<Mac>::Builder primitive_set_builder;
327
328 // Add the first primitive, and set it as primary.
329 primitive_set_builder.AddPrimaryPrimitive(std::move(mac_1), key_info_1);
330
331 auto primitive_set_result = std::move(primitive_set_builder).Build();
332 ASSERT_TRUE(primitive_set_result.ok()) << primitive_set_result.status();
333 PrimitiveSet<Mac> primitive_set = std::move(primitive_set_result.value());
334 std::string identifier = CryptoFormat::GetOutputPrefix(key_info_1).value();
335 const auto& primitives =
336 *(primitive_set.get_primitives(identifier).value());
337 EXPECT_EQ(1, primitives.size());
338 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
339 }
340 }
341
TEST_F(PrimitiveSetTest,DisabledKey)342 TEST_F(PrimitiveSetTest, DisabledKey) {
343 std::string mac_name_1 = "MAC#1";
344 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
345
346 uint32_t key_id_1 = 1234543;
347 KeysetInfo::KeyInfo key_info_1;
348 key_info_1.set_output_prefix_type(OutputPrefixType::TINK);
349 key_info_1.set_key_id(key_id_1);
350 key_info_1.set_status(KeyStatusType::DISABLED);
351
352 // Add all the primitives.
353 auto add_primitive_result = PrimitiveSet<Mac>::Builder{}
354 .AddPrimitive(std::move(mac_1), key_info_1)
355 .Build();
356 EXPECT_FALSE(add_primitive_result.ok());
357 }
358
CreateKey(uint32_t key_id,OutputPrefixType output_prefix_type,KeyStatusType key_status,absl::string_view type_url)359 KeysetInfo::KeyInfo CreateKey(uint32_t key_id,
360 OutputPrefixType output_prefix_type,
361 KeyStatusType key_status,
362 absl::string_view type_url) {
363 KeysetInfo::KeyInfo key_info;
364 key_info.set_output_prefix_type(output_prefix_type);
365 key_info.set_key_id(key_id);
366 key_info.set_status(key_status);
367 std::string type_url_str(type_url);
368 key_info.set_type_url(type_url_str);
369 return key_info;
370 }
371
372 // Struct to hold MAC, Id and type_url.
373 struct MacIdAndTypeUrl {
374 std::string mac;
375 std::string id;
376 std::string type_url;
377 };
378
operator ==(const MacIdAndTypeUrl & first,const MacIdAndTypeUrl & other)379 bool operator==(const MacIdAndTypeUrl& first, const MacIdAndTypeUrl& other) {
380 return first.mac == other.mac && first.id == other.id &&
381 first.type_url == other.type_url;
382 }
383
TEST_F(PrimitiveSetTest,GetAll)384 TEST_F(PrimitiveSetTest, GetAll) {
385 auto pset_result =
386 PrimitiveSet<Mac>::Builder{}
387 .AddPrimitive(
388 absl::make_unique<DummyMac>("MAC1"),
389 CreateKey(0x01010101, OutputPrefixType::TINK,
390 KeyStatusType::ENABLED, /*type_url=*/
391 "type.googleapis.com/google.crypto.tink.HmacKey"))
392 .AddPrimitive(
393 absl::make_unique<DummyMac>("MAC2"),
394 CreateKey(0x02020202, OutputPrefixType::TINK,
395 KeyStatusType::ENABLED, /*type_url=*/
396 "type.googleapis.com/google.crypto.tink.HmacKey"))
397 // Add primitive and make it primary.
398 .AddPrimaryPrimitive(
399 absl::make_unique<DummyMac>("MAC3"),
400 CreateKey(0x02020202, OutputPrefixType::TINK,
401 KeyStatusType::ENABLED, /*type_url=*/
402 "type.googleapis.com/google.crypto.tink.AesCmacKey"))
403 .AddPrimitive(
404 absl::make_unique<DummyMac>("MAC4"),
405 CreateKey(0x02020202, OutputPrefixType::RAW,
406 KeyStatusType::ENABLED, /*type_url=*/
407 "type.googleapis.com/google.crypto.tink.AesCmacKey"))
408 .AddPrimitive(
409 absl::make_unique<DummyMac>("MAC5"),
410 CreateKey(0x01010101, OutputPrefixType::TINK,
411 KeyStatusType::ENABLED, /*type_url=*/
412 "type.googleapis.com/google.crypto.tink.AesCmacKey"))
413 .Build();
414
415 ASSERT_TRUE(pset_result.ok()) << pset_result.status();
416 PrimitiveSet<Mac> pset = std::move(pset_result.value());
417
418 std::vector<MacIdAndTypeUrl> mac_id_and_type;
419 for (auto* entry : pset.get_all()) {
420 auto mac_or = entry->get_primitive().ComputeMac("");
421 ASSERT_THAT(mac_or, IsOk());
422 mac_id_and_type.push_back({mac_or.value(), entry->get_identifier(),
423 std::string(entry->get_key_type_url())});
424 }
425
426 // In the following id part, the first byte is 1 for Tink.
427 std::vector<MacIdAndTypeUrl> expected_result = {
428 {/*mac=*/"13:0:DummyMac:MAC1", /*id=*/absl::StrCat("\1\1\1\1\1"),
429 /*type_url=*/"type.googleapis.com/google.crypto.tink.HmacKey"},
430 {/*mac=*/"13:0:DummyMac:MAC2", /*id=*/absl::StrCat("\1\2\2\2\2"),
431 /*type_url=*/"type.googleapis.com/google.crypto.tink.HmacKey"},
432 {/*mac=*/"13:0:DummyMac:MAC3", /*id=*/absl::StrCat("\1\2\2\2\2"),
433 /*type_url=*/"type.googleapis.com/google.crypto.tink.AesCmacKey"},
434 {/*mac=*/"13:0:DummyMac:MAC4", /*id=*/"",
435 /*type_url=*/"type.googleapis.com/google.crypto.tink.AesCmacKey"},
436 {/*mac=*/"13:0:DummyMac:MAC5", /*id=*/absl::StrCat("\1\1\1\1\1"),
437 /*type_url=*/"type.googleapis.com/google.crypto.tink.AesCmacKey"}};
438
439 EXPECT_THAT(mac_id_and_type, UnorderedElementsAreArray(expected_result));
440 }
441
442 class FakeDeriver : public KeysetDeriver {
443 public:
444 explicit FakeDeriver() = default;
DeriveKeyset(absl::string_view salt) const445 crypto::tink::util::StatusOr<std::unique_ptr<KeysetHandle>> DeriveKeyset(
446 absl::string_view salt) const override {
447 Keyset keyset;
448 return CleartextKeysetHandle::GetKeysetHandle(keyset);
449 }
450 };
451
TEST_F(PrimitiveSetTest,GetAllInKeysetOrder)452 TEST_F(PrimitiveSetTest, GetAllInKeysetOrder) {
453 auto pset = absl::make_unique<PrimitiveSet<KeysetDeriver>>();
454 std::vector<KeysetInfo::KeyInfo> key_infos;
455
456 KeysetInfo::KeyInfo key_info;
457 key_info.set_key_id(1010101);
458 key_info.set_status(KeyStatusType::ENABLED);
459 key_info.set_output_prefix_type(OutputPrefixType::RAW);
460 key_info.set_type_url(
461 "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey");
462 ASSERT_THAT(pset->AddPrimitive(absl::make_unique<FakeDeriver>(), key_info),
463 IsOk());
464 key_infos.push_back(key_info);
465
466 key_info.set_key_id(2020202);
467 key_info.set_status(KeyStatusType::ENABLED);
468 key_info.set_output_prefix_type(OutputPrefixType::LEGACY);
469 key_info.set_type_url(
470 "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey");
471 ASSERT_THAT(pset->AddPrimitive(absl::make_unique<FakeDeriver>(), key_info),
472 IsOk());
473 key_infos.push_back(key_info);
474
475 key_info.set_key_id(3030303);
476 key_info.set_status(KeyStatusType::ENABLED);
477 key_info.set_output_prefix_type(OutputPrefixType::TINK);
478 key_info.set_type_url(
479 "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey");
480 ASSERT_THAT(pset->AddPrimitive(absl::make_unique<FakeDeriver>(), key_info),
481 IsOk());
482 key_infos.push_back(key_info);
483
484 std::vector<PrimitiveSet<KeysetDeriver>::Entry<KeysetDeriver>*> entries =
485 pset->get_all_in_keyset_order();
486 ASSERT_THAT(entries, SizeIs(key_infos.size()));
487
488 for (int i = 0; i < entries.size(); i++) {
489 EXPECT_THAT(entries[i]->get_identifier(),
490 Eq(*CryptoFormat::GetOutputPrefix(key_infos[i])));
491 EXPECT_THAT(entries[i]->get_status(), Eq(KeyStatusType::ENABLED));
492 EXPECT_THAT(entries[i]->get_key_id(), Eq(key_infos[i].key_id()));
493 EXPECT_THAT(entries[i]->get_output_prefix_type(),
494 Eq(key_infos[i].output_prefix_type()));
495 EXPECT_THAT(entries[i]->get_key_type_url(), Eq(key_infos[i].type_url()));
496 }
497 }
498
TEST_F(PrimitiveSetTest,LegacyConcurrentOperations)499 TEST_F(PrimitiveSetTest, LegacyConcurrentOperations) {
500 PrimitiveSet<Mac> mac_set;
501 int offset_a = 100;
502 int offset_b = 150;
503 int count = 100;
504
505 // Add some primitives.
506 std::thread add_primitives_a(
507 [&]() { add_primitives(&mac_set, offset_a, count); });
508 std::thread add_primitives_b(
509 [&]() { add_primitives(&mac_set, offset_b, count); });
510 add_primitives_a.join();
511 add_primitives_b.join();
512
513 // Access primitives.
514 std::thread access_primitives_a(access_primitives, &mac_set, offset_a, count);
515 std::thread access_primitives_b(access_primitives, &mac_set, offset_b, count);
516 access_primitives_a.join();
517 access_primitives_b.join();
518
519 // Verify the common key ids added by both threads.
520 for (int key_id = offset_a; key_id < offset_b + count; key_id++) {
521 KeysetInfo::KeyInfo key_info;
522 key_info.set_output_prefix_type(OutputPrefixType::TINK);
523 key_info.set_key_id(key_id);
524 key_info.set_status(KeyStatusType::ENABLED);
525 std::string prefix = CryptoFormat::GetOutputPrefix(key_info).value();
526 auto get_result = mac_set.get_primitives(prefix);
527 EXPECT_TRUE(get_result.ok()) << get_result.status();
528 auto macs = get_result.value();
529 if (key_id >= offset_b && key_id < offset_a + count) {
530 EXPECT_EQ(2, macs->size()); // overlapping key_id range
531 } else {
532 EXPECT_EQ(1, macs->size());
533 }
534 }
535 }
536
TEST_F(PrimitiveSetTest,LegacyBasic)537 TEST_F(PrimitiveSetTest, LegacyBasic) {
538 std::string mac_name_1 = "MAC#1";
539 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
540 std::string mac_name_2 = "MAC#2";
541 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
542 std::string mac_name_3 = "MAC#3";
543 std::unique_ptr<Mac> mac_3(new DummyMac(mac_name_3));
544 std::string mac_name_4 = "MAC#3";
545 std::unique_ptr<Mac> mac_4(new DummyMac(mac_name_4));
546 std::string mac_name_5 = "MAC#3";
547 std::unique_ptr<Mac> mac_5(new DummyMac(mac_name_5));
548 std::string mac_name_6 = "MAC#3";
549 std::unique_ptr<Mac> mac_6(new DummyMac(mac_name_6));
550
551 uint32_t key_id_1 = 1234543;
552 KeysetInfo::KeyInfo key_1;
553 key_1.set_output_prefix_type(OutputPrefixType::TINK);
554 key_1.set_key_id(key_id_1);
555 key_1.set_status(KeyStatusType::ENABLED);
556
557 uint32_t key_id_2 = 7213743;
558 KeysetInfo::KeyInfo key_2;
559 key_2.set_output_prefix_type(OutputPrefixType::LEGACY);
560 key_2.set_key_id(key_id_2);
561 key_2.set_status(KeyStatusType::ENABLED);
562
563 uint32_t key_id_3 = key_id_2; // same id as key_2
564 KeysetInfo::KeyInfo key_3;
565 key_3.set_output_prefix_type(OutputPrefixType::TINK);
566 key_3.set_key_id(key_id_3);
567 key_3.set_status(KeyStatusType::ENABLED);
568
569 uint32_t key_id_4 = 947327;
570 KeysetInfo::KeyInfo key_4;
571 key_4.set_output_prefix_type(OutputPrefixType::RAW);
572 key_4.set_key_id(key_id_4);
573 key_4.set_status(KeyStatusType::ENABLED);
574
575 uint32_t key_id_5 = 529472;
576 KeysetInfo::KeyInfo key_5;
577 key_5.set_output_prefix_type(OutputPrefixType::RAW);
578 key_5.set_key_id(key_id_5);
579 key_5.set_status(KeyStatusType::ENABLED);
580
581 uint32_t key_id_6 = key_id_1; // same id as key_1
582 KeysetInfo::KeyInfo key_6;
583 key_6.set_output_prefix_type(OutputPrefixType::TINK);
584 key_6.set_key_id(key_id_6);
585 key_6.set_status(KeyStatusType::ENABLED);
586
587 PrimitiveSet<Mac> primitive_set;
588 EXPECT_TRUE(primitive_set.get_primary() == nullptr);
589 EXPECT_EQ(absl::StatusCode::kNotFound,
590 primitive_set.get_raw_primitives().status().code());
591 EXPECT_EQ(absl::StatusCode::kNotFound,
592 primitive_set.get_primitives("prefix").status().code());
593
594 // Add all the primitives.
595 auto add_primitive_result =
596 primitive_set.AddPrimitive(std::move(mac_1), key_1);
597 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
598
599 add_primitive_result = primitive_set.AddPrimitive(std::move(mac_2), key_2);
600 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
601
602 add_primitive_result = primitive_set.AddPrimitive(std::move(mac_3), key_3);
603 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
604 EXPECT_THAT(primitive_set.set_primary(add_primitive_result.value()), IsOk());
605
606 add_primitive_result = primitive_set.AddPrimitive(std::move(mac_4), key_4);
607 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
608
609 add_primitive_result = primitive_set.AddPrimitive(std::move(mac_5), key_5);
610 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
611
612 add_primitive_result = primitive_set.AddPrimitive(std::move(mac_6), key_6);
613 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
614
615 // Try adding a "consumed" unique_ptr as a primitive.
616 add_primitive_result = primitive_set.AddPrimitive(std::move(mac_6), key_6);
617 EXPECT_FALSE(add_primitive_result.ok());
618 EXPECT_EQ(absl::StatusCode::kInvalidArgument,
619 add_primitive_result.status().code());
620
621 std::string data = "some data";
622
623 { // Check the primary.
624 auto primary = primitive_set.get_primary();
625 EXPECT_FALSE(primary == nullptr);
626 EXPECT_EQ(KeyStatusType::ENABLED, primary->get_status());
627 EXPECT_EQ(DummyMac(mac_name_3).ComputeMac(data).value(),
628 primary->get_primitive().ComputeMac(data).value());
629 }
630
631 { // Check raw primitives.
632 auto& primitives = *(primitive_set.get_raw_primitives().value());
633 EXPECT_EQ(2, primitives.size());
634 EXPECT_EQ(DummyMac(mac_name_4).ComputeMac(data).value(),
635 primitives[0]->get_primitive().ComputeMac(data).value());
636 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
637 EXPECT_EQ(key_4.key_id(), primitives[0]->get_key_id());
638 EXPECT_EQ(OutputPrefixType::RAW, primitives[0]->get_output_prefix_type());
639 EXPECT_EQ(DummyMac(mac_name_5).ComputeMac(data).value(),
640 primitives[1]->get_primitive().ComputeMac(data).value());
641 EXPECT_EQ(KeyStatusType::ENABLED, primitives[1]->get_status());
642 EXPECT_EQ(key_5.key_id(), primitives[1]->get_key_id());
643 EXPECT_EQ(OutputPrefixType::RAW, primitives[1]->get_output_prefix_type());
644 }
645
646 { // Check Tink primitives.
647 std::string prefix = CryptoFormat::GetOutputPrefix(key_1).value();
648 auto& primitives = *(primitive_set.get_primitives(prefix).value());
649 EXPECT_EQ(2, primitives.size());
650 EXPECT_EQ(DummyMac(mac_name_1).ComputeMac(data).value(),
651 primitives[0]->get_primitive().ComputeMac(data).value());
652 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
653 EXPECT_EQ(key_1.key_id(), primitives[0]->get_key_id());
654 EXPECT_EQ(OutputPrefixType::TINK, primitives[0]->get_output_prefix_type());
655 EXPECT_EQ(DummyMac(mac_name_6).ComputeMac(data).value(),
656 primitives[1]->get_primitive().ComputeMac(data).value());
657 EXPECT_EQ(KeyStatusType::ENABLED, primitives[1]->get_status());
658 EXPECT_EQ(key_1.key_id(), primitives[1]->get_key_id());
659 EXPECT_EQ(OutputPrefixType::TINK, primitives[1]->get_output_prefix_type());
660 }
661
662 { // Check another Tink primitive.
663 std::string prefix = CryptoFormat::GetOutputPrefix(key_3).value();
664 auto& primitives = *(primitive_set.get_primitives(prefix).value());
665 EXPECT_EQ(1, primitives.size());
666 EXPECT_EQ(DummyMac(mac_name_3).ComputeMac(data).value(),
667 primitives[0]->get_primitive().ComputeMac(data).value());
668 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
669 EXPECT_EQ(key_3.key_id(), primitives[0]->get_key_id());
670 EXPECT_EQ(OutputPrefixType::TINK, primitives[0]->get_output_prefix_type());
671 }
672
673 { // Check legacy primitive.
674 std::string prefix = CryptoFormat::GetOutputPrefix(key_2).value();
675 auto& primitives = *(primitive_set.get_primitives(prefix).value());
676 EXPECT_EQ(1, primitives.size());
677 EXPECT_EQ(DummyMac(mac_name_2).ComputeMac(data).value(),
678 primitives[0]->get_primitive().ComputeMac(data).value());
679 EXPECT_EQ(KeyStatusType::ENABLED, primitives[0]->get_status());
680 EXPECT_EQ(key_2.key_id(), primitives[0]->get_key_id());
681 EXPECT_EQ(OutputPrefixType::LEGACY,
682 primitives[0]->get_output_prefix_type());
683 }
684 }
685
TEST_F(PrimitiveSetTest,LegacyPrimaryKeyWithIdCollisions)686 TEST_F(PrimitiveSetTest, LegacyPrimaryKeyWithIdCollisions) {
687 std::string mac_name_1 = "MAC#1";
688 std::string mac_name_2 = "MAC#2";
689
690 uint32_t key_id_1 = 1234543;
691 KeysetInfo::KeyInfo key_info_1;
692 key_info_1.set_key_id(key_id_1);
693 key_info_1.set_status(KeyStatusType::ENABLED);
694
695 uint32_t key_id_2 = key_id_1; // same id as key_2
696 KeysetInfo::KeyInfo key_info_2;
697 key_info_2.set_key_id(key_id_2);
698 key_info_2.set_status(KeyStatusType::ENABLED);
699
700 { // Test with RAW-keys.
701 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
702 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
703 key_info_1.set_output_prefix_type(OutputPrefixType::RAW);
704 key_info_2.set_output_prefix_type(OutputPrefixType::RAW);
705 PrimitiveSet<Mac> primitive_set;
706 EXPECT_TRUE(primitive_set.get_primary() == nullptr);
707
708 // Add the first primitive, and set it as primary.
709 auto add_primitive_result =
710 primitive_set.AddPrimitive(std::move(mac_1), key_info_1);
711 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
712 ASSERT_THAT(primitive_set.set_primary(add_primitive_result.value()),
713 IsOk());
714
715 std::string identifier = "";
716 const auto& primitives =
717 *(primitive_set.get_primitives(identifier).value());
718 EXPECT_EQ(1, primitives.size());
719 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
720
721 // Adding another primitive should not invalidate the primary.
722 add_primitive_result =
723 primitive_set.AddPrimitive(std::move(mac_2), key_info_2);
724 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
725 EXPECT_EQ(2, primitives.size());
726 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
727 }
728
729 { // Test with TINK-keys.
730 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
731 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
732 key_info_1.set_output_prefix_type(OutputPrefixType::TINK);
733 key_info_2.set_output_prefix_type(OutputPrefixType::TINK);
734 PrimitiveSet<Mac> primitive_set;
735 EXPECT_TRUE(primitive_set.get_primary() == nullptr);
736
737 // Add the first primitive, and set it as primary.
738 auto add_primitive_result =
739 primitive_set.AddPrimitive(std::move(mac_1), key_info_1);
740 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
741 ASSERT_THAT(primitive_set.set_primary(add_primitive_result.value()),
742 IsOk());
743
744 std::string identifier = CryptoFormat::GetOutputPrefix(key_info_1).value();
745 const auto& primitives =
746 *(primitive_set.get_primitives(identifier).value());
747 EXPECT_EQ(1, primitives.size());
748 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
749
750 // Adding another primitive should not invalidate the primary.
751 add_primitive_result =
752 primitive_set.AddPrimitive(std::move(mac_2), key_info_2);
753 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
754 EXPECT_EQ(2, primitives.size());
755 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
756 }
757
758 { // Test with LEGACY-keys.
759 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
760 std::unique_ptr<Mac> mac_2(new DummyMac(mac_name_2));
761 key_info_1.set_output_prefix_type(OutputPrefixType::LEGACY);
762 key_info_2.set_output_prefix_type(OutputPrefixType::LEGACY);
763 PrimitiveSet<Mac> primitive_set;
764 EXPECT_TRUE(primitive_set.get_primary() == nullptr);
765
766 // Add the first primitive, and set it as primary.
767 auto add_primitive_result =
768 primitive_set.AddPrimitive(std::move(mac_1), key_info_1);
769 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
770 ASSERT_THAT(primitive_set.set_primary(add_primitive_result.value()),
771 IsOk());
772
773 std::string identifier = CryptoFormat::GetOutputPrefix(key_info_1).value();
774 const auto& primitives =
775 *(primitive_set.get_primitives(identifier).value());
776 EXPECT_EQ(1, primitives.size());
777 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
778
779 // Adding another primitive should not invalidate the primary.
780 add_primitive_result =
781 primitive_set.AddPrimitive(std::move(mac_2), key_info_2);
782 EXPECT_TRUE(add_primitive_result.ok()) << add_primitive_result.status();
783 EXPECT_EQ(2, primitives.size());
784 EXPECT_EQ(primitive_set.get_primary(), primitives[0].get());
785 }
786 }
787
TEST_F(PrimitiveSetTest,LegacyDisabledKey)788 TEST_F(PrimitiveSetTest, LegacyDisabledKey) {
789 std::string mac_name_1 = "MAC#1";
790 std::unique_ptr<Mac> mac_1(new DummyMac(mac_name_1));
791
792 uint32_t key_id_1 = 1234543;
793 KeysetInfo::KeyInfo key_info_1;
794 key_info_1.set_output_prefix_type(OutputPrefixType::TINK);
795 key_info_1.set_key_id(key_id_1);
796 key_info_1.set_status(KeyStatusType::DISABLED);
797
798 PrimitiveSet<Mac> primitive_set;
799 // Add all the primitives.
800 auto add_primitive_result =
801 primitive_set.AddPrimitive(std::move(mac_1), key_info_1);
802 EXPECT_FALSE(add_primitive_result.ok());
803 }
804
TEST_F(PrimitiveSetTest,LegacyGetAll)805 TEST_F(PrimitiveSetTest, LegacyGetAll) {
806 PrimitiveSet<Mac> pset;
807 EXPECT_THAT(
808 pset.AddPrimitive(
809 absl::make_unique<DummyMac>("MAC1"),
810 CreateKey(0x01010101, OutputPrefixType::TINK,
811 KeyStatusType::ENABLED, /*type_url=*/
812 "type.googleapis.com/google.crypto.tink.HmacKey"))
813 .status(),
814 IsOk());
815
816 EXPECT_THAT(
817 pset.AddPrimitive(
818 absl::make_unique<DummyMac>("MAC2"),
819 CreateKey(0x02020202, OutputPrefixType::TINK,
820 KeyStatusType::ENABLED, /*type_url=*/
821 "type.googleapis.com/google.crypto.tink.HmacKey"))
822 .status(),
823 IsOk());
824 // Add primitive and make it primary.
825 auto entry_or = pset.AddPrimitive(
826 absl::make_unique<DummyMac>("MAC3"),
827 CreateKey(0x02020202, OutputPrefixType::TINK,
828 KeyStatusType::ENABLED, /*type_url=*/
829 "type.googleapis.com/google.crypto.tink.AesCmacKey"));
830 ASSERT_THAT(entry_or, IsOk());
831 EXPECT_THAT(pset.set_primary(entry_or.value()), IsOk());
832
833 EXPECT_THAT(
834 pset.AddPrimitive(
835 absl::make_unique<DummyMac>("MAC4"),
836 CreateKey(0x02020202, OutputPrefixType::RAW,
837 KeyStatusType::ENABLED, /*type_url=*/
838 "type.googleapis.com/google.crypto.tink.AesCmacKey"))
839 .status(),
840 IsOk());
841
842 EXPECT_THAT(
843 pset.AddPrimitive(
844 absl::make_unique<DummyMac>("MAC5"),
845 CreateKey(0x01010101, OutputPrefixType::TINK,
846 KeyStatusType::ENABLED, /*type_url=*/
847 "type.googleapis.com/google.crypto.tink.AesCmacKey"))
848 .status(),
849 IsOk());
850
851 std::vector<MacIdAndTypeUrl> mac_id_and_type;
852 for (auto* entry : pset.get_all()) {
853 auto mac_or = entry->get_primitive().ComputeMac("");
854 ASSERT_THAT(mac_or, IsOk());
855 mac_id_and_type.push_back({mac_or.value(), entry->get_identifier(),
856 std::string(entry->get_key_type_url())});
857 }
858
859 // In the following id part, the first byte is 1 for Tink.
860 std::vector<MacIdAndTypeUrl> expected_result = {
861 {/*mac=*/"13:0:DummyMac:MAC1", /*id=*/absl::StrCat("\1\1\1\1\1"),
862 /*type_url=*/"type.googleapis.com/google.crypto.tink.HmacKey"},
863 {/*mac=*/"13:0:DummyMac:MAC2", /*id=*/absl::StrCat("\1\2\2\2\2"),
864 /*type_url=*/"type.googleapis.com/google.crypto.tink.HmacKey"},
865 {/*mac=*/"13:0:DummyMac:MAC3", /*id=*/absl::StrCat("\1\2\2\2\2"),
866 /*type_url=*/"type.googleapis.com/google.crypto.tink.AesCmacKey"},
867 {/*mac=*/"13:0:DummyMac:MAC4", /*id=*/"",
868 /*type_url=*/"type.googleapis.com/google.crypto.tink.AesCmacKey"},
869 {/*mac=*/"13:0:DummyMac:MAC5", /*id=*/absl::StrCat("\1\1\1\1\1"),
870 /*type_url=*/"type.googleapis.com/google.crypto.tink.AesCmacKey"}};
871
872 EXPECT_THAT(mac_id_and_type, UnorderedElementsAreArray(expected_result));
873 }
874
875 } // namespace
876 } // namespace tink
877 } // namespace crypto
878