• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_rsa_bssa_client.h"
16 
17 #include <cstddef>
18 #include <memory>
19 #include <optional>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/container/flat_hash_set.h"
25 #include "absl/status/status.h"
26 #include "absl/time/time.h"
27 #include "anonymous_tokens/cpp/crypto/anonymous_tokens_pb_openssl_converters.h"
28 #include "anonymous_tokens/cpp/crypto/crypto_utils.h"
29 #include "anonymous_tokens/cpp/shared/proto_utils.h"
30 #include "anonymous_tokens/cpp/shared/status_utils.h"
31 #include "anonymous_tokens/proto/anonymous_tokens.pb.h"
32 
33 
34 namespace anonymous_tokens {
35 
36 namespace {
37 
ValidityChecksForClientCreation(const RSABlindSignaturePublicKey & public_key)38 absl::Status ValidityChecksForClientCreation(
39     const RSABlindSignaturePublicKey& public_key) {
40   // Basic validity checks.
41   if (!ParseUseCase(public_key.use_case()).ok()) {
42     return absl::InvalidArgumentError("Invalid use case for public key.");
43   } else if (public_key.key_version() <= 0) {
44     return absl::InvalidArgumentError(
45         "Key version cannot be zero or negative.");
46   } else if (public_key.key_size() < 256) {
47     return absl::InvalidArgumentError(
48         "Key modulus size cannot be less than 256 bytes.");
49   } else if (public_key.mask_gen_function() == AT_TEST_MGF ||
50              public_key.mask_gen_function() == AT_MGF_UNDEFINED) {
51     return absl::InvalidArgumentError("Unknown or unacceptable mgf1 hash.");
52   } else if (public_key.sig_hash_type() == AT_TEST_HASH_TYPE ||
53              public_key.sig_hash_type() == AT_HASH_TYPE_UNDEFINED) {
54     return absl::InvalidArgumentError(
55         "Unknown or unacceptable signature hash.");
56   } else if (public_key.salt_length() <= 0) {
57     return absl::InvalidArgumentError(
58         "Non-positive salt length is not allowed.");
59   }
60 
61   switch (public_key.message_mask_type()) {
62     case AT_MESSAGE_MASK_CONCAT:
63       if (public_key.message_mask_size() < 32) {
64         return absl::InvalidArgumentError(
65             "Message mask concat type must have a size of at least 32 bytes.");
66       }
67       break;
68     case AT_MESSAGE_MASK_NO_MASK:
69       if (public_key.message_mask_size() != 0) {
70         return absl::InvalidArgumentError(
71             "Message mask no mask type must be set to size 0 bytes.");
72       }
73       break;
74     default:
75       return absl::InvalidArgumentError(
76           "Message mask type must be defined and supported.");
77   }
78 
79   RSAPublicKey rsa_public_key;
80   if (!rsa_public_key.ParseFromString(public_key.serialized_public_key())) {
81     return absl::InvalidArgumentError("Public key is malformed.");
82   }
83   if (rsa_public_key.n().size() != static_cast<size_t>(public_key.key_size())) {
84     return absl::InvalidArgumentError(
85         "Public key size does not match key size.");
86   }
87   return absl::OkStatus();
88 }
89 
CheckPublicKeyValidity(const RSABlindSignaturePublicKey & public_key)90 absl::Status CheckPublicKeyValidity(
91     const RSABlindSignaturePublicKey& public_key) {
92   absl::Time time_now = absl::Now();
93   ANON_TOKENS_ASSIGN_OR_RETURN(
94       absl::Time start_time,
95       TimeFromProto(public_key.key_validity_start_time()));
96   if (start_time > time_now) {
97     return absl::FailedPreconditionError("Key is not valid yet.");
98   }
99   if (public_key.has_expiration_time()) {
100     ANON_TOKENS_ASSIGN_OR_RETURN(absl::Time expiration_time,
101                                  TimeFromProto(public_key.expiration_time()));
102     if (expiration_time <= time_now) {
103       return absl::FailedPreconditionError("Key is already expired.");
104     }
105   }
106   return absl::OkStatus();
107 }
108 
109 }  // namespace
110 
AnonymousTokensRsaBssaClient(const RSABlindSignaturePublicKey & public_key)111 AnonymousTokensRsaBssaClient::AnonymousTokensRsaBssaClient(
112     const RSABlindSignaturePublicKey& public_key)
113     : public_key_(public_key) {}
114 
115 absl::StatusOr<std::unique_ptr<AnonymousTokensRsaBssaClient>>
Create(const RSABlindSignaturePublicKey & public_key)116 AnonymousTokensRsaBssaClient::Create(
117     const RSABlindSignaturePublicKey& public_key) {
118   ANON_TOKENS_RETURN_IF_ERROR(ValidityChecksForClientCreation(public_key));
119   return absl::WrapUnique(new AnonymousTokensRsaBssaClient(public_key));
120 }
121 
122 absl::StatusOr<AnonymousTokensSignRequest>
CreateRequest(const std::vector<PlaintextMessageWithPublicMetadata> & inputs)123 AnonymousTokensRsaBssaClient::CreateRequest(
124     const std::vector<PlaintextMessageWithPublicMetadata>& inputs) {
125   if (inputs.empty()) {
126     return absl::InvalidArgumentError("Cannot create an empty request.");
127   } else if (!blinding_info_map_.empty()) {
128     return absl::FailedPreconditionError(
129         "Blind signature request already created.");
130   }
131 
132   ANON_TOKENS_RETURN_IF_ERROR(CheckPublicKeyValidity(public_key_));
133   RSAPublicKey rsa_public_key_proto;
134   if (!rsa_public_key_proto.ParseFromString(
135           public_key_.serialized_public_key())) {
136     return absl::InvalidArgumentError("Public key is malformed.");
137   }
138 
139   AnonymousTokensSignRequest request;
140   for (const PlaintextMessageWithPublicMetadata& input : inputs) {
141     // Generate nonce and masked message. For more details, see
142     // https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/
143     ANON_TOKENS_ASSIGN_OR_RETURN(std::string mask, GenerateMask(public_key_));
144     std::string masked_message =
145         MaskMessageConcat(mask, input.plaintext_message());
146 
147     std::optional<std::string> public_metadata = std::nullopt;
148     if (public_key_.public_metadata_support()) {
149       // Empty public metadata is a valid value.
150       public_metadata = input.public_metadata();
151     }
152     const bool use_rsa_public_exponent = false;
153     // Owned by BoringSSL.
154     ANON_TOKENS_ASSIGN_OR_RETURN(
155         const EVP_MD* sig_hash,
156         ProtoHashTypeToEVPDigest(public_key_.sig_hash_type()));
157     // Owned by BoringSSL.
158     ANON_TOKENS_ASSIGN_OR_RETURN(
159         const EVP_MD* mgf1_hash,
160         ProtoMaskGenFunctionToEVPDigest(public_key_.mask_gen_function()));
161     // Generate RSA blinder.
162     ANON_TOKENS_ASSIGN_OR_RETURN(
163         auto rsa_bssa_blinder,
164         RsaBlinder::New(rsa_public_key_proto.n(), rsa_public_key_proto.e(),
165                         sig_hash, mgf1_hash, public_key_.salt_length(),
166                         use_rsa_public_exponent, public_metadata));
167     ANON_TOKENS_ASSIGN_OR_RETURN(const std::string blinded_message,
168                                  rsa_bssa_blinder->Blind(masked_message));
169 
170     // Store randomness needed to unblind.
171     BlindingInfo blinding_info = {
172         input,
173         mask,
174         std::move(rsa_bssa_blinder),
175     };
176 
177     // Create the blinded token.
178     AnonymousTokensSignRequest_BlindedToken* blinded_token =
179         request.add_blinded_tokens();
180     blinded_token->set_use_case(public_key_.use_case());
181     blinded_token->set_key_version(public_key_.key_version());
182     blinded_token->set_serialized_token(blinded_message);
183     blinded_token->set_public_metadata(input.public_metadata());
184     blinded_token->set_do_not_use_rsa_public_exponent(!use_rsa_public_exponent);
185     blinding_info_map_[blinded_message] = std::move(blinding_info);
186   }
187 
188   return request;
189 }
190 
191 absl::StatusOr<std::vector<RSABlindSignatureTokenWithInput>>
ProcessResponse(const AnonymousTokensSignResponse & response)192 AnonymousTokensRsaBssaClient::ProcessResponse(
193     const AnonymousTokensSignResponse& response) {
194   if (blinding_info_map_.empty()) {
195     return absl::FailedPreconditionError(
196         "A valid Blind signature request was not created before calling "
197         "RetrieveAnonymousTokensFromSignResponse.");
198   } else if (response.anonymous_tokens().empty()) {
199     return absl::InvalidArgumentError("Cannot process an empty response.");
200   } else if (static_cast<size_t>(response.anonymous_tokens().size()) !=
201              blinding_info_map_.size()) {
202     return absl::InvalidArgumentError(
203         "Response is missing some requested tokens.");
204   }
205 
206   // Vector to accumulate output tokens.
207   std::vector<RSABlindSignatureTokenWithInput> tokens;
208 
209   // Temporary set structure to check for duplicate responses.
210   absl::flat_hash_set<absl::string_view> blinded_messages;
211 
212   // Loop over all the anonymous tokens in the response.
213   for (const AnonymousTokensSignResponse_AnonymousToken& anonymous_token :
214        response.anonymous_tokens()) {
215     // Basic validity checks on the response.
216     if (anonymous_token.use_case() != public_key_.use_case()) {
217       return absl::InvalidArgumentError("Use case does not match public key.");
218     } else if (anonymous_token.key_version() != public_key_.key_version()) {
219       return absl::InvalidArgumentError(
220           "Key version does not match public key.");
221     } else if (anonymous_token.serialized_blinded_message().empty()) {
222       return absl::InvalidArgumentError(
223           "Blinded message that was sent in request cannot be empty in "
224           "response.");
225     } else if (anonymous_token.serialized_token().empty()) {
226       return absl::InvalidArgumentError(
227           "Blinded anonymous token (serialized_token) in response cannot be "
228           "empty.");
229     }
230 
231     // Check for duplicate in responses.
232     if (!blinded_messages.insert(anonymous_token.serialized_blinded_message())
233              .second) {
234       return absl::InvalidArgumentError(
235           "Blinded message was repeated in the response.");
236     }
237 
238     // Retrieve blinding info associated with blind response.
239     auto it =
240         blinding_info_map_.find(anonymous_token.serialized_blinded_message());
241     if (it == blinding_info_map_.end()) {
242       return absl::InvalidArgumentError(
243           "Response has some tokens for some blinded messages that were not "
244           "requested.");
245     }
246     const BlindingInfo& blinding_info = it->second;
247 
248     if (blinding_info.input.public_metadata() !=
249         anonymous_token.public_metadata()) {
250       return absl::InvalidArgumentError(
251           "Response public metadata does not match input.");
252     } else if (public_key_.public_metadata_support() &&
253                !anonymous_token.do_not_use_rsa_public_exponent()) {
254       // Bool do_not_use_rsa_public_exponent does not matter for the non-public
255       // metadata version.
256       return absl::InvalidArgumentError(
257           "Setting do_not_use_rsa_public_exponent to false is no longer "
258           "supported.");
259     }
260 
261     // Unblind the blinded anonymous token to obtain the final anonymous token
262     // (signature).
263     ANON_TOKENS_ASSIGN_OR_RETURN(
264         const std::string final_anonymous_token,
265         blinding_info.rsa_blinder->Unblind(anonymous_token.serialized_token()));
266 
267     // Verify the signature for correctness.
268     ANON_TOKENS_RETURN_IF_ERROR(blinding_info.rsa_blinder->Verify(
269         final_anonymous_token,
270         MaskMessageConcat(blinding_info.mask,
271                           blinding_info.input.plaintext_message())));
272 
273     // Construct the final signature proto.
274     RSABlindSignatureTokenWithInput final_token_proto;
275     *final_token_proto.mutable_token()->mutable_token() = final_anonymous_token;
276     *final_token_proto.mutable_token()->mutable_message_mask() =
277         blinding_info.mask;
278     *final_token_proto.mutable_input() = blinding_info.input;
279 
280     tokens.push_back(final_token_proto);
281   }
282 
283   return tokens;
284 }
285 
Verify(const RSABlindSignaturePublicKey &,const RSABlindSignatureToken &,const PlaintextMessageWithPublicMetadata &)286 absl::Status AnonymousTokensRsaBssaClient::Verify(
287     const RSABlindSignaturePublicKey& /*public_key*/,
288     const RSABlindSignatureToken& /*token*/,
289     const PlaintextMessageWithPublicMetadata& /*input*/) {
290   return absl::UnimplementedError("Verify not implemented yet.");
291 }
292 
293 }  // namespace anonymous_tokens
294 
295