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