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_config.h"
18
19 #include <list>
20 #include <memory>
21 #include <string>
22 #include <utility>
23
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "tink/chunked_mac.h"
27 #include "tink/insecure_secret_key_access.h"
28 #include "tink/internal/fips_utils.h"
29 #include "tink/internal/mutable_serialization_registry.h"
30 #include "tink/internal/proto_key_serialization.h"
31 #include "tink/internal/proto_parameters_serialization.h"
32 #include "tink/keyset_handle.h"
33 #include "tink/mac.h"
34 #include "tink/mac/aes_cmac_key.h"
35 #include "tink/mac/aes_cmac_key_manager.h"
36 #include "tink/mac/aes_cmac_parameters.h"
37 #include "tink/mac/hmac_key.h"
38 #include "tink/mac/hmac_key_manager.h"
39 #include "tink/mac/hmac_parameters.h"
40 #include "tink/mac/mac_key_templates.h"
41 #include "tink/partial_key_access.h"
42 #include "tink/registry.h"
43 #include "tink/util/status.h"
44 #include "tink/util/test_matchers.h"
45 #include "tink/util/test_util.h"
46 #include "proto/common.pb.h"
47 #include "proto/tink.pb.h"
48
49 namespace crypto {
50 namespace tink {
51 namespace {
52
53 using ::crypto::tink::test::DummyMac;
54 using ::crypto::tink::test::IsOk;
55 using ::crypto::tink::test::StatusIs;
56 using ::google::crypto::tink::KeyData;
57 using ::google::crypto::tink::KeysetInfo;
58 using ::google::crypto::tink::KeyStatusType;
59 using ::google::crypto::tink::HashType;
60 using ::google::crypto::tink::KeyTemplate;
61 using ::google::crypto::tink::OutputPrefixType;
62 using ::testing::Values;
63
64 class MacConfigTest : public ::testing::Test {
65 protected:
SetUp()66 void SetUp() override {
67 Registry::Reset();
68 internal::MutableSerializationRegistry::GlobalInstance().Reset();
69 }
70 };
71
TEST_F(MacConfigTest,Basic)72 TEST_F(MacConfigTest, Basic) {
73 if (internal::IsFipsModeEnabled()) {
74 GTEST_SKIP() << "Not supported in FIPS-only mode";
75 }
76
77 EXPECT_THAT(
78 Registry::get_key_manager<Mac>(HmacKeyManager().get_key_type()).status(),
79 StatusIs(absl::StatusCode::kNotFound));
80 EXPECT_THAT(
81 Registry::get_key_manager<ChunkedMac>(HmacKeyManager().get_key_type())
82 .status(),
83 StatusIs(absl::StatusCode::kNotFound));
84 EXPECT_THAT(Registry::get_key_manager<Mac>(AesCmacKeyManager().get_key_type())
85 .status(),
86 StatusIs(absl::StatusCode::kNotFound));
87 EXPECT_THAT(
88 Registry::get_key_manager<ChunkedMac>(AesCmacKeyManager().get_key_type())
89 .status(),
90 StatusIs(absl::StatusCode::kNotFound));
91
92 ASSERT_THAT(MacConfig::Register(), IsOk());
93
94 EXPECT_THAT(
95 Registry::get_key_manager<Mac>(HmacKeyManager().get_key_type()).status(),
96 IsOk());
97 EXPECT_THAT(
98 Registry::get_key_manager<ChunkedMac>(HmacKeyManager().get_key_type())
99 .status(),
100 IsOk());
101 EXPECT_THAT(Registry::get_key_manager<Mac>(AesCmacKeyManager().get_key_type())
102 .status(),
103 IsOk());
104 EXPECT_THAT(
105 Registry::get_key_manager<ChunkedMac>(AesCmacKeyManager().get_key_type())
106 .status(),
107 IsOk());
108 }
109
110 // Tests that the MacWrapper has been properly registered and we can wrap
111 // primitives.
TEST_F(MacConfigTest,MacWrappersRegistered)112 TEST_F(MacConfigTest, MacWrappersRegistered) {
113 if (internal::IsFipsModeEnabled()) {
114 GTEST_SKIP() << "Not supported in FIPS-only mode";
115 }
116
117 ASSERT_TRUE(MacConfig::Register().ok());
118
119 KeysetInfo::KeyInfo key_info;
120 key_info.set_status(KeyStatusType::ENABLED);
121 key_info.set_key_id(1234);
122 key_info.set_output_prefix_type(OutputPrefixType::RAW);
123 auto primitive_set = absl::make_unique<PrimitiveSet<Mac>>();
124 ASSERT_TRUE(
125 primitive_set
126 ->set_primary(
127 primitive_set
128 ->AddPrimitive(absl::make_unique<DummyMac>("dummy"), key_info)
129 .value())
130 .ok());
131
132 auto primitive_result = Registry::Wrap(std::move(primitive_set));
133
134 ASSERT_TRUE(primitive_result.ok()) << primitive_result.status();
135 auto mac_result = primitive_result.value()->ComputeMac("verified text");
136 ASSERT_TRUE(mac_result.ok());
137
138 EXPECT_TRUE(
139 DummyMac("dummy").VerifyMac(mac_result.value(), "verified text").ok());
140 EXPECT_FALSE(
141 DummyMac("dummy").VerifyMac(mac_result.value(), "faked text").ok());
142 }
143
TEST_F(MacConfigTest,AesCmacProtoParamsSerializationRegistered)144 TEST_F(MacConfigTest, AesCmacProtoParamsSerializationRegistered) {
145 if (internal::IsFipsModeEnabled()) {
146 GTEST_SKIP() << "Not supported in FIPS-only mode";
147 }
148
149 util::StatusOr<internal::ProtoParametersSerialization>
150 proto_params_serialization =
151 internal::ProtoParametersSerialization::Create(
152 MacKeyTemplates::AesCmac());
153 ASSERT_THAT(proto_params_serialization, IsOk());
154
155 util::StatusOr<std::unique_ptr<Parameters>> parsed_params =
156 internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
157 *proto_params_serialization);
158 ASSERT_THAT(parsed_params.status(), StatusIs(absl::StatusCode::kNotFound));
159
160 util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
161 /*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
162 AesCmacParameters::Variant::kTink);
163 ASSERT_THAT(params, IsOk());
164
165 util::StatusOr<std::unique_ptr<Serialization>> serialized_params =
166 internal::MutableSerializationRegistry::GlobalInstance()
167 .SerializeParameters<internal::ProtoParametersSerialization>(*params);
168 ASSERT_THAT(serialized_params.status(),
169 StatusIs(absl::StatusCode::kNotFound));
170
171 ASSERT_THAT(MacConfig::Register(), IsOk());
172
173 util::StatusOr<std::unique_ptr<Parameters>> parsed_params2 =
174 internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
175 *proto_params_serialization);
176 ASSERT_THAT(parsed_params2, IsOk());
177
178 util::StatusOr<std::unique_ptr<Serialization>> serialized_params2 =
179 internal::MutableSerializationRegistry::GlobalInstance()
180 .SerializeParameters<internal::ProtoParametersSerialization>(*params);
181 ASSERT_THAT(serialized_params2, IsOk());
182 }
183
TEST_F(MacConfigTest,AesCmacProtoKeySerializationRegistered)184 TEST_F(MacConfigTest, AesCmacProtoKeySerializationRegistered) {
185 if (internal::IsFipsModeEnabled()) {
186 GTEST_SKIP() << "Not supported in FIPS-only mode";
187 }
188
189 google::crypto::tink::AesCmacKey key_proto;
190 key_proto.set_version(0);
191 key_proto.set_key_value(subtle::Random::GetRandomBytes(32));
192 key_proto.mutable_params()->set_tag_size(16);
193
194 util::StatusOr<internal::ProtoKeySerialization> proto_key_serialization =
195 internal::ProtoKeySerialization::Create(
196 "type.googleapis.com/google.crypto.tink.AesCmacKey",
197 RestrictedData(key_proto.SerializeAsString(),
198 InsecureSecretKeyAccess::Get()),
199 KeyData::SYMMETRIC, OutputPrefixType::TINK, /*id_requirement=*/123);
200 ASSERT_THAT(proto_key_serialization, IsOk());
201
202 util::StatusOr<std::unique_ptr<Key>> parsed_key =
203 internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
204 *proto_key_serialization, InsecureSecretKeyAccess::Get());
205 ASSERT_THAT(parsed_key.status(), StatusIs(absl::StatusCode::kNotFound));
206
207 util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
208 /*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
209 AesCmacParameters::Variant::kTink);
210 ASSERT_THAT(params, IsOk());
211
212 util::StatusOr<AesCmacKey> key =
213 AesCmacKey::Create(*params,
214 RestrictedData(subtle::Random::GetRandomBytes(32),
215 InsecureSecretKeyAccess::Get()),
216 /*id_requirement=*/123, GetPartialKeyAccess());
217 ASSERT_THAT(key, IsOk());
218
219 util::StatusOr<std::unique_ptr<Serialization>> serialized_key =
220 internal::MutableSerializationRegistry::GlobalInstance()
221 .SerializeKey<internal::ProtoKeySerialization>(
222 *key, InsecureSecretKeyAccess::Get());
223 ASSERT_THAT(serialized_key.status(), StatusIs(absl::StatusCode::kNotFound));
224
225 ASSERT_THAT(MacConfig::Register(), IsOk());
226
227 util::StatusOr<std::unique_ptr<Key>> parsed_key2 =
228 internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
229 *proto_key_serialization, InsecureSecretKeyAccess::Get());
230 ASSERT_THAT(parsed_key2, IsOk());
231
232 util::StatusOr<std::unique_ptr<Serialization>> serialized_key2 =
233 internal::MutableSerializationRegistry::GlobalInstance()
234 .SerializeKey<internal::ProtoKeySerialization>(
235 *key, InsecureSecretKeyAccess::Get());
236 ASSERT_THAT(serialized_key2, IsOk());
237 }
238
TEST_F(MacConfigTest,HmacProtoParamsSerializationRegistered)239 TEST_F(MacConfigTest, HmacProtoParamsSerializationRegistered) {
240 if (internal::IsFipsModeEnabled()) {
241 GTEST_SKIP() << "Not supported in FIPS-only mode";
242 }
243
244 util::StatusOr<internal::ProtoParametersSerialization>
245 proto_params_serialization =
246 internal::ProtoParametersSerialization::Create(
247 MacKeyTemplates::HmacSha256());
248 ASSERT_THAT(proto_params_serialization, IsOk());
249
250 util::StatusOr<std::unique_ptr<Parameters>> parsed_params =
251 internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
252 *proto_params_serialization);
253 ASSERT_THAT(parsed_params.status(), StatusIs(absl::StatusCode::kNotFound));
254
255 util::StatusOr<HmacParameters> parameters = HmacParameters::Create(
256 /*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/32,
257 HmacParameters::HashType::kSha256, HmacParameters::Variant::kTink);
258 ASSERT_THAT(parameters, IsOk());
259
260 util::StatusOr<std::unique_ptr<Serialization>> serialized_parameters =
261 internal::MutableSerializationRegistry::GlobalInstance()
262 .SerializeParameters<internal::ProtoParametersSerialization>(
263 *parameters);
264 ASSERT_THAT(serialized_parameters.status(),
265 StatusIs(absl::StatusCode::kNotFound));
266
267 // Register parser and serializer.
268 ASSERT_THAT(MacConfig::Register(), IsOk());
269
270 util::StatusOr<std::unique_ptr<Parameters>> parsed_params2 =
271 internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
272 *proto_params_serialization);
273 ASSERT_THAT(parsed_params2, IsOk());
274
275 util::StatusOr<std::unique_ptr<Serialization>> serialized_params2 =
276 internal::MutableSerializationRegistry::GlobalInstance()
277 .SerializeParameters<internal::ProtoParametersSerialization>(
278 *parameters);
279 ASSERT_THAT(serialized_params2, IsOk());
280 }
281
TEST_F(MacConfigTest,HmacProtoKeySerializationRegistered)282 TEST_F(MacConfigTest, HmacProtoKeySerializationRegistered) {
283 if (internal::IsFipsModeEnabled()) {
284 GTEST_SKIP() << "Not supported in FIPS-only mode";
285 }
286
287 google::crypto::tink::HmacKey key_proto;
288 key_proto.set_version(0);
289 key_proto.set_key_value(subtle::Random::GetRandomBytes(32));
290 key_proto.mutable_params()->set_tag_size(32);
291 key_proto.mutable_params()->set_hash(HashType::SHA256);
292
293 util::StatusOr<internal::ProtoKeySerialization> proto_key_serialization =
294 internal::ProtoKeySerialization::Create(
295 "type.googleapis.com/google.crypto.tink.HmacKey",
296 RestrictedData(key_proto.SerializeAsString(),
297 InsecureSecretKeyAccess::Get()),
298 KeyData::SYMMETRIC, OutputPrefixType::TINK, /*id_requirement=*/123);
299 ASSERT_THAT(proto_key_serialization, IsOk());
300
301 util::StatusOr<std::unique_ptr<Key>> parsed_key =
302 internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
303 *proto_key_serialization, InsecureSecretKeyAccess::Get());
304 ASSERT_THAT(parsed_key.status(), StatusIs(absl::StatusCode::kNotFound));
305
306 util::StatusOr<HmacParameters> parameters = HmacParameters::Create(
307 /*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/32,
308 HmacParameters::HashType::kSha256, HmacParameters::Variant::kTink);
309 ASSERT_THAT(parameters, IsOk());
310
311 util::StatusOr<HmacKey> key =
312 HmacKey::Create(*parameters,
313 RestrictedData(subtle::Random::GetRandomBytes(32),
314 InsecureSecretKeyAccess::Get()),
315 /*id_requirement=*/123, GetPartialKeyAccess());
316 ASSERT_THAT(key, IsOk());
317
318 util::StatusOr<std::unique_ptr<Serialization>> serialized_key =
319 internal::MutableSerializationRegistry::GlobalInstance()
320 .SerializeKey<internal::ProtoKeySerialization>(
321 *key, InsecureSecretKeyAccess::Get());
322 ASSERT_THAT(serialized_key.status(), StatusIs(absl::StatusCode::kNotFound));
323
324 // Register parser and serializer.
325 ASSERT_THAT(MacConfig::Register(), IsOk());
326
327 util::StatusOr<std::unique_ptr<Key>> parsed_key2 =
328 internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
329 *proto_key_serialization, InsecureSecretKeyAccess::Get());
330 ASSERT_THAT(parsed_key2, IsOk());
331
332 util::StatusOr<std::unique_ptr<Serialization>> serialized_key2 =
333 internal::MutableSerializationRegistry::GlobalInstance()
334 .SerializeKey<internal::ProtoKeySerialization>(
335 *key, InsecureSecretKeyAccess::Get());
336 ASSERT_THAT(serialized_key2, IsOk());
337 }
338
339 class ChunkedMacConfigTest : public ::testing::TestWithParam<KeyTemplate> {
340 protected:
SetUp()341 void SetUp() override { Registry::Reset(); }
342 };
343
344 INSTANTIATE_TEST_SUITE_P(ChunkedMacConfigTestSuite, ChunkedMacConfigTest,
345 Values(MacKeyTemplates::AesCmac(),
346 MacKeyTemplates::HmacSha256()));
347
348 // Tests that the ChunkedMacWrapper has been properly registered and we can get
349 // primitives.
TEST_P(ChunkedMacConfigTest,ChunkedMacWrappersRegistered)350 TEST_P(ChunkedMacConfigTest, ChunkedMacWrappersRegistered) {
351 if (internal::IsFipsModeEnabled()) {
352 GTEST_SKIP() << "Not supported in FIPS-only mode";
353 }
354
355 ASSERT_THAT(MacConfig::Register(), IsOk());
356
357 KeyTemplate key_template = GetParam();
358 util::StatusOr<std::unique_ptr<KeysetHandle>> key =
359 KeysetHandle::GenerateNew(key_template);
360 ASSERT_THAT(key, IsOk());
361
362 util::StatusOr<std::unique_ptr<ChunkedMac>> chunked_mac =
363 (*key)->GetPrimitive<ChunkedMac>();
364 ASSERT_THAT(chunked_mac, IsOk());
365
366 util::StatusOr<std::unique_ptr<ChunkedMacComputation>> computation =
367 (*chunked_mac)->CreateComputation();
368 ASSERT_THAT(computation, IsOk());
369 ASSERT_THAT((*computation)->Update("verified text"), IsOk());
370 util::StatusOr<std::string> tag = (*computation)->ComputeMac();
371 ASSERT_THAT(tag, IsOk());
372
373 util::StatusOr<std::unique_ptr<ChunkedMacVerification>> verification =
374 (*chunked_mac)->CreateVerification(*tag);
375 ASSERT_THAT(verification, IsOk());
376 ASSERT_THAT((*verification)->Update("verified text"), IsOk());
377
378 EXPECT_THAT((*verification)->VerifyMac(), IsOk());
379 }
380
381 // FIPS-only mode tests
TEST_F(MacConfigTest,RegisterNonFipsTemplates)382 TEST_F(MacConfigTest, RegisterNonFipsTemplates) {
383 if (!internal::IsFipsModeEnabled() || !internal::IsFipsEnabledInSsl()) {
384 GTEST_SKIP() << "Only supported in FIPS-only mode";
385 }
386
387 EXPECT_THAT(MacConfig::Register(), IsOk());
388
389 std::list<google::crypto::tink::KeyTemplate> non_fips_key_templates;
390 non_fips_key_templates.push_back(MacKeyTemplates::AesCmac());
391
392 for (auto key_template : non_fips_key_templates) {
393 EXPECT_THAT(KeysetHandle::GenerateNew(key_template).status(),
394 StatusIs(absl::StatusCode::kNotFound));
395 }
396 }
397
TEST_F(MacConfigTest,RegisterFipsValidTemplates)398 TEST_F(MacConfigTest, RegisterFipsValidTemplates) {
399 if (!internal::IsFipsModeEnabled() || !internal::IsFipsEnabledInSsl()) {
400 GTEST_SKIP() << "Only supported in FIPS-only mode";
401 }
402
403 EXPECT_THAT(MacConfig::Register(), IsOk());
404
405 std::list<google::crypto::tink::KeyTemplate> fips_key_templates;
406 fips_key_templates.push_back(MacKeyTemplates::HmacSha256());
407 fips_key_templates.push_back(MacKeyTemplates::HmacSha256HalfSizeTag());
408 fips_key_templates.push_back(MacKeyTemplates::HmacSha512());
409 fips_key_templates.push_back(MacKeyTemplates::HmacSha512HalfSizeTag());
410
411 for (auto key_template : fips_key_templates) {
412 EXPECT_THAT(KeysetHandle::GenerateNew(key_template), IsOk());
413 }
414 }
415
416 } // namespace
417 } // namespace tink
418 } // namespace crypto
419