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