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