xref: /aosp_15_r20/external/tink/cc/core/json_keyset_writer.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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 <istream>
20 #include <memory>
21 #include <ostream>
22 #include <sstream>
23 #include <string>
24 #include <utility>
25 
26 #include "absl/status/status.h"
27 #include "absl/strings/escaping.h"
28 #include "include/rapidjson/document.h"
29 #include "include/rapidjson/prettywriter.h"
30 #include "tink/util/enums.h"
31 #include "tink/util/errors.h"
32 #include "tink/util/protobuf_helper.h"
33 #include "tink/util/status.h"
34 #include "tink/util/statusor.h"
35 #include "proto/tink.pb.h"
36 
37 namespace crypto {
38 namespace tink {
39 
40 
41 using google::crypto::tink::EncryptedKeyset;
42 using google::crypto::tink::KeyData;
43 using google::crypto::tink::Keyset;
44 using google::crypto::tink::KeysetInfo;
45 using util::Enums;
46 
47 namespace {
48 
49 // Helpers for transoforming Keyset-protos to  JSON strings.
ToJson(const KeyData & key_data,rapidjson::Value * json_key_data,rapidjson::Document::AllocatorType * allocator)50 util::Status ToJson(const KeyData& key_data,
51                         rapidjson::Value* json_key_data,
52                         rapidjson::Document::AllocatorType* allocator) {
53   rapidjson::Value type_url(rapidjson::kStringType);
54   type_url.SetString(key_data.type_url().c_str(), *allocator);
55   json_key_data->AddMember("typeUrl", type_url, *allocator);
56 
57   rapidjson::Value material_type(rapidjson::kStringType);
58   material_type.SetString(Enums::KeyMaterialName(key_data.key_material_type()),
59                           *allocator);
60   json_key_data->AddMember("keyMaterialType", material_type, *allocator);
61 
62   std::string base64_string;
63   absl::Base64Escape(key_data.value(), &base64_string);
64   rapidjson::Value key_value(rapidjson::kStringType);
65   key_value.SetString(base64_string.c_str(), *allocator);
66   json_key_data->AddMember("value", key_value, *allocator);
67 
68   return util::OkStatus();
69 }
70 
ToJson(const Keyset::Key & key,rapidjson::Value * json_key,rapidjson::Document::AllocatorType * allocator)71 util::Status ToJson(const Keyset::Key& key,
72                         rapidjson::Value* json_key,
73                         rapidjson::Document::AllocatorType* allocator) {
74   rapidjson::Value key_id(rapidjson::kNumberType);
75   key_id.SetUint(key.key_id());
76   json_key->AddMember("keyId", key_id, *allocator);
77 
78   rapidjson::Value key_status(rapidjson::kStringType);
79   key_status.SetString(Enums::KeyStatusName(key.status()), *allocator);
80   json_key->AddMember("status", key_status, *allocator);
81 
82   rapidjson::Value prefix_type(rapidjson::kStringType);
83   prefix_type.SetString(Enums::OutputPrefixName(key.output_prefix_type()),
84                         *allocator);
85   json_key->AddMember("outputPrefixType", prefix_type, *allocator);
86 
87   rapidjson::Value json_key_data(rapidjson::kObjectType);
88   auto status = ToJson(key.key_data(), &json_key_data, allocator);
89   if (!status.ok()) return status;
90   json_key->AddMember("keyData", json_key_data, *allocator);
91   return util::OkStatus();
92 }
93 
ToJsonString(const Keyset & keyset)94 util::StatusOr<std::string> ToJsonString(const Keyset& keyset) {
95   rapidjson::Document json_doc(rapidjson::kObjectType);
96   auto& allocator = json_doc.GetAllocator();
97 
98   rapidjson::Value primary_key_id(rapidjson::kNumberType);
99   primary_key_id.SetUint(keyset.primary_key_id());
100   json_doc.AddMember("primaryKeyId", primary_key_id, allocator);
101 
102   rapidjson::Value key_array(rapidjson::kArrayType);
103   for (const Keyset::Key& key : keyset.key()) {
104     rapidjson::Value json_key(rapidjson::kObjectType);
105     auto status = ToJson(key, &json_key, &allocator);
106     if (!status.ok()) return status;
107     key_array.PushBack(json_key, allocator);
108   }
109   json_doc.AddMember("key", key_array, allocator);
110   rapidjson::StringBuffer string_buffer;
111   rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(string_buffer);
112   json_doc.Accept(writer);
113   return std::string(string_buffer.GetString());
114 }
115 
ToJson(const KeysetInfo::KeyInfo & key_info,rapidjson::Value * json_key_info,rapidjson::Document::AllocatorType * allocator)116 util::Status ToJson(const KeysetInfo::KeyInfo& key_info,
117                         rapidjson::Value* json_key_info,
118                         rapidjson::Document::AllocatorType* allocator) {
119   rapidjson::Value type_url(rapidjson::kStringType);
120   type_url.SetString(key_info.type_url().c_str(), *allocator);
121   json_key_info->AddMember("typeUrl", type_url, *allocator);
122 
123   rapidjson::Value key_id(rapidjson::kNumberType);
124   key_id.SetUint(key_info.key_id());
125   json_key_info->AddMember("keyId", key_id, *allocator);
126 
127   rapidjson::Value key_status(rapidjson::kStringType);
128   key_status.SetString(Enums::KeyStatusName(key_info.status()), *allocator);
129   json_key_info->AddMember("status", key_status, *allocator);
130 
131   rapidjson::Value prefix_type(rapidjson::kStringType);
132   prefix_type.SetString(Enums::OutputPrefixName(key_info.output_prefix_type()),
133                         *allocator);
134   json_key_info->AddMember("outputPrefixType", prefix_type, *allocator);
135   return util::OkStatus();
136 }
137 
ToJson(const KeysetInfo & keyset_info,rapidjson::Value * json_keyset_info,rapidjson::Document::AllocatorType * allocator)138 util::Status ToJson(const KeysetInfo& keyset_info,
139                         rapidjson::Value* json_keyset_info,
140                         rapidjson::Document::AllocatorType* allocator) {
141   rapidjson::Value primary_key_id(rapidjson::kNumberType);
142   primary_key_id.SetUint(keyset_info.primary_key_id());
143   json_keyset_info->AddMember("primaryKeyId", primary_key_id, *allocator);
144 
145   rapidjson::Value key_info_array(rapidjson::kArrayType);
146   for (const KeysetInfo::KeyInfo& key_info : keyset_info.key_info()) {
147     rapidjson::Value json_key_info(rapidjson::kObjectType);
148     auto status = ToJson(key_info, &json_key_info, allocator);
149     if (!status.ok()) return status;
150     key_info_array.PushBack(json_key_info, *allocator);
151   }
152   json_keyset_info->AddMember("keyInfo", key_info_array, *allocator);
153   return util::OkStatus();
154 }
155 
ToJsonString(const EncryptedKeyset & keyset)156 util::StatusOr<std::string> ToJsonString(const EncryptedKeyset& keyset) {
157   rapidjson::Document json_doc(rapidjson::kObjectType);
158   auto& allocator = json_doc.GetAllocator();
159 
160   std::string base64_string;
161   absl::Base64Escape(keyset.encrypted_keyset(), &base64_string);
162   rapidjson::Value encrypted_keyset(rapidjson::kStringType);
163   encrypted_keyset.SetString(base64_string.c_str(), allocator);
164   json_doc.AddMember("encryptedKeyset", encrypted_keyset, allocator);
165 
166   if (keyset.has_keyset_info()) {
167     rapidjson::Value json_keyset_info(rapidjson::kObjectType);
168     auto status = ToJson(keyset.keyset_info(), &json_keyset_info, &allocator);
169     if (!status.ok()) return status;
170     json_doc.AddMember("keysetInfo", json_keyset_info, allocator);
171   }
172 
173   rapidjson::StringBuffer string_buffer;
174   rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(string_buffer);
175   json_doc.Accept(writer);
176   return std::string(string_buffer.GetString());
177 }
178 
WriteData(absl::string_view data,std::ostream * destination)179 util::Status WriteData(absl::string_view data, std::ostream* destination) {
180   (*destination) << data;
181   if (destination->fail()) {
182     return util::Status(absl::StatusCode::kUnknown,
183                             "Error writing to the destination stream.");
184   }
185   return util::OkStatus();
186 }
187 
188 }  // anonymous namespace
189 
190 
191 //  static
New(std::unique_ptr<std::ostream> destination_stream)192 util::StatusOr<std::unique_ptr<JsonKeysetWriter>> JsonKeysetWriter::New(
193     std::unique_ptr<std::ostream> destination_stream) {
194   if (destination_stream == nullptr) {
195     return util::Status(absl::StatusCode::kInvalidArgument,
196                         "destination_stream must be non-null.");
197   }
198   std::unique_ptr<JsonKeysetWriter> writer(
199       new JsonKeysetWriter(std::move(destination_stream)));
200   return std::move(writer);
201 }
202 
Write(const Keyset & keyset)203 util::Status JsonKeysetWriter::Write(const Keyset& keyset) {
204   auto json_string_result = ToJsonString(keyset);
205   if (!json_string_result.ok()) return json_string_result.status();
206   return WriteData(json_string_result.value(), destination_stream_.get());
207 }
208 
Write(const EncryptedKeyset & encrypted_keyset)209 util::Status JsonKeysetWriter::Write(
210     const EncryptedKeyset& encrypted_keyset) {
211   auto json_string_result = ToJsonString(encrypted_keyset);
212   if (!json_string_result.ok()) return json_string_result.status();
213   return WriteData(json_string_result.value(), destination_stream_.get());
214 }
215 
216 }  // namespace tink
217 }  // namespace crypto
218