xref: /aosp_15_r20/external/tink/cc/mac/aes_cmac_proto_serialization_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2023 Google LLC
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/aes_cmac_proto_serialization.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "tink/insecure_secret_key_access.h"
25 #include "tink/internal/mutable_serialization_registry.h"
26 #include "tink/internal/proto_key_serialization.h"
27 #include "tink/internal/proto_parameters_serialization.h"
28 #include "tink/mac/aes_cmac_key.h"
29 #include "tink/mac/aes_cmac_parameters.h"
30 #include "tink/partial_key_access.h"
31 #include "tink/restricted_data.h"
32 #include "tink/subtle/random.h"
33 #include "tink/util/test_matchers.h"
34 #include "proto/aes_cmac.pb.h"
35 #include "proto/tink.pb.h"
36 
37 namespace crypto {
38 namespace tink {
39 namespace {
40 
41 using ::crypto::tink::subtle::Random;
42 using ::crypto::tink::test::IsOk;
43 using ::crypto::tink::test::IsOkAndHolds;
44 using ::crypto::tink::test::StatusIs;
45 using ::google::crypto::tink::AesCmacKeyFormat;
46 using ::google::crypto::tink::KeyData;
47 using ::google::crypto::tink::OutputPrefixType;
48 using ::testing::Eq;
49 using ::testing::IsTrue;
50 using ::testing::NotNull;
51 using ::testing::TestWithParam;
52 using ::testing::Values;
53 
54 struct TestCase {
55   AesCmacParameters::Variant variant;
56   OutputPrefixType output_prefix_type;
57   int key_size;
58   int tag_size;
59   int total_size;
60   absl::optional<int> id;
61   std::string output_prefix;
62 };
63 
64 class AesCmacProtoSerializationTest : public TestWithParam<TestCase> {
65  protected:
SetUp()66   void SetUp() override {
67     internal::MutableSerializationRegistry::GlobalInstance().Reset();
68   }
69 };
70 
71 INSTANTIATE_TEST_SUITE_P(
72     AesCmacProtoSerializationTestSuite, AesCmacProtoSerializationTest,
73     Values(TestCase{AesCmacParameters::Variant::kTink, OutputPrefixType::TINK,
74                     /*key_size=*/16, /*tag_size=*/10, /*total_size=*/15,
75                     /*id=*/0x02030400,
76                     /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
77            TestCase{AesCmacParameters::Variant::kCrunchy,
78                     OutputPrefixType::CRUNCHY, /*key_size=*/16,
79                     /*tag_size=*/12, /*total_size=*/17, /*id=*/0x01030005,
80                     /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
81            TestCase{AesCmacParameters::Variant::kLegacy,
82                     OutputPrefixType::LEGACY, /*key_size=*/32,
83                     /*cryptographic_tag_size=*/14, /*total_tag_size=*/19,
84                     /*id=*/0x01020304,
85                     /*output_prefix=*/std::string("\x00\x01\x02\x03\x04", 5)},
86            TestCase{AesCmacParameters::Variant::kNoPrefix,
87                     OutputPrefixType::RAW, /*key_size=*/32,
88                     /*cryptographic_tag_size=*/16, /*total_tag_size=*/16,
89                     /*id=*/absl::nullopt, /*output_prefix=*/""}));
90 
TEST_P(AesCmacProtoSerializationTest,ParseParameters)91 TEST_P(AesCmacProtoSerializationTest, ParseParameters) {
92   TestCase test_case = GetParam();
93   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
94 
95   AesCmacKeyFormat key_format_proto;
96   key_format_proto.set_key_size(test_case.key_size);
97   key_format_proto.mutable_params()->set_tag_size(test_case.tag_size);
98 
99   util::StatusOr<internal::ProtoParametersSerialization> serialization =
100       internal::ProtoParametersSerialization::Create(
101           "type.googleapis.com/google.crypto.tink.AesCmacKey",
102           test_case.output_prefix_type, key_format_proto.SerializeAsString());
103   ASSERT_THAT(serialization, IsOk());
104 
105   util::StatusOr<std::unique_ptr<Parameters>> params =
106       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
107           *serialization);
108   ASSERT_THAT(params, IsOk());
109   EXPECT_THAT((*params)->HasIdRequirement(), test_case.id.has_value());
110 
111   const AesCmacParameters* cmac_params =
112       dynamic_cast<const AesCmacParameters*>(params->get());
113   ASSERT_THAT(cmac_params, NotNull());
114   EXPECT_THAT(cmac_params->GetVariant(), Eq(test_case.variant));
115   EXPECT_THAT(cmac_params->KeySizeInBytes(), Eq(test_case.key_size));
116   EXPECT_THAT(cmac_params->CryptographicTagSizeInBytes(),
117               Eq(test_case.tag_size));
118   EXPECT_THAT(cmac_params->TotalTagSizeInBytes(), Eq(test_case.total_size));
119 }
120 
TEST_F(AesCmacProtoSerializationTest,ParseParametersWithInvalidSerialization)121 TEST_F(AesCmacProtoSerializationTest, ParseParametersWithInvalidSerialization) {
122   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
123 
124   AesCmacKeyFormat key_format_proto;
125   key_format_proto.set_key_size(16);
126   key_format_proto.mutable_params()->set_tag_size(10);
127 
128   util::StatusOr<internal::ProtoParametersSerialization> serialization =
129       internal::ProtoParametersSerialization::Create(
130           "type.googleapis.com/google.crypto.tink.AesCmacKey",
131           OutputPrefixType::RAW, "invalid_serialization");
132   ASSERT_THAT(serialization, IsOk());
133 
134   util::StatusOr<std::unique_ptr<Parameters>> params =
135       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
136           *serialization);
137   ASSERT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
138 }
139 
TEST_F(AesCmacProtoSerializationTest,ParseParametersWithUnkownOutputPrefix)140 TEST_F(AesCmacProtoSerializationTest, ParseParametersWithUnkownOutputPrefix) {
141   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
142 
143   AesCmacKeyFormat key_format_proto;
144   key_format_proto.set_key_size(16);
145   key_format_proto.mutable_params()->set_tag_size(10);
146 
147   util::StatusOr<internal::ProtoParametersSerialization> serialization =
148       internal::ProtoParametersSerialization::Create(
149           "type.googleapis.com/google.crypto.tink.AesCmacKey",
150           OutputPrefixType::UNKNOWN_PREFIX,
151           key_format_proto.SerializeAsString());
152   ASSERT_THAT(serialization, IsOk());
153 
154   util::StatusOr<std::unique_ptr<Parameters>> params =
155       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
156           *serialization);
157   ASSERT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
158 }
159 
TEST_P(AesCmacProtoSerializationTest,SerializeParameters)160 TEST_P(AesCmacProtoSerializationTest, SerializeParameters) {
161   TestCase test_case = GetParam();
162   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
163 
164   util::StatusOr<AesCmacParameters> parameters = AesCmacParameters::Create(
165       test_case.key_size, test_case.tag_size, test_case.variant);
166   ASSERT_THAT(parameters, IsOk());
167 
168   util::StatusOr<std::unique_ptr<Serialization>> serialization =
169       internal::MutableSerializationRegistry::GlobalInstance()
170           .SerializeParameters<internal::ProtoParametersSerialization>(
171               *parameters);
172   ASSERT_THAT(serialization, IsOk());
173   EXPECT_THAT((*serialization)->ObjectIdentifier(),
174               Eq("type.googleapis.com/google.crypto.tink.AesCmacKey"));
175 
176   const internal::ProtoParametersSerialization* proto_serialization =
177       dynamic_cast<const internal::ProtoParametersSerialization*>(
178           serialization->get());
179   ASSERT_THAT(proto_serialization, NotNull());
180   EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(),
181               Eq("type.googleapis.com/google.crypto.tink.AesCmacKey"));
182   EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(),
183               Eq(test_case.output_prefix_type));
184 
185   AesCmacKeyFormat key_format;
186   ASSERT_THAT(
187       key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()),
188       IsTrue());
189   ASSERT_THAT(key_format.key_size(), Eq(test_case.key_size));
190   ASSERT_THAT(key_format.params().tag_size(), Eq(test_case.tag_size));
191 }
192 
TEST_P(AesCmacProtoSerializationTest,ParseKey)193 TEST_P(AesCmacProtoSerializationTest, ParseKey) {
194   TestCase test_case = GetParam();
195   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
196 
197   std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
198   google::crypto::tink::AesCmacKey key_proto;
199   key_proto.set_version(0);
200   key_proto.set_key_value(raw_key_bytes);
201   key_proto.mutable_params()->set_tag_size(test_case.tag_size);
202   RestrictedData serialized_key = RestrictedData(
203       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
204 
205   util::StatusOr<internal::ProtoKeySerialization> serialization =
206       internal::ProtoKeySerialization::Create(
207           "type.googleapis.com/google.crypto.tink.AesCmacKey", serialized_key,
208           KeyData::SYMMETRIC, test_case.output_prefix_type, test_case.id);
209   ASSERT_THAT(serialization, IsOk());
210 
211   util::StatusOr<std::unique_ptr<Key>> key =
212       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
213           *serialization, InsecureSecretKeyAccess::Get());
214   ASSERT_THAT(key, IsOk());
215   EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id));
216   EXPECT_THAT((*key)->GetParameters().HasIdRequirement(),
217               test_case.id.has_value());
218 
219   const AesCmacKey* cmac_key = dynamic_cast<const AesCmacKey*>(key->get());
220   ASSERT_THAT(cmac_key, NotNull());
221   util::StatusOr<RestrictedData> parsed_key =
222       cmac_key->GetKeyBytes(GetPartialKeyAccess());
223   ASSERT_THAT(parsed_key, IsOk());
224   EXPECT_THAT(parsed_key->GetSecret(InsecureSecretKeyAccess::Get()),
225               Eq(raw_key_bytes));
226   EXPECT_THAT(cmac_key->GetOutputPrefix(), Eq(test_case.output_prefix));
227   EXPECT_THAT(cmac_key->GetParameters().GetVariant(), Eq(test_case.variant));
228   EXPECT_THAT(cmac_key->GetParameters().KeySizeInBytes(),
229               Eq(test_case.key_size));
230   EXPECT_THAT(cmac_key->GetParameters().CryptographicTagSizeInBytes(),
231               Eq(test_case.tag_size));
232   EXPECT_THAT(cmac_key->GetParameters().TotalTagSizeInBytes(),
233               test_case.total_size);
234   EXPECT_THAT(cmac_key->GetParameters().HasIdRequirement(),
235               test_case.id.has_value());
236 }
237 
TEST_F(AesCmacProtoSerializationTest,ParseKeyWithInvalidSerialization)238 TEST_F(AesCmacProtoSerializationTest, ParseKeyWithInvalidSerialization) {
239   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
240 
241   RestrictedData serialized_key =
242       RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
243 
244   util::StatusOr<internal::ProtoKeySerialization> serialization =
245       internal::ProtoKeySerialization::Create(
246           "type.googleapis.com/google.crypto.tink.AesCmacKey", serialized_key,
247           KeyData::SYMMETRIC, OutputPrefixType::TINK,
248           /*id_requirement=*/0x23456789);
249   ASSERT_THAT(serialization, IsOk());
250 
251   util::StatusOr<std::unique_ptr<Key>> key =
252       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
253           *serialization, InsecureSecretKeyAccess::Get());
254   ASSERT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
255 }
256 
TEST_F(AesCmacProtoSerializationTest,ParseKeyNoSecretKeyAccess)257 TEST_F(AesCmacProtoSerializationTest, ParseKeyNoSecretKeyAccess) {
258   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
259 
260   std::string raw_key_bytes = Random::GetRandomBytes(16);
261   google::crypto::tink::AesCmacKey key_proto;
262   key_proto.set_version(0);
263   key_proto.set_key_value(raw_key_bytes);
264   key_proto.mutable_params()->set_tag_size(10);
265   RestrictedData serialized_key = RestrictedData(
266       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
267 
268   util::StatusOr<internal::ProtoKeySerialization> serialization =
269       internal::ProtoKeySerialization::Create(
270           "type.googleapis.com/google.crypto.tink.AesCmacKey", serialized_key,
271           KeyData::SYMMETRIC, OutputPrefixType::TINK,
272           /*id_requirement=*/0x23456789);
273   ASSERT_THAT(serialization, IsOk());
274 
275   util::StatusOr<std::unique_ptr<Key>> key =
276       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
277           *serialization, absl::nullopt);
278   ASSERT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
279 }
280 
TEST_F(AesCmacProtoSerializationTest,ParseKeyWithInvalidVersion)281 TEST_F(AesCmacProtoSerializationTest, ParseKeyWithInvalidVersion) {
282   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
283 
284   std::string raw_key_bytes = Random::GetRandomBytes(16);
285   google::crypto::tink::AesCmacKey key_proto;
286   key_proto.set_version(1);  // Invalid version number.
287   key_proto.set_key_value(raw_key_bytes);
288   key_proto.mutable_params()->set_tag_size(10);
289   RestrictedData serialized_key = RestrictedData(
290       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
291 
292   util::StatusOr<internal::ProtoKeySerialization> serialization =
293       internal::ProtoKeySerialization::Create(
294           "type.googleapis.com/google.crypto.tink.AesCmacKey", serialized_key,
295           KeyData::SYMMETRIC, OutputPrefixType::TINK,
296           /*id_requirement=*/0x23456789);
297   ASSERT_THAT(serialization, IsOk());
298 
299   util::StatusOr<std::unique_ptr<Key>> key =
300       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
301           *serialization, InsecureSecretKeyAccess::Get());
302   ASSERT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
303 }
304 
TEST_P(AesCmacProtoSerializationTest,SerializeKey)305 TEST_P(AesCmacProtoSerializationTest, SerializeKey) {
306   TestCase test_case = GetParam();
307   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
308 
309   util::StatusOr<AesCmacParameters> parameters = AesCmacParameters::Create(
310       test_case.key_size, test_case.tag_size, test_case.variant);
311   ASSERT_THAT(parameters, IsOk());
312 
313   std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
314   util::StatusOr<AesCmacKey> key = AesCmacKey::Create(
315       *parameters,
316       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
317       test_case.id, GetPartialKeyAccess());
318   ASSERT_THAT(key, IsOk());
319 
320   util::StatusOr<std::unique_ptr<Serialization>> serialization =
321       internal::MutableSerializationRegistry::GlobalInstance()
322           .SerializeKey<internal::ProtoKeySerialization>(
323               *key, InsecureSecretKeyAccess::Get());
324   ASSERT_THAT(serialization, IsOk());
325   EXPECT_THAT((*serialization)->ObjectIdentifier(),
326               Eq("type.googleapis.com/google.crypto.tink.AesCmacKey"));
327 
328   const internal::ProtoKeySerialization* proto_serialization =
329       dynamic_cast<const internal::ProtoKeySerialization*>(
330           serialization->get());
331   ASSERT_THAT(proto_serialization, NotNull());
332   EXPECT_THAT(proto_serialization->TypeUrl(),
333               Eq("type.googleapis.com/google.crypto.tink.AesCmacKey"));
334   EXPECT_THAT(proto_serialization->KeyMaterialType(), Eq(KeyData::SYMMETRIC));
335   EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
336               Eq(test_case.output_prefix_type));
337   EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id));
338 
339   google::crypto::tink::AesCmacKey proto_key;
340   // OSS proto library complains if input is not converted to a string.
341   ASSERT_THAT(proto_key.ParseFromString(std::string(
342                   proto_serialization->SerializedKeyProto().GetSecret(
343                       InsecureSecretKeyAccess::Get()))),
344               IsTrue());
345   EXPECT_THAT(proto_key.key_value().size(), Eq(test_case.key_size));
346   EXPECT_THAT(proto_key.params().tag_size(), Eq(test_case.tag_size));
347 }
348 
TEST_F(AesCmacProtoSerializationTest,SerializeKeyNoSecretKeyAccess)349 TEST_F(AesCmacProtoSerializationTest, SerializeKeyNoSecretKeyAccess) {
350   ASSERT_THAT(RegisterAesCmacProtoSerialization(), IsOk());
351 
352   util::StatusOr<AesCmacParameters> parameters = AesCmacParameters::Create(
353       /*key_size_in_bytes=*/16, /*cryptographic_tag_size_in_bytes=*/10,
354       AesCmacParameters::Variant::kNoPrefix);
355   ASSERT_THAT(parameters, IsOk());
356 
357   std::string raw_key_bytes = Random::GetRandomBytes(16);
358   util::StatusOr<AesCmacKey> key = AesCmacKey::Create(
359       *parameters,
360       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
361       /*id_requirement=*/absl::nullopt, GetPartialKeyAccess());
362   ASSERT_THAT(key, IsOk());
363 
364   util::StatusOr<std::unique_ptr<Serialization>> serialization =
365       internal::MutableSerializationRegistry::GlobalInstance()
366           .SerializeKey<internal::ProtoKeySerialization>(*key, absl::nullopt);
367   ASSERT_THAT(serialization.status(),
368               StatusIs(absl::StatusCode::kInvalidArgument));
369 }
370 
371 }  // namespace
372 }  // namespace tink
373 }  // namespace crypto
374