• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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/json_keyset_writer.h"
18 
19 #include <memory>
20 #include <ostream>
21 #include <sstream>
22 #include <string>
23 #include <utility>
24 
25 #include "gtest/gtest.h"
26 #include "absl/strings/escaping.h"
27 #include "absl/strings/substitute.h"
28 #include "include/rapidjson/document.h"
29 #include "include/rapidjson/error/en.h"
30 #include "tink/json_keyset_reader.h"
31 #include "tink/util/protobuf_helper.h"
32 #include "tink/util/test_matchers.h"
33 #include "tink/util/test_util.h"
34 #include "proto/aes_eax.pb.h"
35 #include "proto/aes_gcm.pb.h"
36 #include "proto/tink.pb.h"
37 
38 namespace crypto {
39 namespace tink {
40 
41 using ::crypto::tink::test::AddRawKey;
42 using ::crypto::tink::test::AddTinkKey;
43 using ::crypto::tink::test::IsOk;
44 using ::google::crypto::tink::AesEaxKey;
45 using ::google::crypto::tink::AesGcmKey;
46 using ::google::crypto::tink::EncryptedKeyset;
47 using ::google::crypto::tink::KeyData;
48 using ::google::crypto::tink::Keyset;
49 using ::google::crypto::tink::KeyStatusType;
50 using ::google::crypto::tink::OutputPrefixType;
51 using ::testing::HasSubstr;
52 
53 namespace {
54 
55 class JsonKeysetWriterTest : public ::testing::Test {
56  protected:
SetUp()57   void SetUp() override {
58     gcm_key_.set_key_value("some gcm key value");
59     gcm_key_.set_version(0);
60 
61     eax_key_.set_key_value("some eax key value");
62     eax_key_.set_version(0);
63     eax_key_.mutable_params()->set_iv_size(16);
64 
65     AddTinkKey("type.googleapis.com/google.crypto.tink.AesGcmKey", 42, gcm_key_,
66                KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset_);
67     AddRawKey("type.googleapis.com/google.crypto.tink.AesEaxKey", 711, eax_key_,
68               KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset_);
69     keyset_.set_primary_key_id(42);
70     std::string json_string =
71         absl::Substitute(R"(
72       {
73          "primaryKeyId":42,
74          "key":[
75             {
76                "keyData":{
77                   "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
78                   "keyMaterialType":"SYMMETRIC",
79                   "value": "$0"
80                },
81                "outputPrefixType":"TINK",
82                "keyId":42,
83                "status":"ENABLED"
84             },
85             {
86                "keyData":{
87                   "typeUrl":"type.googleapis.com/google.crypto.tink.AesEaxKey",
88                   "keyMaterialType":"SYMMETRIC",
89                   "value":"$1"
90                },
91                "outputPrefixType":"RAW",
92                "keyId":711,
93                "status":"ENABLED"
94             }
95          ]
96       })",
97                          absl::Base64Escape(gcm_key_.SerializeAsString()),
98                          absl::Base64Escape(eax_key_.SerializeAsString()));
99     ASSERT_FALSE(good_json_keyset_.Parse(json_string.c_str()).HasParseError());
100 
101     std::string enc_keyset = "some ciphertext with keyset";
102     encrypted_keyset_.set_encrypted_keyset(enc_keyset);
103     std::string enc_keyset_base64;
104     absl::Base64Escape(enc_keyset, &enc_keyset_base64);
105     auto keyset_info = encrypted_keyset_.mutable_keyset_info();
106     keyset_info->set_primary_key_id(42);
107     auto key_info = keyset_info->add_key_info();
108     key_info->set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey");
109     key_info->set_key_id(42);
110     key_info->set_output_prefix_type(OutputPrefixType::TINK);
111     key_info->set_status(KeyStatusType::ENABLED);
112     good_json_encrypted_keyset_string_ = "{"
113            "\"encryptedKeyset\": \"" + enc_keyset_base64 + "\", "
114            "\"keysetInfo\": {"
115            "  \"primaryKeyId\": 42,"
116            "  \"keyInfo\": ["
117            "    {"
118            "      \"typeUrl\":"
119            "        \"type.googleapis.com/google.crypto.tink.AesGcmKey\","
120            "      \"outputPrefixType\": \"TINK\","
121            "      \"keyId\": 42,"
122            "      \"status\": \"ENABLED\""
123            "    }"
124            "  ]"
125            "}}";
126     ASSERT_FALSE(good_json_encrypted_keyset_.Parse(
127         good_json_encrypted_keyset_string_.c_str()).HasParseError());
128   }
129 
130   EncryptedKeyset encrypted_keyset_;
131   Keyset keyset_;
132   rapidjson::Document good_json_keyset_;
133   rapidjson::Document good_json_encrypted_keyset_;
134   std::string good_json_encrypted_keyset_string_;
135   AesGcmKey gcm_key_;
136   AesEaxKey eax_key_;
137 };
138 
TEST_F(JsonKeysetWriterTest,testWriterCreation)139 TEST_F(JsonKeysetWriterTest, testWriterCreation) {
140   {  // Input stream is null.
141     std::unique_ptr<std::ostream> null_stream(nullptr);
142     auto writer_result = JsonKeysetWriter::New(std::move(null_stream));
143     EXPECT_FALSE(writer_result.ok());
144     EXPECT_EQ(absl::StatusCode::kInvalidArgument,
145               writer_result.status().code());
146   }
147 
148   {  // Stream with good keyset.
149     std::unique_ptr<std::ostream> destination_stream(new std::stringstream());
150     auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
151     EXPECT_TRUE(writer_result.ok()) << writer_result.status();
152   }
153 }
154 
TEST_F(JsonKeysetWriterTest,testWriteKeyset)155 TEST_F(JsonKeysetWriterTest, testWriteKeyset) {
156   std::stringbuf buffer;
157   std::unique_ptr<std::ostream> destination_stream(new std::ostream(&buffer));
158   auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
159   ASSERT_TRUE(writer_result.ok()) << writer_result.status();
160   auto writer = std::move(writer_result.value());
161   auto status = writer->Write(keyset_);
162   EXPECT_TRUE(status.ok()) << status;
163   rapidjson::Document json_keyset(rapidjson::kObjectType);
164   EXPECT_FALSE(json_keyset.Parse(buffer.str().c_str()).HasParseError());
165   EXPECT_TRUE(good_json_keyset_ == json_keyset);
166 }
167 
TEST_F(JsonKeysetWriterTest,testWriteAndReadKeyset)168 TEST_F(JsonKeysetWriterTest, testWriteAndReadKeyset) {
169   std::stringbuf buffer;
170   std::unique_ptr<std::ostream> destination_stream(new std::ostream(&buffer));
171   auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
172   ASSERT_TRUE(writer_result.ok()) << writer_result.status();
173   auto writer = std::move(writer_result.value());
174   auto status = writer->Write(keyset_);
175   EXPECT_TRUE(status.ok()) << status;
176 
177   auto reader_result = JsonKeysetReader::New(buffer.str());
178   EXPECT_TRUE(reader_result.ok()) << reader_result.status();
179   auto reader = std::move(reader_result.value());
180   auto read_result = reader->Read();
181   EXPECT_TRUE(read_result.ok()) << read_result.status();
182   auto keyset = std::move(read_result.value());
183   EXPECT_EQ(keyset_.SerializeAsString(), keyset->SerializeAsString());
184 }
185 
TEST_F(JsonKeysetWriterTest,testWriteEncryptedKeyset)186 TEST_F(JsonKeysetWriterTest, testWriteEncryptedKeyset) {
187   std::stringbuf buffer;
188   std::unique_ptr<std::ostream> destination_stream(new std::ostream(&buffer));
189   auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
190   ASSERT_TRUE(writer_result.ok()) << writer_result.status();
191   auto writer = std::move(writer_result.value());
192   auto status = writer->Write(encrypted_keyset_);
193   EXPECT_TRUE(status.ok()) << status;
194   rapidjson::Document json_encrypted_keyset(rapidjson::kObjectType);
195   EXPECT_FALSE(
196       json_encrypted_keyset.Parse(buffer.str().c_str()).HasParseError())
197       << "Parsing error at position "
198       << static_cast<unsigned>(json_encrypted_keyset.GetErrorOffset())
199       << " of JSON string\n"
200       << buffer.str() << "\n"
201       << rapidjson::GetParseError_En(json_encrypted_keyset.GetParseError());
202   EXPECT_TRUE(good_json_encrypted_keyset_ == json_encrypted_keyset)
203       << "Expected JSON:\n" << good_json_encrypted_keyset_string_ << "\n"
204       << "Got JSON:\n" << buffer.str();
205 }
206 
TEST_F(JsonKeysetWriterTest,testWriteAndReadEncryptedKeyset)207 TEST_F(JsonKeysetWriterTest, testWriteAndReadEncryptedKeyset) {
208   std::stringbuf buffer;
209   std::unique_ptr<std::ostream> destination_stream(new std::ostream(&buffer));
210   auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
211   ASSERT_TRUE(writer_result.ok()) << writer_result.status();
212   auto writer = std::move(writer_result.value());
213   auto status = writer->Write(encrypted_keyset_);
214   EXPECT_TRUE(status.ok()) << status;
215 
216   auto reader_result = JsonKeysetReader::New(buffer.str());
217   EXPECT_TRUE(reader_result.ok()) << reader_result.status();
218   auto reader = std::move(reader_result.value());
219   auto read_result = reader->ReadEncrypted();
220   EXPECT_TRUE(read_result.ok()) << read_result.status();
221   auto encrypted_keyset = std::move(read_result.value());
222   EXPECT_EQ(encrypted_keyset_.SerializeAsString(),
223             encrypted_keyset->SerializeAsString());
224 }
225 
TEST_F(JsonKeysetWriterTest,testDestinationStreamErrors)226 TEST_F(JsonKeysetWriterTest, testDestinationStreamErrors) {
227   std::stringbuf buffer;
228   std::unique_ptr<std::ostream> destination_stream(new std::ostream(&buffer));
229   destination_stream->setstate(std::ostream::badbit);
230   auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
231   ASSERT_TRUE(writer_result.ok()) << writer_result.status();
232   auto writer = std::move(writer_result.value());
233   {  // Write keyset.
234     auto status = writer->Write(keyset_);
235     EXPECT_FALSE(status.ok()) << status;
236     EXPECT_EQ(absl::StatusCode::kUnknown, status.code());
237   }
238   {  // Write encrypted keyset.
239     auto status = writer->Write(encrypted_keyset_);
240     EXPECT_FALSE(status.ok()) << status;
241     EXPECT_EQ(absl::StatusCode::kUnknown, status.code());
242   }
243 }
244 
TEST_F(JsonKeysetWriterTest,WriteLargeKeyId)245 TEST_F(JsonKeysetWriterTest, WriteLargeKeyId) {
246   Keyset keyset;
247   AddTinkKey("type.googleapis.com/google.crypto.tink.AesGcmKey", 4123456789,
248              gcm_key_, KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset);
249   keyset.set_primary_key_id(4123456789);  // 4123456789 > 2^31
250 
251   std::stringbuf buffer;
252   std::unique_ptr<std::ostream> destination_stream(new std::ostream(&buffer));
253   auto writer_result = JsonKeysetWriter::New(std::move(destination_stream));
254   ASSERT_THAT(writer_result, IsOk());
255   auto writer = std::move(writer_result.value());
256   ASSERT_THAT(writer->Write(keyset), IsOk());
257   EXPECT_THAT(buffer.str(), HasSubstr("\"primaryKeyId\": 4123456789"));
258   EXPECT_THAT(buffer.str(), HasSubstr("\"keyId\": 4123456789"));
259 }
260 
261 }  // namespace
262 }  // namespace tink
263 }  // namespace crypto
264