1 // Copyright 2023 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 // https://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 #include "anonymous_tokens/cpp/client/anonymous_tokens_public_key_client.h"
16
17 #include <memory>
18 #include <string>
19 #include <tuple>
20 #include <utility>
21 #include <vector>
22
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/strings/string_view.h"
25 #include "absl/types/optional.h"
26 #include "anonymous_tokens/cpp/shared/proto_utils.h"
27 #include "anonymous_tokens/cpp/shared/status_utils.h"
28 #include "anonymous_tokens/proto/anonymous_tokens.pb.h"
29
30
31 namespace anonymous_tokens {
32
33 namespace {
34
ValidityChecksForRequestCreation(const AnonymousTokensPublicKeysGetRequest & public_key_request,AnonymousTokensUseCase use_case,int64_t key_version,absl::Time key_validity_start_time,absl::optional<absl::Time> key_validity_end_time)35 absl::Status ValidityChecksForRequestCreation(
36 const AnonymousTokensPublicKeysGetRequest& public_key_request,
37 AnonymousTokensUseCase use_case, int64_t key_version,
38 absl::Time key_validity_start_time,
39 absl::optional<absl::Time> key_validity_end_time) {
40 // Basic validity checks.
41 if (!public_key_request.use_case().empty()) {
42 // Cannot create a public key request more than once using the same client.
43 return absl::FailedPreconditionError(
44 "Public Key request is already created.");
45 } else if (use_case == ANONYMOUS_TOKENS_USE_CASE_UNDEFINED) {
46 // Use case must be valid.
47 return absl::InvalidArgumentError("Use case must be defined.");
48 } else if (key_version < 0) {
49 // Key version cannot be negative.
50 return absl::InvalidArgumentError(
51 "Key Version in an AnonymousTokensPublicKeysGetRequest "
52 "must be 0 or greater than 0.");
53 } else if (key_validity_end_time.has_value() &&
54 key_validity_end_time.value() <= key_validity_start_time) {
55 // Key cannot expire before or at its validity start time.
56 return absl::InvalidArgumentError(
57 "Key validity start time can not be the same or after key validity "
58 "end time (if set).");
59 } else if (key_validity_end_time.has_value() &&
60 key_validity_end_time.value() < absl::Now()) {
61 // Key's expiry time cannot be in the past.
62 return absl::InvalidArgumentError(
63 "Requested Key expiry time (if set) must not be in the past.");
64 }
65 return absl::OkStatus();
66 }
67
ValidityChecksForResponseProcessing(const RSABlindSignaturePublicKey & public_key,const AnonymousTokensPublicKeysGetRequest & public_key_request)68 absl::Status ValidityChecksForResponseProcessing(
69 const RSABlindSignaturePublicKey& public_key,
70 const AnonymousTokensPublicKeysGetRequest& public_key_request) {
71 // Basic validity checks.
72 ANON_TOKENS_RETURN_IF_ERROR(ParseUseCase(public_key.use_case()).status());
73 if (public_key_request.use_case() != public_key.use_case()) {
74 // Use case must be the same as the requested use case.
75 return absl::InvalidArgumentError(
76 "Public key is not for the Use Case requested.");
77 } else if (public_key.key_version() <= 0) {
78 // Key version must be greater than zero.
79 return absl::InvalidArgumentError(
80 "Key_version cannot be zero or negative.");
81 } else if (public_key_request.key_version() > 0 &&
82 public_key_request.key_version() != public_key.key_version()) {
83 // Key version must be the same as the requested key version if the
84 // latter was greater than zero (explicit).
85 return absl::InvalidArgumentError(
86 "Public key is not for the Key Version requested.");
87 } else if (public_key.salt_length() <= 0) {
88 // We do not want deterministic signatures and negative lengths are
89 // invalid.
90 return absl::InvalidArgumentError(
91 "Salt length must not be zero or negative.");
92 } else if (public_key.key_size() < 256) {
93 // Key size must be a valid value.
94 return absl::InvalidArgumentError(
95 "Key_size cannot be less than 256 bytes.");
96 } else if (public_key.message_mask_type() == AT_MESSAGE_MASK_TYPE_UNDEFINED ||
97 public_key.message_mask_type() == AT_MESSAGE_MASK_XOR) {
98 return absl::InvalidArgumentError(
99 "Message mask type must be defined and supported.");
100 } else if (public_key.message_mask_type() == AT_MESSAGE_MASK_CONCAT &&
101 public_key.message_mask_size() < 32) {
102 return absl::InvalidArgumentError(
103 "Message mask concat type must have a size of at least 32 bytes.");
104 } else if (public_key.message_mask_type() == AT_MESSAGE_MASK_NO_MASK &&
105 public_key.message_mask_size() != 0) {
106 return absl::InvalidArgumentError(
107 "Message mask no mask type must be set to size 0 bytes.");
108 } else if (public_key.serialized_public_key().empty()) {
109 // Public key should not be empty.
110 return absl::InvalidArgumentError(
111 "Public Key not set for a particular use case and key version.");
112 } else if (!public_key.has_key_validity_start_time()) {
113 // Public key must have a key validity start time.
114 return absl::InvalidArgumentError(
115 "Public Key has no set validity start time.");
116 }
117 ANON_TOKENS_ASSIGN_OR_RETURN(
118 absl::Time requested_key_validity_start_time,
119 TimeFromProto(public_key_request.key_validity_start_time()));
120 ANON_TOKENS_ASSIGN_OR_RETURN(
121 absl::Time public_key_validity_start_time,
122 TimeFromProto(public_key.key_validity_start_time()));
123 if (requested_key_validity_start_time < public_key_validity_start_time) {
124 // Public key start time must be at or before the requested validity
125 // start time.
126 return absl::InvalidArgumentError(
127 "Public Key is not valid at the requested validity start time.");
128 } else if (public_key_request.has_key_validity_end_time() &&
129 !public_key.has_expiration_time()) {
130 // If a public key with explicit expiration was requested, indefinitely
131 // valid public key should not be returned.
132 return absl::InvalidArgumentError("Public Key does not expire.");
133 } else if (!public_key_request.has_key_validity_end_time() &&
134 public_key.has_expiration_time()) {
135 // If an indefinitely valid public key was requested, a public key with
136 // an expiry time should not be returned.
137 return absl::InvalidArgumentError("Public Key is not indefinitely valid");
138 }
139 absl::optional<absl::Time> public_key_expiry_time = absl::nullopt;
140 if (public_key_request.has_key_validity_end_time() &&
141 public_key.has_expiration_time()) {
142 ANON_TOKENS_ASSIGN_OR_RETURN(
143 absl::Time requested_key_expiry_time,
144 TimeFromProto(public_key_request.key_validity_end_time()));
145 ANON_TOKENS_ASSIGN_OR_RETURN(public_key_expiry_time,
146 TimeFromProto(public_key.expiration_time()));
147 if (requested_key_expiry_time < public_key_expiry_time) {
148 // Public key expiry time must be at or before the requested expiry
149 // time.
150 return absl::InvalidArgumentError(
151 "Public Key expires after the requested expiry time.");
152 } else if (public_key_expiry_time <= public_key_validity_start_time) {
153 // Key cannot expire before its validity period has even started.
154 return absl::InvalidArgumentError(
155 "Public Key cannot be expired at or before its validity start "
156 "time.");
157 } else if (public_key_expiry_time <= absl::Now()) {
158 // Key cannot be already expired.
159 return absl::InvalidArgumentError("Expired Public Key was returned");
160 }
161 }
162 RSAPublicKey rsa_public_key_pb;
163 if (!rsa_public_key_pb.ParseFromString(public_key.serialized_public_key())) {
164 return absl::InvalidArgumentError("Public key is malformed.");
165 }
166 if (rsa_public_key_pb.n().size() !=
167 static_cast<size_t>(public_key.key_size())) {
168 return absl::InvalidArgumentError(
169 "Actual and given Public Key sizes are different.");
170 }
171 return absl::OkStatus();
172 }
173
174 } // namespace
175
176 absl::StatusOr<std::unique_ptr<AnonymousTokensPublicKeysGetClient>>
Create()177 AnonymousTokensPublicKeysGetClient::Create() {
178 return absl::WrapUnique(new AnonymousTokensPublicKeysGetClient());
179 }
180
181 absl::StatusOr<AnonymousTokensPublicKeysGetRequest>
CreateAnonymousTokensPublicKeysGetRequest(AnonymousTokensUseCase use_case,int64_t key_version,absl::Time key_validity_start_time,absl::optional<absl::Time> key_validity_end_time)182 AnonymousTokensPublicKeysGetClient::CreateAnonymousTokensPublicKeysGetRequest(
183 AnonymousTokensUseCase use_case, int64_t key_version,
184 absl::Time key_validity_start_time,
185 absl::optional<absl::Time> key_validity_end_time) {
186 ANON_TOKENS_RETURN_IF_ERROR(ValidityChecksForRequestCreation(
187 public_key_request_, use_case, key_version, key_validity_start_time,
188 key_validity_end_time));
189 AnonymousTokensPublicKeysGetRequest request;
190 request.set_use_case(AnonymousTokensUseCase_Name(use_case));
191 request.set_key_version(key_version);
192 ANON_TOKENS_ASSIGN_OR_RETURN(*(request.mutable_key_validity_start_time()),
193 TimeToProto(key_validity_start_time));
194 if (key_validity_end_time.has_value()) {
195 ANON_TOKENS_ASSIGN_OR_RETURN(*(request.mutable_key_validity_end_time()),
196 TimeToProto(*key_validity_end_time));
197 }
198 // Record the request.
199 public_key_request_ = request;
200 return request;
201 }
202
203 absl::StatusOr<std::vector<RSABlindSignaturePublicKey>>
204 AnonymousTokensPublicKeysGetClient::
ProcessAnonymousTokensRSAPublicKeysGetResponse(const AnonymousTokensPublicKeysGetResponse & rsa_public_key_get_response)205 ProcessAnonymousTokensRSAPublicKeysGetResponse(
206 const AnonymousTokensPublicKeysGetResponse&
207 rsa_public_key_get_response) {
208 if (public_key_request_.use_case().empty()) {
209 // Create request method must be called before processing the response.
210 return absl::FailedPreconditionError(
211 "CreateAnonymousTokensPublicKeysGetRequest has not been called yet.");
212 }
213 std::vector<RSABlindSignaturePublicKey> rsa_public_keys;
214 // Temporary set structure to identify duplicate responses.
215 absl::flat_hash_set<std::tuple<std::string, int>> use_case_and_key_version;
216 for (const auto& resp_public_key :
217 rsa_public_key_get_response.rsa_public_keys()) {
218 ANON_TOKENS_RETURN_IF_ERROR(ValidityChecksForResponseProcessing(
219 resp_public_key, public_key_request_));
220
221 // Extract use case and key version.
222 ANON_TOKENS_ASSIGN_OR_RETURN(AnonymousTokensUseCase use_case,
223 ParseUseCase(resp_public_key.use_case()));
224 int key_version = resp_public_key.key_version();
225
226 // Check for duplicate responses.
227 std::tuple<std::string, int> use_case_key_version_tuple =
228 std::make_pair(AnonymousTokensUseCase_Name(use_case), key_version);
229 if (use_case_and_key_version.contains(use_case_key_version_tuple)) {
230 return absl::InvalidArgumentError(
231 "Use Case and Key Version combination must not be repeated in the "
232 "response.");
233 } else {
234 use_case_and_key_version.insert(use_case_key_version_tuple);
235 }
236
237 rsa_public_keys.push_back(resp_public_key);
238 }
239
240 return rsa_public_keys;
241 }
242
243 } // namespace anonymous_tokens
244
245