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