• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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