1 // Copyright 2022 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 "walkthrough/load_encrypted_keyset.h"
18
19 #include <memory>
20 #include <ostream>
21 #include <sstream>
22 #include <string>
23 #include <utility>
24
25 #include "gmock/gmock.h"
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/string_view.h"
29 #include "tink/aead.h"
30 #include "tink/aead/aead_config.h"
31 #include "walkthrough/load_cleartext_keyset.h"
32 #include "walkthrough/test_util.h"
33 #include "tink/kms_clients.h"
34 #include "tink/registry.h"
35 #include "tink/util/statusor.h"
36 #include "tink/util/test_matchers.h"
37
38 namespace tink_walkthrough {
39 namespace {
40
41 constexpr absl::string_view kSerializedMasterKeyKeyset = R"json({
42 "key": [
43 {
44 "keyData": {
45 "keyMaterialType": "SYMMETRIC",
46 "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
47 "value": "GiBWyUfGgYk3RTRhj/LIUzSudIWlyjCftCOypTr0jCNSLg=="
48 },
49 "keyId": 294406504,
50 "outputPrefixType": "TINK",
51 "status": "ENABLED"
52 }
53 ],
54 "primaryKeyId": 294406504
55 })json";
56
57 constexpr absl::string_view kSerializedKeysetToEncrypt = R"json({
58 "key": [
59 {
60 "keyData": {
61 "keyMaterialType": "SYMMETRIC",
62 "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
63 "value": "GhD+9l0RANZjzZEZ8PDp7LRW"
64 },
65 "keyId": 1931667682,
66 "outputPrefixType": "TINK",
67 "status": "ENABLED"
68 }
69 ],
70 "primaryKeyId": 1931667682
71 })json";
72
73 // Encryption of kSerializedKeysetToEncrypt using kSerializedMasterKeyKeyset.
74 constexpr absl::string_view kEncryptedKeyset = R"json({
75 "encryptedKeyset": "ARGMSWi6YHyZ/Oqxl00XSq631a0q2UPmf+rCvCIAggSZrwCmxFF797MpY0dqgaXu1fz2eQ8zFNhlyTXv9kwg1kY6COpyhY/68zNBUkyKX4CharLYfpg1LgRl+6rMzIQa0XDHh7ZDmp1CevzecZIKnG83uDRHxxSv3h8c/Kc="
76 })json";
77
78 constexpr absl::string_view kFakeKmsKeyUri = "fake://some_key";
79
80 using ::crypto::tink::Aead;
81 using ::crypto::tink::KeysetHandle;
82 using ::crypto::tink::Registry;
83 using ::crypto::tink::test::IsOk;
84 using ::crypto::tink::test::IsOkAndHolds;
85 using ::crypto::tink::test::StatusIs;
86 using ::crypto::tink::util::Status;
87 using ::crypto::tink::util::StatusOr;
88 using ::testing::Environment;
89
90 // Test environment used to register KMS clients only once for the whole test.
91 class LoadKeysetTestEnvironment : public Environment {
92 public:
93 ~LoadKeysetTestEnvironment() override = default;
94
95 // Register FakeKmsClient and AlwaysFailingFakeKmsClient.
SetUp()96 void SetUp() override {
97 auto fake_kms =
98 absl::make_unique<FakeKmsClient>(kSerializedMasterKeyKeyset);
99 ASSERT_THAT(crypto::tink::KmsClients::Add(std::move(fake_kms)), IsOk());
100 auto failing_kms = absl::make_unique<AlwaysFailingFakeKmsClient>();
101 ASSERT_THAT(crypto::tink::KmsClients::Add(std::move(failing_kms)), IsOk());
102 }
103 };
104
105 // Unused.
106 Environment *const test_env =
107 testing::AddGlobalTestEnvironment(new LoadKeysetTestEnvironment());
108
109 class LoadKeysetTest : public ::testing::Test {
110 public:
TearDown()111 void TearDown() override { Registry::Reset(); }
112 };
113
TEST_F(LoadKeysetTest,LoadKeysetFailsWhenNoKmsRegistered)114 TEST_F(LoadKeysetTest, LoadKeysetFailsWhenNoKmsRegistered) {
115 StatusOr<std::unique_ptr<KeysetHandle>> expected_keyset =
116 LoadKeyset(kEncryptedKeyset, /*master_key_uri=*/"other_kms://some_key");
117 EXPECT_THAT(expected_keyset.status(), StatusIs(absl::StatusCode::kNotFound));
118 }
119
TEST_F(LoadKeysetTest,LoadKeysetFailsWhenKmsClientFails)120 TEST_F(LoadKeysetTest, LoadKeysetFailsWhenKmsClientFails) {
121 StatusOr<std::unique_ptr<KeysetHandle>> expected_keyset =
122 LoadKeyset(kEncryptedKeyset, /*master_key_uri=*/"failing://some_key");
123 EXPECT_THAT(expected_keyset.status(),
124 StatusIs(absl::StatusCode::kUnimplemented));
125 }
126
TEST_F(LoadKeysetTest,LoadKeysetFailsWhenAeadNotRegistered)127 TEST_F(LoadKeysetTest, LoadKeysetFailsWhenAeadNotRegistered) {
128 StatusOr<std::unique_ptr<KeysetHandle>> expected_keyset =
129 LoadKeyset(kEncryptedKeyset, kFakeKmsKeyUri);
130 EXPECT_THAT(expected_keyset.status(), StatusIs(absl::StatusCode::kNotFound));
131 }
132
TEST_F(LoadKeysetTest,LoadKeysetFailsWhenInvalidKeyset)133 TEST_F(LoadKeysetTest, LoadKeysetFailsWhenInvalidKeyset) {
134 ASSERT_THAT(crypto::tink::AeadConfig::Register(), IsOk());
135 StatusOr<std::unique_ptr<KeysetHandle>> expected_keyset =
136 LoadKeyset("invalid", kFakeKmsKeyUri);
137 EXPECT_THAT(expected_keyset.status(),
138 StatusIs(absl::StatusCode::kInvalidArgument));
139 Registry::Reset();
140 }
141
TEST_F(LoadKeysetTest,LoadKeysetSucceeds)142 TEST_F(LoadKeysetTest, LoadKeysetSucceeds) {
143 ASSERT_THAT(crypto::tink::AeadConfig::Register(), IsOk());
144 StatusOr<std::unique_ptr<KeysetHandle>> handle =
145 LoadKeyset(kEncryptedKeyset, kFakeKmsKeyUri);
146 ASSERT_THAT(handle, IsOk());
147 StatusOr<std::unique_ptr<Aead>> aead = (*handle)->GetPrimitive<Aead>();
148 ASSERT_THAT(aead, IsOk());
149
150 StatusOr<std::unique_ptr<KeysetHandle>> expected_keyset =
151 LoadKeyset(kSerializedKeysetToEncrypt);
152 ASSERT_THAT(expected_keyset, IsOk());
153 StatusOr<std::unique_ptr<Aead>> expected_aead =
154 (*expected_keyset)->GetPrimitive<Aead>();
155 ASSERT_THAT(expected_aead, IsOk());
156
157 std::string associated_data = "Some associated data";
158 std::string plaintext = "Some plaintext";
159
160 StatusOr<std::string> ciphertext =
161 (*aead)->Encrypt(plaintext, associated_data);
162 ASSERT_THAT(ciphertext, IsOk());
163 EXPECT_THAT((*expected_aead)->Decrypt(*ciphertext, associated_data),
164 IsOkAndHolds(plaintext));
165 }
166
167 } // namespace
168 } // namespace tink_walkthrough
169