xref: /aosp_15_r20/external/tink/cc/mac/mac_wrapper_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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/mac/mac_wrapper.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 
23 #include "gtest/gtest.h"
24 #include "absl/strings/str_cat.h"
25 #include "tink/crypto_format.h"
26 #include "tink/internal/registry_impl.h"
27 #include "tink/mac.h"
28 #include "tink/mac/failing_mac.h"
29 #include "tink/monitoring/monitoring.h"
30 #include "tink/monitoring/monitoring_client_mocks.h"
31 #include "tink/primitive_set.h"
32 #include "tink/util/status.h"
33 #include "tink/util/test_matchers.h"
34 #include "tink/util/test_util.h"
35 #include "proto/tink.pb.h"
36 
37 namespace crypto {
38 namespace tink {
39 namespace {
40 
41 using ::crypto::tink::test::DummyMac;
42 using ::crypto::tink::test::IsOk;
43 using ::crypto::tink::test::IsOkAndHolds;
44 using ::crypto::tink::test::StatusIs;
45 using ::google::crypto::tink::KeysetInfo;
46 using ::google::crypto::tink::KeyStatusType;
47 using ::google::crypto::tink::OutputPrefixType;
48 using ::testing::_;
49 using ::testing::ByMove;
50 using ::testing::IsNull;
51 using ::testing::NiceMock;
52 using ::testing::Not;
53 using ::testing::NotNull;
54 using ::testing::Return;
55 using ::testing::Test;
56 
TEST(MacWrapperTest,WrapNullptr)57 TEST(MacWrapperTest, WrapNullptr) {
58   auto mac_result = MacWrapper().Wrap(nullptr);
59   EXPECT_FALSE(mac_result.ok());
60   EXPECT_EQ(absl::StatusCode::kInternal, mac_result.status().code());
61   EXPECT_PRED_FORMAT2(testing::IsSubstring, "non-NULL",
62                       std::string(mac_result.status().message()));
63 }
64 
TEST(MacWrapperTest,WrapEmpty)65 TEST(MacWrapperTest, WrapEmpty) {
66   std::unique_ptr<PrimitiveSet<Mac>> mac_set(new PrimitiveSet<Mac>());
67   auto mac_result = MacWrapper().Wrap(std::move(mac_set));
68   EXPECT_FALSE(mac_result.ok());
69   EXPECT_EQ(absl::StatusCode::kInvalidArgument, mac_result.status().code());
70   EXPECT_PRED_FORMAT2(testing::IsSubstring, "no primary",
71                       std::string(mac_result.status().message()));
72 }
73 
TEST(MacWrapperTest,Basic)74 TEST(MacWrapperTest, Basic) {
75   KeysetInfo::KeyInfo* key_info;
76   KeysetInfo keyset_info;
77 
78   uint32_t key_id_0 = 1234543;
79   key_info = keyset_info.add_key_info();
80   key_info->set_output_prefix_type(OutputPrefixType::TINK);
81   key_info->set_key_id(key_id_0);
82   key_info->set_status(KeyStatusType::ENABLED);
83 
84   uint32_t key_id_1 = 726329;
85   key_info = keyset_info.add_key_info();
86   key_info->set_output_prefix_type(OutputPrefixType::LEGACY);
87   key_info->set_key_id(key_id_1);
88   key_info->set_status(KeyStatusType::ENABLED);
89 
90   uint32_t key_id_2 = 7213743;
91   key_info = keyset_info.add_key_info();
92   key_info->set_output_prefix_type(OutputPrefixType::TINK);
93   key_info->set_key_id(key_id_2);
94   key_info->set_status(KeyStatusType::ENABLED);
95 
96   std::string mac_name_0 = "mac0";
97   std::string mac_name_1 = "mac1";
98   std::string mac_name_2 = "mac2";
99   std::unique_ptr<PrimitiveSet<Mac>> mac_set(new PrimitiveSet<Mac>());
100   auto entry_result = mac_set->AddPrimitive(
101       absl::make_unique<DummyMac>(mac_name_0), keyset_info.key_info(0));
102   ASSERT_TRUE(entry_result.ok());
103   entry_result = mac_set->AddPrimitive(absl::make_unique<DummyMac>(mac_name_1),
104                                        keyset_info.key_info(1));
105   ASSERT_TRUE(entry_result.ok());
106   entry_result = mac_set->AddPrimitive(absl::make_unique<DummyMac>(mac_name_2),
107                                        keyset_info.key_info(2));
108   ASSERT_TRUE(entry_result.ok());
109   // The last key is the primary.
110   ASSERT_THAT(mac_set->set_primary(entry_result.value()), IsOk());
111 
112   // Wrap mac_set and test the resulting Mac.
113   auto mac_result = MacWrapper().Wrap(std::move(mac_set));
114   EXPECT_TRUE(mac_result.ok()) << mac_result.status();
115   std::unique_ptr<Mac> mac = std::move(mac_result.value());
116   std::string data = "some_data_for_mac";
117 
118   auto compute_mac_result = mac->ComputeMac(data);
119   EXPECT_TRUE(compute_mac_result.ok()) << compute_mac_result.status();
120   std::string mac_value = compute_mac_result.value();
121   EXPECT_PRED_FORMAT2(testing::IsSubstring, mac_name_2, mac_value);
122 
123   util::Status status = mac->VerifyMac(mac_value, data);
124   EXPECT_TRUE(status.ok()) << status;
125 
126   status = mac->VerifyMac("some bad mac", data);
127   EXPECT_FALSE(status.ok());
128   EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code());
129   EXPECT_PRED_FORMAT2(testing::IsSubstring, "verification failed",
130                       std::string(status.message()));
131 }
132 
TEST(MacWrapperTest,testLegacyAuthentication)133 TEST(MacWrapperTest, testLegacyAuthentication) {
134   // Prepare a set for the wrapper.
135   KeysetInfo::KeyInfo key_info;
136   uint32_t key_id = 1234543;
137   key_info.set_output_prefix_type(OutputPrefixType::LEGACY);
138   key_info.set_key_id(key_id);
139   key_info.set_status(KeyStatusType::ENABLED);
140   std::string mac_name = "SomeLegacyMac";
141 
142   std::unique_ptr<PrimitiveSet<Mac>> mac_set(new PrimitiveSet<Mac>());
143   std::unique_ptr<Mac> mac(new DummyMac(mac_name));
144   auto entry_result = mac_set->AddPrimitive(std::move(mac), key_info);
145   ASSERT_TRUE(entry_result.ok());
146   ASSERT_THAT(mac_set->set_primary(entry_result.value()), IsOk());
147 
148   // Wrap mac_set and test the resulting Mac.
149   auto mac_result = MacWrapper().Wrap(std::move(mac_set));
150   EXPECT_TRUE(mac_result.ok()) << mac_result.status();
151   mac = std::move(mac_result.value());
152   std::string data = "Some data to authenticate";
153 
154   // Compute and verify MAC via wrapper.
155   auto compute_mac_result = mac->ComputeMac(data);
156   EXPECT_TRUE(compute_mac_result.ok()) << compute_mac_result.status();
157   std::string mac_value = compute_mac_result.value();
158   EXPECT_PRED_FORMAT2(testing::IsSubstring, mac_name, mac_value);
159   auto status = mac->VerifyMac(mac_value, data);
160   EXPECT_TRUE(status.ok()) << status;
161 
162   // Try verifying on raw Mac-primitive using original data.
163   std::unique_ptr<Mac> raw_mac(new DummyMac(mac_name));  // same as in wrapper
164   std::string raw_mac_value = mac_value.substr(CryptoFormat::kNonRawPrefixSize);
165   status = raw_mac->VerifyMac(raw_mac_value, data);
166   EXPECT_FALSE(status.ok());
167   EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code());
168 
169   // Verify on raw Mac-primitive using legacy-formatted data.
170   std::string legacy_data = data;
171   legacy_data.append(1, CryptoFormat::kLegacyStartByte);
172   status = raw_mac->VerifyMac(raw_mac_value, legacy_data);
173   EXPECT_TRUE(status.ok()) << status;
174 }
175 
176 // Produces a mac which starts in the same way as a legacy non-raw signature.
177 class TryBreakLegacyMac : public Mac {
178  public:
ComputeMac(absl::string_view data) const179   crypto::tink::util::StatusOr<std::string> ComputeMac(
180       absl::string_view data) const override {
181     return absl::StrCat(std::string("\x00", 1), "\xff\xff\xff\xff", data);
182   }
183 
VerifyMac(absl::string_view mac,absl::string_view data) const184   crypto::tink::util::Status VerifyMac(absl::string_view mac,
185                                        absl::string_view data) const override {
186     if (mac != ComputeMac(data).value()) {
187       return absl::InvalidArgumentError("Wrong mac");
188     }
189     return util::OkStatus();
190   }
191 };
192 
193 // Checks that a raw tag can be verified after a legacy tag is verified with
194 // the same output prefix. (To prevent regression of b/173013224).
TEST(MacWrapperTest,VerifyRawAfterLegacy)195 TEST(MacWrapperTest, VerifyRawAfterLegacy) {
196   std::unique_ptr<PrimitiveSet<Mac>> mac_set(new PrimitiveSet<Mac>());
197 
198   KeysetInfo::KeyInfo key_info_0;
199   key_info_0.set_output_prefix_type(OutputPrefixType::RAW);
200   key_info_0.set_key_id(1234);
201   key_info_0.set_status(KeyStatusType::ENABLED);
202   ASSERT_THAT(
203       mac_set->AddPrimitive(absl::make_unique<TryBreakLegacyMac>(), key_info_0)
204           .status(),
205       IsOk());
206 
207   KeysetInfo::KeyInfo key_info_1;
208   key_info_1.set_output_prefix_type(OutputPrefixType::LEGACY);
209   key_info_1.set_key_id(0xffffffff);
210   key_info_1.set_status(KeyStatusType::ENABLED);
211 
212   auto entry1 =
213       mac_set->AddPrimitive(absl::make_unique<DummyMac>(""), key_info_1);
214   ASSERT_THAT(entry1, IsOk());
215   ASSERT_THAT(mac_set->set_primary(entry1.value()), IsOk());
216 
217   // Wrap mac_set and test the resulting Mac.
218   auto wrapped_mac = MacWrapper().Wrap(std::move(mac_set));
219   EXPECT_THAT(wrapped_mac, IsOk());
220 
221   std::string data = "some data";
222   std::string mac_tag = TryBreakLegacyMac().ComputeMac(data).value();
223   EXPECT_THAT(wrapped_mac.value()->VerifyMac(mac_tag, data), IsOk());
224 }
225 
PopulateKeyInfo(uint32_t key_id,OutputPrefixType out_prefix_type,KeyStatusType status)226 KeysetInfo::KeyInfo PopulateKeyInfo(uint32_t key_id,
227                                     OutputPrefixType out_prefix_type,
228                                     KeyStatusType status) {
229   KeysetInfo::KeyInfo key_info;
230   key_info.set_output_prefix_type(out_prefix_type);
231   key_info.set_key_id(key_id);
232   key_info.set_status(status);
233   return key_info;
234 }
235 
236 // Creates a test keyset info object.
CreateTestKeysetInfo()237 KeysetInfo CreateTestKeysetInfo() {
238   KeysetInfo keyset_info;
239   *keyset_info.add_key_info() =
240       PopulateKeyInfo(/*key_id=*/1234543, OutputPrefixType::TINK,
241                       /*status=*/KeyStatusType::ENABLED);
242   *keyset_info.add_key_info() =
243       PopulateKeyInfo(/*key_id=*/726329, OutputPrefixType::LEGACY,
244                       /*status=*/KeyStatusType::ENABLED);
245   *keyset_info.add_key_info() =
246       PopulateKeyInfo(/*key_id=*/7213743, OutputPrefixType::TINK,
247                       /*status=*/KeyStatusType::ENABLED);
248   return keyset_info;
249 }
250 
251 // Tests for the monitoring behavior.
252 class MacSetWrapperWithMonitoringTest : public Test {
253  protected:
254   // Perform some common initialization: reset the global registry, set expected
255   // calls for the mock monitoring factory and the returned clients.
SetUp()256   void SetUp() override {
257     Registry::Reset();
258 
259     // Setup mocks for catching Monitoring calls.
260     auto monitoring_client_factory =
261         absl::make_unique<MockMonitoringClientFactory>();
262     auto compute_monitoring_client =
263         absl::make_unique<NiceMock<MockMonitoringClient>>();
264     compute_monitoring_client_ = compute_monitoring_client.get();
265     auto verify_monitoring_client =
266         absl::make_unique<NiceMock<MockMonitoringClient>>();
267     verify_monitoring_client_ = verify_monitoring_client.get();
268 
269     // Monitoring tests expect that the client factory will create the
270     // corresponding MockMonitoringClients.
271     EXPECT_CALL(*monitoring_client_factory, New(_))
272         .WillOnce(
273             Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
274                 std::move(compute_monitoring_client)))))
275         .WillOnce(
276             Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
277                 std::move(verify_monitoring_client)))));
278 
279     ASSERT_THAT(internal::RegistryImpl::GlobalInstance()
280                     .RegisterMonitoringClientFactory(
281                         std::move(monitoring_client_factory)),
282                 IsOk());
283     ASSERT_THAT(
284         internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory(),
285         Not(IsNull()));
286   }
287 
288   // Cleanup the registry to avoid mock leaks.
~MacSetWrapperWithMonitoringTest()289   ~MacSetWrapperWithMonitoringTest() override { Registry::Reset(); }
290 
291   MockMonitoringClient* compute_monitoring_client_;
292   MockMonitoringClient* verify_monitoring_client_;
293 };
294 
295 // Tests that successful ComputeMac operations are logged.
TEST_F(MacSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringComputeSuccess)296 TEST_F(MacSetWrapperWithMonitoringTest,
297        WrapKeysetWithMonitoringComputeSuccess) {
298   // Create a primitive set and fill it with some entries
299   KeysetInfo keyset_info = CreateTestKeysetInfo();
300   const absl::flat_hash_map<std::string, std::string> annotations = {
301       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
302   auto mac_primitive_set = absl::make_unique<PrimitiveSet<Mac>>(annotations);
303   ASSERT_THAT(mac_primitive_set
304                   ->AddPrimitive(absl::make_unique<DummyMac>("mac0"),
305                                  keyset_info.key_info(0))
306                   .status(),
307               IsOk());
308   ASSERT_THAT(mac_primitive_set
309                   ->AddPrimitive(absl::make_unique<DummyMac>("mac1"),
310                                  keyset_info.key_info(1))
311                   .status(),
312               IsOk());
313   // Set the last as primary.
314   util::StatusOr<PrimitiveSet<Mac>::Entry<Mac>*> last =
315       mac_primitive_set->AddPrimitive(absl::make_unique<DummyMac>("mac2"),
316                                       keyset_info.key_info(2));
317   ASSERT_THAT(last.status(), IsOk());
318   ASSERT_THAT(mac_primitive_set->set_primary(*last), IsOk());
319   // Record the ID of the primary key.
320   const uint32_t primary_key_id = keyset_info.key_info(2).key_id();
321 
322   // Create a MAC and compute an authentication tag
323   util::StatusOr<std::unique_ptr<Mac>> mac =
324       MacWrapper().Wrap(std::move(mac_primitive_set));
325   ASSERT_THAT(mac, IsOkAndHolds(NotNull()));
326 
327   constexpr absl::string_view message = "This is some message!";
328 
329   // Check that calling ComputeMac triggers a Log() call.
330   EXPECT_CALL(*compute_monitoring_client_, Log(primary_key_id, message.size()));
331   EXPECT_THAT((*mac)->ComputeMac(message).status(), IsOk());
332 }
333 
334 // Test that successful VerifyMac operations are logged.
TEST_F(MacSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringVerifySuccess)335 TEST_F(MacSetWrapperWithMonitoringTest,
336        WrapKeysetWithMonitoringVerifySuccess) {
337   // Create a primitive set and fill it with some entries
338   KeysetInfo keyset_info = CreateTestKeysetInfo();
339   const absl::flat_hash_map<std::string, std::string> annotations = {
340       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
341   auto mac_primitive_set = absl::make_unique<PrimitiveSet<Mac>>(annotations);
342   ASSERT_THAT(mac_primitive_set
343                   ->AddPrimitive(absl::make_unique<DummyMac>("mac0"),
344                                  keyset_info.key_info(0))
345                   .status(),
346               IsOk());
347   ASSERT_THAT(mac_primitive_set
348                   ->AddPrimitive(absl::make_unique<DummyMac>("mac1"),
349                                  keyset_info.key_info(1))
350                   .status(),
351               IsOk());
352   // Set the last as primary.
353   util::StatusOr<PrimitiveSet<Mac>::Entry<Mac>*> last =
354       mac_primitive_set->AddPrimitive(absl::make_unique<DummyMac>("mac2"),
355                                       keyset_info.key_info(2));
356   ASSERT_THAT(last.status(), IsOk());
357   ASSERT_THAT(mac_primitive_set->set_primary(*last), IsOk());
358   // Record the ID of the primary key.
359   const uint32_t primary_key_id = keyset_info.key_info(2).key_id();
360 
361   // Create a MAC, compute a Mac and verify it.
362   util::StatusOr<std::unique_ptr<Mac>> mac =
363       MacWrapper().Wrap(std::move(mac_primitive_set));
364   ASSERT_THAT(mac, IsOkAndHolds(NotNull()));
365 
366   constexpr absl::string_view message = "This is some message!";
367 
368   // Check that calling VerifyMac triggers a Log() call.
369   util::StatusOr<std::string> tag = (*mac)->ComputeMac(message);
370   EXPECT_THAT(tag.status(), IsOk());
371 
372   // In the log expect the size of the message without the non-raw prefix.
373   EXPECT_CALL(*verify_monitoring_client_, Log(primary_key_id, message.size()));
374   EXPECT_THAT((*mac)->VerifyMac(*tag, message), IsOk());
375 }
376 
TEST_F(MacSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringComputeFailures)377 TEST_F(MacSetWrapperWithMonitoringTest,
378        WrapKeysetWithMonitoringComputeFailures) {
379   // Create a primitive set and fill it with some entries.
380   KeysetInfo keyset_info = CreateTestKeysetInfo();
381   const absl::flat_hash_map<std::string, std::string> annotations = {
382       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
383   auto mac_primitive_set = absl::make_unique<PrimitiveSet<Mac>>(annotations);
384   ASSERT_THAT(mac_primitive_set
385                   ->AddPrimitive(CreateAlwaysFailingMac("mac "),
386                                  keyset_info.key_info(0))
387                   .status(),
388               IsOk());
389   ASSERT_THAT(mac_primitive_set
390                   ->AddPrimitive(CreateAlwaysFailingMac("mac "),
391                                  keyset_info.key_info(1))
392                   .status(),
393               IsOk());
394   // Set the last as primary.
395   util::StatusOr<PrimitiveSet<Mac>::Entry<Mac>*> last =
396       mac_primitive_set->AddPrimitive(CreateAlwaysFailingMac("mac "),
397                                       keyset_info.key_info(2));
398   ASSERT_THAT(last.status(), IsOk());
399   ASSERT_THAT(mac_primitive_set->set_primary(*last), IsOk());
400 
401   // Create a MAC and compute a tag.
402   util::StatusOr<std::unique_ptr<Mac>> mac =
403       MacWrapper().Wrap(std::move(mac_primitive_set));
404   ASSERT_THAT(mac, IsOkAndHolds(NotNull()));
405 
406   constexpr absl::string_view message = "This is some message!";
407 
408   // Check that calling ComputeMac triggers a LogFailure() call.
409   EXPECT_CALL(*compute_monitoring_client_, LogFailure());
410   EXPECT_THAT((*mac)->ComputeMac(message).status(),
411               StatusIs(absl::StatusCode::kInternal));
412 }
413 
414 // Test that monitoring logs verify failures correctly.
TEST_F(MacSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringVerifyFailures)415 TEST_F(MacSetWrapperWithMonitoringTest,
416        WrapKeysetWithMonitoringVerifyFailures) {
417   // Create a primitive set and fill it with some entries.
418   KeysetInfo keyset_info = CreateTestKeysetInfo();
419   const absl::flat_hash_map<std::string, std::string> annotations = {
420       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
421   auto mac_primitive_set = absl::make_unique<PrimitiveSet<Mac>>(annotations);
422   ASSERT_THAT(mac_primitive_set
423                   ->AddPrimitive(CreateAlwaysFailingMac("mac "),
424                                  keyset_info.key_info(0))
425                   .status(),
426               IsOk());
427   ASSERT_THAT(mac_primitive_set
428                   ->AddPrimitive(CreateAlwaysFailingMac("mac "),
429                                  keyset_info.key_info(1))
430                   .status(),
431               IsOk());
432   // Set the last as primary.
433   util::StatusOr<PrimitiveSet<Mac>::Entry<Mac>*> last =
434       mac_primitive_set->AddPrimitive(CreateAlwaysFailingMac("mac "),
435                                       keyset_info.key_info(2));
436   ASSERT_THAT(last.status(), IsOk());
437   ASSERT_THAT(mac_primitive_set->set_primary(*last), IsOk());
438 
439   // Create a MAC and verify a tag.
440   util::StatusOr<std::unique_ptr<Mac>> mac =
441       MacWrapper().Wrap(std::move(mac_primitive_set));
442   ASSERT_THAT(mac, IsOkAndHolds(NotNull()));
443 
444   constexpr absl::string_view message = "This is some message!";
445   constexpr absl::string_view tag = "some invalid tag!";
446 
447   // Check that calling VerifyMac triggers a LogFailure() call.
448   EXPECT_CALL(*verify_monitoring_client_, LogFailure());
449   EXPECT_THAT((*mac)->VerifyMac(tag, message),
450               StatusIs(absl::StatusCode::kInvalidArgument));
451 }
452 
453 }  // namespace
454 }  // namespace tink
455 }  // namespace crypto
456