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/json_keyset_reader.h"
18
19 #include <iostream>
20 #include <istream>
21 #include <memory>
22 #include <sstream>
23 #include <string>
24 #include <utility>
25
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/escaping.h"
29 #include "absl/strings/str_cat.h"
30 #include "include/rapidjson/document.h"
31 #include "include/rapidjson/error/en.h"
32 #include "tink/util/enums.h"
33 #include "tink/util/errors.h"
34 #include "tink/util/protobuf_helper.h"
35 #include "tink/util/status.h"
36 #include "tink/util/statusor.h"
37 #include "proto/tink.pb.h"
38
39 namespace crypto {
40 namespace tink {
41
42 using google::crypto::tink::EncryptedKeyset;
43 using google::crypto::tink::KeyData;
44 using google::crypto::tink::Keyset;
45 using google::crypto::tink::KeysetInfo;
46 using crypto::tink::util::Enums;
47
48 namespace {
49
50
51 // Helpers for validating and parsing JSON strings with EncryptedKeyset-protos.
ValidateEncryptedKeyset(const rapidjson::Document & json_doc)52 util::Status ValidateEncryptedKeyset(const rapidjson::Document& json_doc) {
53 if (!json_doc.HasMember("encryptedKeyset") ||
54 !json_doc["encryptedKeyset"].IsString() ||
55 (json_doc.HasMember("keysetInfo") &&
56 !json_doc["keysetInfo"].IsObject())) {
57 return util::Status(absl::StatusCode::kInvalidArgument,
58 "Invalid JSON EncryptedKeyset");
59 }
60 return util::OkStatus();
61 }
62
ValidateKeysetInfo(const rapidjson::Value & json_value)63 util::Status ValidateKeysetInfo(const rapidjson::Value& json_value) {
64 if (!json_value.HasMember("primaryKeyId") ||
65 !json_value["primaryKeyId"].IsUint() ||
66 !json_value.HasMember("keyInfo") ||
67 !json_value["keyInfo"].IsArray() ||
68 json_value["keyInfo"].Size() < 1) {
69 return util::Status(absl::StatusCode::kInvalidArgument,
70 "Invalid JSON KeysetInfo");
71 }
72 return util::OkStatus();
73 }
74
ValidateKeyInfo(const rapidjson::Value & json_value)75 util::Status ValidateKeyInfo(const rapidjson::Value& json_value) {
76 if (!json_value.HasMember("typeUrl") ||
77 !json_value["typeUrl"].IsString() ||
78 !json_value.HasMember("status") ||
79 !json_value["status"].IsString() ||
80 !json_value.HasMember("keyId") ||
81 !json_value["keyId"].IsUint() ||
82 !json_value.HasMember("outputPrefixType") ||
83 !json_value["outputPrefixType"].IsString()) {
84 return util::Status(absl::StatusCode::kInvalidArgument,
85 "Invalid JSON KeyInfo");
86 }
87 return util::OkStatus();
88 }
89
90 util::StatusOr<std::unique_ptr<KeysetInfo::KeyInfo>>
KeyInfoFromJson(const rapidjson::Value & json_value)91 KeyInfoFromJson(const rapidjson::Value& json_value) {
92 auto status = ValidateKeyInfo(json_value);
93 if (!status.ok()) return status;
94
95 auto key_info = absl::make_unique<KeysetInfo::KeyInfo>();
96 key_info->set_type_url(json_value["typeUrl"].GetString());
97 key_info->set_status(Enums::KeyStatus(json_value["status"].GetString()));
98 key_info->set_key_id(json_value["keyId"].GetUint());
99 key_info->set_output_prefix_type(
100 Enums::OutputPrefix(json_value["outputPrefixType"].GetString()));
101 return std::move(key_info);
102 }
103
104 util::StatusOr<std::unique_ptr<KeysetInfo>>
KeysetInfoFromJson(const rapidjson::Value & json_value)105 KeysetInfoFromJson(const rapidjson::Value& json_value) {
106 auto status = ValidateKeysetInfo(json_value);
107 if (!status.ok()) return status;
108 auto keyset_info = absl::make_unique<KeysetInfo>();
109 keyset_info->set_primary_key_id(json_value["primaryKeyId"].GetUint());
110 for (const auto& json_key_info : json_value["keyInfo"].GetArray()) {
111 auto key_info_result = KeyInfoFromJson(json_key_info);
112 if (!key_info_result.ok()) return key_info_result.status();
113 *(keyset_info->add_key_info()) = *(key_info_result.value());
114 }
115 return std::move(keyset_info);
116 }
117
118 util::StatusOr<std::unique_ptr<EncryptedKeyset>>
EncryptedKeysetFromJson(const rapidjson::Document & json_doc)119 EncryptedKeysetFromJson(const rapidjson::Document& json_doc) {
120 auto status = ValidateEncryptedKeyset(json_doc);
121 if (!status.ok()) return status;
122 std::string enc_keyset;
123 if (!absl::Base64Unescape(
124 json_doc["encryptedKeyset"].GetString(), &enc_keyset)) {
125 return util::Status(absl::StatusCode::kInvalidArgument,
126 "Invalid JSON EncryptedKeyset");
127 }
128 auto encrypted_keyset = absl::make_unique<EncryptedKeyset>();
129 encrypted_keyset->set_encrypted_keyset(enc_keyset);
130 if (json_doc.HasMember("keysetInfo")) {
131 auto keyset_info_result =
132 KeysetInfoFromJson(json_doc["keysetInfo"]);
133 if (!keyset_info_result.ok()) {
134 return keyset_info_result.status();
135 }
136 *(encrypted_keyset->mutable_keyset_info()) = *(keyset_info_result.value());
137 }
138 return std::move(encrypted_keyset);
139 }
140
141 // Helpers for validating and parsing JSON strings with Keyset-protos.
ValidateKeyset(const rapidjson::Document & json_doc)142 util::Status ValidateKeyset(const rapidjson::Document& json_doc) {
143 if (!json_doc.HasMember("primaryKeyId") ||
144 !json_doc["primaryKeyId"].IsUint() ||
145 !json_doc.HasMember("key") ||
146 !json_doc["key"].IsArray() ||
147 json_doc["key"].Size() < 1) {
148 return util::Status(absl::StatusCode::kInvalidArgument,
149 "Invalid JSON Keyset");
150 }
151 return util::OkStatus();
152 }
153
ValidateKey(const rapidjson::Value & json_value)154 util::Status ValidateKey(const rapidjson::Value& json_value) {
155 if (!json_value.HasMember("keyData") ||
156 !json_value["keyData"].IsObject() ||
157 !json_value.HasMember("status") ||
158 !json_value["status"].IsString() ||
159 !json_value.HasMember("keyId") ||
160 !json_value["keyId"].IsUint() ||
161 !json_value.HasMember("outputPrefixType") ||
162 !json_value["outputPrefixType"].IsString()) {
163 return util::Status(absl::StatusCode::kInvalidArgument, "Invalid JSON Key");
164 }
165 return util::OkStatus();
166 }
167
ValidateKeyData(const rapidjson::Value & json_value)168 util::Status ValidateKeyData(const rapidjson::Value& json_value) {
169 if (!json_value.HasMember("typeUrl") ||
170 !json_value["typeUrl"].IsString() ||
171 !json_value.HasMember("value") ||
172 !json_value["value"].IsString() ||
173 !json_value.HasMember("keyMaterialType") ||
174 !json_value["keyMaterialType"].IsString()) {
175 return util::Status(absl::StatusCode::kInvalidArgument,
176 "Invalid JSON KeyData");
177 }
178 return util::OkStatus();
179 }
180
181 util::StatusOr<std::unique_ptr<KeyData>>
KeyDataFromJson(const rapidjson::Value & json_value)182 KeyDataFromJson(const rapidjson::Value& json_value) {
183 auto status = ValidateKeyData(json_value);
184 if (!status.ok()) return status;
185 std::string value_field;
186 if (!absl::Base64Unescape(json_value["value"].GetString(), &value_field)) {
187 return util::Status(absl::StatusCode::kInvalidArgument,
188 "Invalid JSON KeyData");
189 }
190 auto key_data = absl::make_unique<KeyData>();
191 key_data->set_type_url(json_value["typeUrl"].GetString());
192 key_data->set_value(value_field);
193 key_data->set_key_material_type(
194 Enums::KeyMaterial(json_value["keyMaterialType"].GetString()));
195 return std::move(key_data);
196 }
197
198 util::StatusOr<std::unique_ptr<Keyset::Key>>
KeyFromJson(const rapidjson::Value & json_value)199 KeyFromJson(const rapidjson::Value& json_value) {
200 auto status = ValidateKey(json_value);
201 if (!status.ok()) return status;
202 auto key_data_result = KeyDataFromJson(json_value["keyData"]);
203 if (!key_data_result.ok()) return key_data_result.status();
204
205 auto key = absl::make_unique<Keyset::Key>();
206 key->set_key_id(json_value["keyId"].GetUint());
207 key->set_status(Enums::KeyStatus(json_value["status"].GetString()));
208 key->set_output_prefix_type(
209 Enums::OutputPrefix(json_value["outputPrefixType"].GetString()));
210 *(key->mutable_key_data()) = *(key_data_result.value());
211 return std::move(key);
212 }
213
214 util::StatusOr<std::unique_ptr<Keyset>>
KeysetFromJson(const rapidjson::Document & json_doc)215 KeysetFromJson(const rapidjson::Document& json_doc) {
216 auto status = ValidateKeyset(json_doc);
217 if (!status.ok()) return status;
218 auto keyset = absl::make_unique<Keyset>();
219 keyset->set_primary_key_id(json_doc["primaryKeyId"].GetUint());
220 for (const auto& json_key : json_doc["key"].GetArray()) {
221 auto key_result = KeyFromJson(json_key);
222 if (!key_result.ok()) return key_result.status();
223 *(keyset->add_key()) = *(key_result.value());
224 }
225 return std::move(keyset);
226 }
227
228 } // namespace
229
230
231 // static
New(std::unique_ptr<std::istream> keyset_stream)232 util::StatusOr<std::unique_ptr<KeysetReader>> JsonKeysetReader::New(
233 std::unique_ptr<std::istream> keyset_stream) {
234 if (keyset_stream == nullptr) {
235 return util::Status(absl::StatusCode::kInvalidArgument,
236 "keyset_stream must be non-null.");
237 }
238 std::unique_ptr<KeysetReader> reader(
239 new JsonKeysetReader(std::move(keyset_stream)));
240 return std::move(reader);
241 }
242
243 // static
New(absl::string_view serialized_keyset)244 util::StatusOr<std::unique_ptr<KeysetReader>> JsonKeysetReader::New(
245 absl::string_view serialized_keyset) {
246 std::unique_ptr<KeysetReader> reader(new JsonKeysetReader(serialized_keyset));
247 return std::move(reader);
248 }
249
Read()250 util::StatusOr<std::unique_ptr<Keyset>> JsonKeysetReader::Read() {
251 std::string serialized_keyset_from_stream;
252 std::string* serialized_keyset;
253 if (keyset_stream_ == nullptr) {
254 serialized_keyset = &serialized_keyset_;
255 } else {
256 serialized_keyset_from_stream =
257 std::string(std::istreambuf_iterator<char>(*keyset_stream_), {});
258 serialized_keyset = &serialized_keyset_from_stream;
259 }
260 rapidjson::Document json_doc(rapidjson::kObjectType);
261 if (json_doc.Parse(serialized_keyset->c_str()).HasParseError()) {
262 return util::Status(
263 absl::StatusCode::kInvalidArgument,
264 absl::StrCat(
265 "Invalid JSON Keyset: Error (offset ", json_doc.GetErrorOffset(),
266 "): ", rapidjson::GetParseError_En(json_doc.GetParseError())));
267 }
268 return KeysetFromJson(json_doc);
269 }
270
271 util::StatusOr<std::unique_ptr<EncryptedKeyset>>
ReadEncrypted()272 JsonKeysetReader::ReadEncrypted() {
273 std::string serialized_keyset_from_stream;
274 std::string* serialized_keyset;
275 if (keyset_stream_ == nullptr) {
276 serialized_keyset = &serialized_keyset_;
277 } else {
278 serialized_keyset_from_stream =
279 std::string(std::istreambuf_iterator<char>(*keyset_stream_), {});
280 serialized_keyset = &serialized_keyset_from_stream;
281 }
282 rapidjson::Document json_doc;
283 if (json_doc.Parse(serialized_keyset->c_str()).HasParseError()) {
284 return util::Status(
285 absl::StatusCode::kInvalidArgument,
286 absl::StrCat("Invalid JSON EncryptedKeyset: Error (offset ",
287 json_doc.GetErrorOffset(), "): ",
288 rapidjson::GetParseError_En(json_doc.GetParseError())));
289 }
290 return EncryptedKeysetFromJson(json_doc);
291 }
292
293 } // namespace tink
294 } // namespace crypto
295