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/aead/aead_wrapper.h"
18
19 #include <stdint.h>
20
21 #include <memory>
22 #include <string>
23 #include <utility>
24
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/container/flat_hash_map.h"
28 #include "absl/memory/memory.h"
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "absl/strings/str_cat.h"
32 #include "absl/strings/string_view.h"
33 #include "tink/aead.h"
34 #include "tink/aead/mock_aead.h"
35 #include "tink/crypto_format.h"
36 #include "tink/internal/registry_impl.h"
37 #include "tink/monitoring/monitoring.h"
38 #include "tink/monitoring/monitoring_client_mocks.h"
39 #include "tink/primitive_set.h"
40 #include "tink/registry.h"
41 #include "tink/util/status.h"
42 #include "tink/util/statusor.h"
43 #include "tink/util/test_matchers.h"
44 #include "tink/util/test_util.h"
45 #include "proto/tink.pb.h"
46
47 namespace crypto {
48 namespace tink {
49 namespace {
50
51 using ::crypto::tink::test::DummyAead;
52 using ::crypto::tink::test::IsOk;
53 using ::crypto::tink::test::StatusIs;
54 using ::google::crypto::tink::KeysetInfo;
55 using ::google::crypto::tink::KeyStatusType;
56 using ::google::crypto::tink::OutputPrefixType;
57 using ::testing::_;
58 using ::testing::ByMove;
59 using ::testing::HasSubstr;
60 using ::testing::IsNull;
61 using ::testing::IsSubstring;
62 using ::testing::Not;
63 using ::testing::Return;
64 using ::testing::StrictMock;
65 using ::testing::Test;
66
PopulateKeyInfo(KeysetInfo::KeyInfo * key_info,uint32_t key_id,OutputPrefixType out_prefix_type,KeyStatusType status)67 void PopulateKeyInfo(KeysetInfo::KeyInfo* key_info, uint32_t key_id,
68 OutputPrefixType out_prefix_type, KeyStatusType status) {
69 key_info->set_output_prefix_type(out_prefix_type);
70 key_info->set_key_id(key_id);
71 key_info->set_status(status);
72 }
73
74 // Creates a test keyset info object.
CreateTestKeysetInfo()75 KeysetInfo CreateTestKeysetInfo() {
76 KeysetInfo keyset_info;
77 PopulateKeyInfo(keyset_info.add_key_info(), /*key_id=*/1234543,
78 OutputPrefixType::TINK,
79 /*status=*/KeyStatusType::ENABLED);
80 PopulateKeyInfo(keyset_info.add_key_info(), /*key_id=*/726329,
81 OutputPrefixType::LEGACY,
82 /*status=*/KeyStatusType::ENABLED);
83 PopulateKeyInfo(keyset_info.add_key_info(), /*key_id=*/7213743,
84 OutputPrefixType::TINK,
85 /*status=*/KeyStatusType::ENABLED);
86 return keyset_info;
87 }
88
TEST(AeadSetWrapperTest,WrapNullptr)89 TEST(AeadSetWrapperTest, WrapNullptr) {
90 AeadWrapper wrapper;
91 util::StatusOr<std::unique_ptr<Aead>> aead = wrapper.Wrap(nullptr);
92 EXPECT_THAT(aead, Not(IsOk()));
93 EXPECT_THAT(aead.status(), StatusIs(absl::StatusCode::kInternal));
94 EXPECT_PRED_FORMAT2(IsSubstring, "non-NULL",
95 std::string(aead.status().message()));
96 }
97
TEST(AeadSetWrapperTest,WrapEmpty)98 TEST(AeadSetWrapperTest, WrapEmpty) {
99 AeadWrapper wrapper;
100 util::StatusOr<std::unique_ptr<Aead>> aead =
101 wrapper.Wrap(absl::make_unique<PrimitiveSet<Aead>>());
102 EXPECT_THAT(aead, Not(IsOk()));
103 EXPECT_THAT(aead.status(), StatusIs(absl::StatusCode::kInvalidArgument));
104 EXPECT_PRED_FORMAT2(IsSubstring, "no primary",
105 std::string(aead.status().message()));
106 }
107
TEST(AeadSetWrapperTest,Basic)108 TEST(AeadSetWrapperTest, Basic) {
109 KeysetInfo keyset_info = CreateTestKeysetInfo();
110 std::string aead_name_0 = "aead0";
111 std::string aead_name_1 = "aead1";
112 std::string aead_name_2 = "aead2";
113 auto aead_set = absl::make_unique<PrimitiveSet<Aead>>();
114 std::unique_ptr<Aead> aead = absl::make_unique<DummyAead>(aead_name_0);
115 util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> aead_entry =
116 aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(0));
117 EXPECT_THAT(aead_entry, IsOk());
118 aead = absl::make_unique<DummyAead>(aead_name_1);
119 aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(1));
120 EXPECT_THAT(aead_entry, IsOk());
121 aead = absl::make_unique<DummyAead>(aead_name_2);
122 aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(2));
123 EXPECT_THAT(aead_entry, IsOk());
124 // The last key is the primary.
125 EXPECT_THAT(aead_set->set_primary(*aead_entry), IsOk());
126
127 // Wrap aead_set and test the resulting Aead.
128 AeadWrapper wrapper;
129 util::StatusOr<std::unique_ptr<Aead>> aead_result =
130 wrapper.Wrap(std::move(aead_set));
131 EXPECT_THAT(aead_result, IsOk());
132 aead = std::move(*aead_result);
133 std::string plaintext = "some_plaintext";
134 std::string aad = "some_aad";
135
136 util::StatusOr<std::string> encrypt_result = aead->Encrypt(plaintext, aad);
137 EXPECT_THAT(encrypt_result, IsOk());
138 std::string ciphertext = *encrypt_result;
139 EXPECT_PRED_FORMAT2(testing::IsSubstring, aead_name_2, ciphertext);
140
141 util::StatusOr<std::string> resulting_plaintext =
142 aead->Decrypt(ciphertext, aad);
143 EXPECT_THAT(resulting_plaintext, IsOk());
144 EXPECT_EQ(*resulting_plaintext, plaintext);
145
146 resulting_plaintext = aead->Decrypt("some bad ciphertext", aad);
147 EXPECT_THAT(resulting_plaintext, Not(IsOk()));
148 EXPECT_THAT(resulting_plaintext.status(),
149 StatusIs(absl::StatusCode::kInvalidArgument));
150 EXPECT_PRED_FORMAT2(IsSubstring, "decryption failed",
151 std::string(resulting_plaintext.status().message()));
152 }
153
TEST(AeadSetWrapperTest,DecryptNonPrimary)154 TEST(AeadSetWrapperTest, DecryptNonPrimary) {
155 KeysetInfo keyset_info = CreateTestKeysetInfo();
156 std::string aead_name_0 = "aead0";
157 std::string aead_name_1 = "aead1";
158 std::string aead_name_2 = "aead2";
159 std::unique_ptr<PrimitiveSet<Aead>> aead_set(new PrimitiveSet<Aead>());
160 std::unique_ptr<Aead> aead = absl::make_unique<DummyAead>(aead_name_0);
161
162 // Encrypt some message with the first aead.s
163 std::string plaintext = "some_plaintext";
164 std::string aad = "some_aad";
165 util::StatusOr<std::string> ciphertext = aead->Encrypt(plaintext, aad);
166 EXPECT_THAT(ciphertext, IsOk());
167 util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> aead_entry =
168 aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(0));
169 ASSERT_THAT(aead_entry, IsOk());
170 EXPECT_THAT(aead_set->set_primary(*aead_entry), IsOk());
171
172 // The complete ciphertext is of the form: | key_id | ciphertext |.
173 std::string complete_ciphertext =
174 absl::StrCat(aead_set->get_primary()->get_identifier(), *ciphertext);
175
176 aead = absl::make_unique<DummyAead>(aead_name_1);
177 aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(1));
178 EXPECT_THAT(aead_entry, IsOk());
179 aead = absl::make_unique<DummyAead>(aead_name_2);
180 aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(2));
181 EXPECT_THAT(aead_entry, IsOk());
182 // The last key is the primary.
183 EXPECT_THAT(aead_set->set_primary(*aead_entry), IsOk());
184
185 // Wrap aead_set and test the resulting Aead.
186 AeadWrapper wrapper;
187 util::StatusOr<std::unique_ptr<Aead>> aead_wrapped =
188 wrapper.Wrap(std::move(aead_set));
189 EXPECT_THAT(aead_wrapped, IsOk());
190 aead = std::move(*aead_wrapped);
191 EXPECT_THAT(complete_ciphertext, HasSubstr(aead_name_0));
192
193 // Primary key is different from the one we used to encrypt. This
194 // should still be decryptable as we have the correct key in the set.
195 util::StatusOr<std::string> decrypted_plaintext =
196 aead->Decrypt(complete_ciphertext, aad);
197 EXPECT_THAT(decrypted_plaintext, IsOk());
198 }
199
200 // Tests with monitoring enabled.
201 class AeadSetWrapperTestWithMonitoring : public Test {
202 protected:
203 // Perform some common initialization: reset the global registry, set expected
204 // calls for the mock monitoring factory and the returned clients.
SetUp()205 void SetUp() override {
206 Registry::Reset();
207 auto monitoring_client_factory =
208 absl::make_unique<MockMonitoringClientFactory>();
209
210 auto encryption_monitoring_client =
211 absl::make_unique<StrictMock<MockMonitoringClient>>();
212 encryption_monitoring_client_ptr_ = encryption_monitoring_client.get();
213 auto decryption_monitoring_client =
214 absl::make_unique<StrictMock<MockMonitoringClient>>();
215 decryption_monitoring_client_ptr_ = decryption_monitoring_client.get();
216
217 EXPECT_CALL(*monitoring_client_factory, New(_))
218 .WillOnce(
219 Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
220 std::move(encryption_monitoring_client)))))
221 .WillOnce(
222 Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
223 std::move(decryption_monitoring_client)))));
224
225 ASSERT_THAT(internal::RegistryImpl::GlobalInstance()
226 .RegisterMonitoringClientFactory(
227 std::move(monitoring_client_factory)),
228 IsOk());
229 ASSERT_THAT(
230 internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory(),
231 Not(IsNull()));
232 }
233
234 // Cleanup the registry to avoid mock leaks.
TearDown()235 void TearDown() override { Registry::Reset(); }
236
237 MockMonitoringClient* encryption_monitoring_client_ptr_;
238 MockMonitoringClient* decryption_monitoring_client_ptr_;
239 };
240
241 // Test that successful encrypt/decrypt operations are logged.
TEST_F(AeadSetWrapperTestWithMonitoring,WrapKeysetWithMonitoringEncryptDecryptSuccess)242 TEST_F(AeadSetWrapperTestWithMonitoring,
243 WrapKeysetWithMonitoringEncryptDecryptSuccess) {
244 // Populate a primitive set.
245 KeysetInfo keyset_info = CreateTestKeysetInfo();
246 const absl::flat_hash_map<std::string, std::string> kAnnotations = {
247 {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
248 auto aead_primitive_set = absl::make_unique<PrimitiveSet<Aead>>(kAnnotations);
249 ASSERT_THAT(aead_primitive_set
250 ->AddPrimitive(absl::make_unique<DummyAead>("aead0"),
251 keyset_info.key_info(0))
252 .status(),
253 IsOk());
254 ASSERT_THAT(aead_primitive_set
255 ->AddPrimitive(absl::make_unique<DummyAead>("aead1"),
256 keyset_info.key_info(1))
257 .status(),
258 IsOk());
259 // Set the last as primary.
260 util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> last =
261 aead_primitive_set->AddPrimitive(absl::make_unique<DummyAead>("aead2"),
262 keyset_info.key_info(2));
263 ASSERT_THAT(last, IsOk());
264 ASSERT_THAT(aead_primitive_set->set_primary(*last), IsOk());
265 // Record the ID of the primary key.
266 const uint32_t kPrimaryKeyId = keyset_info.key_info(2).key_id();
267
268 util::StatusOr<std::unique_ptr<Aead>> aead =
269 AeadWrapper().Wrap(std::move(aead_primitive_set));
270 ASSERT_THAT(aead, IsOk());
271
272 constexpr absl::string_view kPlaintext = "This is some plaintext!";
273 constexpr absl::string_view kAssociatedData = "Some associated data!";
274 EXPECT_CALL(*encryption_monitoring_client_ptr_,
275 Log(kPrimaryKeyId, kPlaintext.size()));
276 util::StatusOr<std::string> ciphertext =
277 (*aead)->Encrypt(kPlaintext, kAssociatedData);
278 ASSERT_THAT(ciphertext, IsOk());
279
280 // In the log expect the size of the ciphertext without the non-raw prefix.
281 auto raw_ciphertext =
282 absl::string_view(*ciphertext).substr(CryptoFormat::kNonRawPrefixSize);
283 EXPECT_CALL(*decryption_monitoring_client_ptr_,
284 Log(kPrimaryKeyId, raw_ciphertext.size()));
285 EXPECT_THAT((*aead)->Decrypt(*ciphertext, kAssociatedData), IsOk());
286 }
287
288 // Test that monitoring logs encryption and decryption failures correctly.
TEST_F(AeadSetWrapperTestWithMonitoring,WrapKeysetWithMonitoringEncryptDecryptFailures)289 TEST_F(AeadSetWrapperTestWithMonitoring,
290 WrapKeysetWithMonitoringEncryptDecryptFailures) {
291 // Populate a primitive set.
292 KeysetInfo keyset_info = CreateTestKeysetInfo();
293
294 const absl::flat_hash_map<std::string, std::string> kAnnotations = {
295 {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
296
297 auto aead_primitive_set = absl::make_unique<PrimitiveSet<Aead>>(kAnnotations);
298
299 // Assume encryption and decryption always fail.
300 auto mock_aead = absl::make_unique<MockAead>();
301 constexpr absl::string_view kPlaintext = "A plaintext!!";
302 constexpr absl::string_view kCiphertext = "A ciphertext!";
303 constexpr absl::string_view kAssociatedData = "Some associated data!";
304 ON_CALL(*mock_aead, Encrypt(kPlaintext, kAssociatedData))
305 .WillByDefault(Return(util::Status(absl::StatusCode::kInternal,
306 "Oh no encryption failed :(!")));
307 ON_CALL(*mock_aead, Decrypt(kCiphertext, kAssociatedData))
308 .WillByDefault(Return(util::Status(absl::StatusCode::kInternal,
309 "Oh no decryption failed :(!")));
310
311 util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> primary =
312 aead_primitive_set->AddPrimitive(std::move(mock_aead),
313 keyset_info.key_info(2));
314 ASSERT_THAT(primary, IsOk());
315 // Set the only primitive as primary.
316 ASSERT_THAT(aead_primitive_set->set_primary(*primary), IsOk());
317
318 util::StatusOr<std::unique_ptr<Aead>> aead =
319 AeadWrapper().Wrap(std::move(aead_primitive_set));
320 ASSERT_THAT(aead, IsOk());
321
322 // Expect encryption failure gets logged.
323 EXPECT_CALL(*encryption_monitoring_client_ptr_, LogFailure());
324 util::StatusOr<std::string> ciphertext =
325 (*aead)->Encrypt(kPlaintext, kAssociatedData);
326 EXPECT_THAT(ciphertext, Not(IsOk()));
327
328 // We must prepend the identifier to the ciphertext to make sure our mock gets
329 // called.
330 util::StatusOr<std::string> key_identifier =
331 CryptoFormat::GetOutputPrefix(keyset_info.key_info(2));
332 ASSERT_THAT(key_identifier, IsOk());
333 std::string ciphertext_with_key_id =
334 absl::StrCat(*key_identifier, kCiphertext);
335
336 // Expect decryption failure gets logged.
337 EXPECT_CALL(*decryption_monitoring_client_ptr_, LogFailure());
338 EXPECT_THAT(
339 (*aead)->Decrypt(ciphertext_with_key_id, kAssociatedData).status(),
340 Not(IsOk()));
341 }
342
343 } // namespace
344 } // namespace tink
345 } // namespace crypto
346