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 "tink/internal/keyset_handle_builder_entry.h"
18
19 #include <memory>
20 #include <string>
21
22 #include "absl/status/status.h"
23 #include "absl/strings/string_view.h"
24 #include "absl/types/optional.h"
25 #include "tink/insecure_secret_key_access.h"
26 #include "tink/internal/key_status_util.h"
27 #include "tink/internal/legacy_proto_key.h"
28 #include "tink/internal/legacy_proto_parameters.h"
29 #include "tink/internal/mutable_serialization_registry.h"
30 #include "tink/internal/proto_key_serialization.h"
31 #include "tink/internal/proto_parameters_serialization.h"
32 #include "tink/internal/serialization.h"
33 #include "tink/key.h"
34 #include "tink/parameters.h"
35 #include "tink/registry.h"
36 #include "tink/restricted_data.h"
37 #include "tink/secret_key_access_token.h"
38 #include "tink/util/status.h"
39 #include "tink/util/statusor.h"
40 #include "proto/tink.pb.h"
41
42 namespace crypto {
43 namespace tink {
44 namespace internal {
45 namespace {
46
47 using ::google::crypto::tink::KeyData;
48 using ::google::crypto::tink::Keyset;
49 using ::google::crypto::tink::KeyStatusType;
50
ToKeysetKey(int id,KeyStatusType status,const ProtoKeySerialization & serialization)51 Keyset::Key ToKeysetKey(int id, KeyStatusType status,
52 const ProtoKeySerialization& serialization) {
53 KeyData key_data;
54 key_data.set_type_url(std::string(serialization.TypeUrl()));
55 // OSS proto library complains if serialized key is not converted to string.
56 key_data.set_value(std::string(serialization.SerializedKeyProto().GetSecret(
57 InsecureSecretKeyAccess::Get())));
58 key_data.set_key_material_type(serialization.KeyMaterialType());
59 Keyset::Key key;
60 key.set_status(status);
61 key.set_key_id(id);
62 key.set_output_prefix_type(serialization.GetOutputPrefixType());
63 *key.mutable_key_data() = key_data;
64 return key;
65 }
66
SerializeParameters(const Parameters & params)67 util::StatusOr<ProtoParametersSerialization> SerializeParameters(
68 const Parameters& params) {
69 util::StatusOr<std::unique_ptr<Serialization>> serialization =
70 MutableSerializationRegistry::GlobalInstance()
71 .SerializeParameters<ProtoParametersSerialization>(params);
72 if (!serialization.ok()) return serialization.status();
73
74 const ProtoParametersSerialization* proto_serialization =
75 dynamic_cast<const ProtoParametersSerialization*>(serialization->get());
76 if (proto_serialization == nullptr) {
77 return util::Status(absl::StatusCode::kInternal,
78 "Failed to serialize proto parameters.");
79 }
80
81 return *proto_serialization;
82 }
83
SerializeLegacyParameters(const Parameters * params)84 util::StatusOr<ProtoParametersSerialization> SerializeLegacyParameters(
85 const Parameters* params) {
86 const LegacyProtoParameters* proto_params =
87 dynamic_cast<const LegacyProtoParameters*>(params);
88 if (proto_params == nullptr) {
89 return util::Status(absl::StatusCode::kInvalidArgument,
90 "Failed to serialize legacy proto parameters.");
91 }
92 return proto_params->Serialization();
93 }
94
SerializeKey(const Key & key)95 util::StatusOr<ProtoKeySerialization> SerializeKey(const Key& key) {
96 util::StatusOr<std::unique_ptr<Serialization>> serialization =
97 MutableSerializationRegistry::GlobalInstance()
98 .SerializeKey<ProtoKeySerialization>(key,
99 InsecureSecretKeyAccess::Get());
100 if (!serialization.ok()) return serialization.status();
101
102 const ProtoKeySerialization* serialized_proto_key =
103 dynamic_cast<const ProtoKeySerialization*>(serialization->get());
104 if (serialized_proto_key == nullptr) {
105 return util::Status(absl::StatusCode::kInternal,
106 "Failed to serialize proto key.");
107 }
108
109 return *serialized_proto_key;
110 }
111
SerializeLegacyKey(const Key * key)112 util::StatusOr<ProtoKeySerialization> SerializeLegacyKey(const Key* key) {
113 const LegacyProtoKey* proto_key = dynamic_cast<const LegacyProtoKey*>(key);
114 if (proto_key == nullptr) {
115 return util::Status(absl::StatusCode::kInvalidArgument,
116 "Failed to serialize legacy proto key.");
117 }
118 util::StatusOr<const ProtoKeySerialization*> serialized_key =
119 proto_key->Serialization(InsecureSecretKeyAccess::Get());
120 if (!serialized_key.ok()) return serialized_key.status();
121
122 return **serialized_key;
123 }
124
CreateKeysetKeyFromProtoParametersSerialization(const ProtoParametersSerialization & serialization,int id,KeyStatusType status)125 util::StatusOr<Keyset::Key> CreateKeysetKeyFromProtoParametersSerialization(
126 const ProtoParametersSerialization& serialization, int id,
127 KeyStatusType status) {
128 util::StatusOr<std::unique_ptr<KeyData>> key_data =
129 Registry::NewKeyData(serialization.GetKeyTemplate());
130 if (!key_data.ok()) return key_data.status();
131
132 Keyset::Key key;
133 key.set_status(status);
134 key.set_key_id(id);
135 key.set_output_prefix_type(
136 serialization.GetKeyTemplate().output_prefix_type());
137 *key.mutable_key_data() = **key_data;
138 return key;
139 }
140
CreateKeysetKeyFromProtoKeySerialization(const ProtoKeySerialization & key,int id,KeyStatusType status)141 util::StatusOr<Keyset::Key> CreateKeysetKeyFromProtoKeySerialization(
142 const ProtoKeySerialization& key, int id, KeyStatusType status) {
143 absl::optional<int> id_requirement = key.IdRequirement();
144 if (id_requirement.has_value() && *id_requirement != id) {
145 return util::Status(absl::StatusCode::kInvalidArgument,
146 "Wrong ID set for key with ID requirement.");
147 }
148 return ToKeysetKey(id, status, key);
149 }
150
151 } // namespace
152
SetFixedId(int id)153 void KeysetHandleBuilderEntry::SetFixedId(int id) {
154 strategy_.strategy = KeyIdStrategyEnum::kFixedId;
155 strategy_.id_requirement = id;
156 }
157
SetRandomId()158 void KeysetHandleBuilderEntry::SetRandomId() {
159 strategy_.strategy = KeyIdStrategyEnum::kRandomId;
160 strategy_.id_requirement = absl::nullopt;
161 }
162
CreateKeysetKey(int id)163 util::StatusOr<Keyset::Key> KeyEntry::CreateKeysetKey(int id) {
164 util::StatusOr<KeyStatusType> key_status = ToKeyStatusType(key_status_);
165 if (!key_status.ok()) return key_status.status();
166
167 if (GetKeyIdRequirement().has_value() && GetKeyIdRequirement() != id) {
168 return util::Status(absl::StatusCode::kInvalidArgument,
169 "Requested id does not match id requirement.");
170 }
171
172 util::StatusOr<ProtoKeySerialization> serialization = SerializeKey(*key_);
173 if (!serialization.ok() &&
174 serialization.status().code() != absl::StatusCode::kNotFound) {
175 return serialization.status();
176 }
177
178 if (serialization.status().code() == absl::StatusCode::kNotFound) {
179 // Fallback to legacy proto key.
180 serialization = SerializeLegacyKey(key_.get());
181 if (!serialization.ok()) return serialization.status();
182 }
183
184 return CreateKeysetKeyFromProtoKeySerialization(*serialization, id,
185 *key_status);
186 }
187
CreateKeysetKey(int id)188 util::StatusOr<Keyset::Key> ParametersEntry::CreateKeysetKey(int id) {
189 util::StatusOr<KeyStatusType> key_status = ToKeyStatusType(key_status_);
190 if (!key_status.ok()) return key_status.status();
191
192 if (GetKeyIdRequirement().has_value() && GetKeyIdRequirement() != id) {
193 return util::Status(absl::StatusCode::kInvalidArgument,
194 "Requested id does not match id requirement.");
195 }
196
197 util::StatusOr<ProtoParametersSerialization> serialization =
198 SerializeParameters(*parameters_);
199 if (!serialization.ok() &&
200 serialization.status().code() != absl::StatusCode::kNotFound) {
201 return serialization.status();
202 }
203
204 if (serialization.status().code() == absl::StatusCode::kNotFound) {
205 // Fallback to legacy proto parameters.
206 serialization = SerializeLegacyParameters(parameters_.get());
207 if (!serialization.ok()) return serialization.status();
208 }
209
210 return CreateKeysetKeyFromProtoParametersSerialization(*serialization, id,
211 *key_status);
212 }
213
214 } // namespace internal
215 } // namespace tink
216 } // namespace crypto
217