1 // Copyright (c) 2023 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/blind_sign_auth/blind_sign_auth.h"
6
7 #include <cstdint>
8 #include <memory>
9 #include <string>
10 #include <utility>
11
12 #include "absl/status/status.h"
13 #include "absl/status/statusor.h"
14 #include "absl/strings/escaping.h"
15 #include "absl/strings/string_view.h"
16 #include "absl/time/time.h"
17 #include "anonymous_tokens/cpp/crypto/crypto_utils.h"
18 #include "anonymous_tokens/cpp/privacy_pass/token_encodings.h"
19 #include "anonymous_tokens/cpp/testing/utils.h"
20 #include "openssl/base.h"
21 #include "openssl/digest.h"
22 #include "quiche/blind_sign_auth/blind_sign_auth_interface.h"
23 #include "quiche/blind_sign_auth/blind_sign_auth_protos.h"
24 #include "quiche/blind_sign_auth/blind_sign_http_interface.h"
25 #include "quiche/blind_sign_auth/blind_sign_http_response.h"
26 #include "quiche/blind_sign_auth/test_tools/mock_blind_sign_http_interface.h"
27 #include "quiche/common/platform/api/quiche_mutex.h"
28 #include "quiche/common/platform/api/quiche_test.h"
29 #include "quiche/common/test_tools/quiche_test_utils.h"
30
31 namespace quiche {
32 namespace test {
33 namespace {
34
35 using ::testing::_;
36 using ::testing::Eq;
37 using ::testing::InSequence;
38 using ::testing::Invoke;
39 using ::testing::StartsWith;
40 using ::testing::Unused;
41
42 class BlindSignAuthTest : public QuicheTest {
43 protected:
SetUp()44 void SetUp() override {
45 // Create keypair and populate protos.
46 auto [test_rsa_public_key, test_rsa_private_key] =
47 anonymous_tokens::GetStrongTestRsaKeyPair2048();
48 ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
49 rsa_public_key_,
50 anonymous_tokens::CreatePublicKeyRSA(
51 test_rsa_public_key.n, test_rsa_public_key.e));
52 ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
53 rsa_private_key_,
54 anonymous_tokens::CreatePrivateKeyRSA(
55 test_rsa_private_key.n, test_rsa_private_key.e,
56 test_rsa_private_key.d, test_rsa_private_key.p,
57 test_rsa_private_key.q, test_rsa_private_key.dp,
58 test_rsa_private_key.dq, test_rsa_private_key.crt));
59
60 anonymous_tokens::RSAPublicKey public_key;
61 public_key.set_n(test_rsa_public_key.n);
62 public_key.set_e(test_rsa_public_key.e);
63
64 public_key_proto_.set_key_version(1);
65 public_key_proto_.set_use_case("TEST_USE_CASE");
66 public_key_proto_.set_serialized_public_key(public_key.SerializeAsString());
67 public_key_proto_.set_sig_hash_type(
68 anonymous_tokens::AT_HASH_TYPE_SHA384);
69 public_key_proto_.set_mask_gen_function(
70 anonymous_tokens::AT_MGF_SHA384);
71 public_key_proto_.set_salt_length(48);
72 public_key_proto_.set_key_size(256);
73 public_key_proto_.set_message_mask_type(
74 anonymous_tokens::AT_MESSAGE_MASK_CONCAT);
75 public_key_proto_.set_message_mask_size(32);
76
77 // Create expected GetInitialDataRequest.
78 expected_get_initial_data_request_.set_use_attestation(false);
79 expected_get_initial_data_request_.set_service_type("chromeipblinding");
80 expected_get_initial_data_request_.set_location_granularity(
81 privacy::ppn::GetInitialDataRequest_LocationGranularity_CITY_GEOS);
82 expected_get_initial_data_request_.set_validation_version(2);
83 expected_get_initial_data_request_.set_proxy_layer(privacy::ppn::PROXY_A);
84
85 // Create fake GetInitialDataResponse.
86 privacy::ppn::GetInitialDataResponse fake_get_initial_data_response;
87 *fake_get_initial_data_response.mutable_at_public_metadata_public_key() =
88 public_key_proto_;
89
90 // Create public metadata info.
91 privacy::ppn::PublicMetadata::Location location;
92 location.set_country("US");
93 anonymous_tokens::Timestamp expiration;
94 expiration.set_seconds(absl::ToUnixSeconds(absl::Now() + absl::Hours(1)));
95 privacy::ppn::PublicMetadata public_metadata;
96 *public_metadata.mutable_exit_location() = location;
97 public_metadata.set_service_type("chromeipblinding");
98 *public_metadata.mutable_expiration() = expiration;
99 public_metadata_info_.set_validation_version(1);
100 *public_metadata_info_.mutable_public_metadata() = public_metadata;
101 *fake_get_initial_data_response.mutable_public_metadata_info() =
102 public_metadata_info_;
103 fake_get_initial_data_response_ = fake_get_initial_data_response;
104
105 // Create PrivacyPassData.
106 privacy::ppn::GetInitialDataResponse::PrivacyPassData privacy_pass_data;
107 // token_key_id is derived from public key.
108 ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
109 std::string public_key_der,
110 anonymous_tokens::RsaSsaPssPublicKeyToDerEncoding(
111 rsa_public_key_.get()));
112 const EVP_MD* sha256 = EVP_sha256();
113 ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
114 token_key_id_, anonymous_tokens::ComputeHash(
115 public_key_der, *sha256));
116
117 // Create and serialize fake extensions.
118 anonymous_tokens::ExpirationTimestamp
119 expiration_timestamp;
120 int64_t one_hour_away = absl::ToUnixSeconds(absl::Now() + absl::Hours(1));
121 expiration_timestamp.timestamp = one_hour_away - (one_hour_away % 900);
122 expiration_timestamp.timestamp_precision = 900;
123 absl::StatusOr<anonymous_tokens::Extension>
124 expiration_extension = expiration_timestamp.AsExtension();
125 QUICHE_EXPECT_OK(expiration_extension);
126 extensions_.extensions.push_back(*expiration_extension);
127
128 anonymous_tokens::GeoHint geo_hint;
129 geo_hint.geo_hint = "US,US-AL,ALABASTER";
130 absl::StatusOr<anonymous_tokens::Extension>
131 geo_hint_extension = geo_hint.AsExtension();
132 QUICHE_EXPECT_OK(geo_hint_extension);
133 extensions_.extensions.push_back(*geo_hint_extension);
134
135 anonymous_tokens::ServiceType service_type;
136 service_type.service_type_id =
137 anonymous_tokens::ServiceType::kChromeIpBlinding;
138 absl::StatusOr<anonymous_tokens::Extension>
139 service_type_extension = service_type.AsExtension();
140 QUICHE_EXPECT_OK(service_type_extension);
141 extensions_.extensions.push_back(*service_type_extension);
142
143 anonymous_tokens::DebugMode debug_mode;
144 debug_mode.mode = anonymous_tokens::DebugMode::kDebug;
145 absl::StatusOr<anonymous_tokens::Extension>
146 debug_mode_extension = debug_mode.AsExtension();
147 QUICHE_EXPECT_OK(debug_mode_extension);
148 extensions_.extensions.push_back(*debug_mode_extension);
149
150 anonymous_tokens::ProxyLayer proxy_layer;
151 proxy_layer.layer =
152 anonymous_tokens::ProxyLayer::kProxyA;
153 absl::StatusOr<anonymous_tokens::Extension>
154 proxy_layer_extension = proxy_layer.AsExtension();
155 QUICHE_EXPECT_OK(proxy_layer_extension);
156 extensions_.extensions.push_back(*proxy_layer_extension);
157
158 absl::StatusOr<std::string> serialized_extensions =
159 anonymous_tokens::EncodeExtensions(extensions_);
160 QUICHE_EXPECT_OK(serialized_extensions);
161
162 privacy_pass_data.set_token_key_id(token_key_id_);
163 privacy_pass_data.set_public_metadata_extensions(*serialized_extensions);
164
165 *fake_get_initial_data_response.mutable_public_metadata_info() =
166 public_metadata_info_;
167 *fake_get_initial_data_response.mutable_privacy_pass_data() =
168 privacy_pass_data;
169 fake_get_initial_data_response_ = fake_get_initial_data_response;
170
171 // Create BlindSignAuthOptions.
172 privacy::ppn::BlindSignAuthOptions options;
173 options.set_enable_privacy_pass(false);
174
175 blind_sign_auth_ =
176 std::make_unique<BlindSignAuth>(&mock_http_interface_, options);
177 }
178
TearDown()179 void TearDown() override {
180 blind_sign_auth_.reset(nullptr);
181 }
182
183 public:
CreateSignResponse(const std::string & body,bool use_privacy_pass)184 void CreateSignResponse(const std::string& body, bool use_privacy_pass) {
185 privacy::ppn::AuthAndSignRequest request;
186 ASSERT_TRUE(request.ParseFromString(body));
187
188 // Validate AuthAndSignRequest.
189 EXPECT_EQ(request.oauth_token(), oauth_token_);
190 EXPECT_EQ(request.service_type(), "chromeipblinding");
191 // Phosphor does not need the public key hash if the KeyType is
192 // privacy::ppn::AT_PUBLIC_METADATA_KEY_TYPE.
193 EXPECT_EQ(request.key_type(), privacy::ppn::AT_PUBLIC_METADATA_KEY_TYPE);
194 EXPECT_EQ(request.public_key_hash(), "");
195 EXPECT_EQ(request.key_version(), public_key_proto_.key_version());
196 EXPECT_EQ(request.do_not_use_rsa_public_exponent(), true);
197 EXPECT_NE(request.blinded_token().size(), 0);
198
199 if (use_privacy_pass) {
200 EXPECT_EQ(request.public_metadata_extensions(),
201 fake_get_initial_data_response_.privacy_pass_data()
202 .public_metadata_extensions());
203 } else {
204 EXPECT_EQ(request.public_metadata_info().SerializeAsString(),
205 public_metadata_info_.SerializeAsString());
206 }
207
208 // Construct AuthAndSignResponse.
209 privacy::ppn::AuthAndSignResponse response;
210 for (const auto& request_token : request.blinded_token()) {
211 std::string decoded_blinded_token;
212 ASSERT_TRUE(absl::Base64Unescape(request_token, &decoded_blinded_token));
213 if (use_privacy_pass) {
214 absl::StatusOr<std::string> signature =
215 anonymous_tokens::TestSignWithPublicMetadata(
216 decoded_blinded_token, request.public_metadata_extensions(),
217 *rsa_private_key_, false);
218 QUICHE_EXPECT_OK(signature);
219 response.add_blinded_token_signature(absl::Base64Escape(*signature));
220 } else {
221 absl::StatusOr<std::string> serialized_token =
222 anonymous_tokens::TestSign(
223 decoded_blinded_token, rsa_private_key_.get());
224 // TestSignWithPublicMetadata for privacy pass
225 QUICHE_EXPECT_OK(serialized_token);
226 response.add_blinded_token_signature(
227 absl::Base64Escape(*serialized_token));
228 }
229 }
230 sign_response_ = response;
231 }
232
ValidateGetTokensOutput(absl::Span<BlindSignToken> tokens)233 void ValidateGetTokensOutput(absl::Span<BlindSignToken> tokens) {
234 for (const auto& token : tokens) {
235 privacy::ppn::SpendTokenData spend_token_data;
236 ASSERT_TRUE(spend_token_data.ParseFromString(token.token));
237 // Validate token structure.
238 EXPECT_EQ(spend_token_data.public_metadata().SerializeAsString(),
239 public_metadata_info_.public_metadata().SerializeAsString());
240 EXPECT_THAT(spend_token_data.unblinded_token(), StartsWith("blind:"));
241 EXPECT_GE(spend_token_data.unblinded_token_signature().size(),
242 spend_token_data.unblinded_token().size());
243 EXPECT_EQ(spend_token_data.signing_key_version(),
244 public_key_proto_.key_version());
245 EXPECT_NE(spend_token_data.use_case(),
246 anonymous_tokens::AnonymousTokensUseCase::
247 ANONYMOUS_TOKENS_USE_CASE_UNDEFINED);
248 EXPECT_NE(spend_token_data.message_mask(), "");
249 }
250 }
251
ValidatePrivacyPassTokensOutput(absl::Span<BlindSignToken> tokens)252 void ValidatePrivacyPassTokensOutput(absl::Span<BlindSignToken> tokens) {
253 for (const auto& token : tokens) {
254 privacy::ppn::PrivacyPassTokenData privacy_pass_token_data;
255 ASSERT_TRUE(privacy_pass_token_data.ParseFromString(token.token));
256 // Validate token structure.
257 std::string decoded_token;
258 ASSERT_TRUE(absl::WebSafeBase64Unescape(privacy_pass_token_data.token(),
259 &decoded_token));
260 std::string decoded_extensions;
261 ASSERT_TRUE(absl::WebSafeBase64Unescape(
262 privacy_pass_token_data.encoded_extensions(), &decoded_extensions));
263 }
264 }
265
266 MockBlindSignHttpInterface mock_http_interface_;
267 std::unique_ptr<BlindSignAuth> blind_sign_auth_;
268 anonymous_tokens::RSABlindSignaturePublicKey
269 public_key_proto_;
270 bssl::UniquePtr<RSA> rsa_public_key_;
271 bssl::UniquePtr<RSA> rsa_private_key_;
272 std::string token_key_id_;
273 anonymous_tokens::Extensions extensions_;
274 privacy::ppn::PublicMetadataInfo public_metadata_info_;
275 privacy::ppn::AuthAndSignResponse sign_response_;
276 privacy::ppn::GetInitialDataResponse fake_get_initial_data_response_;
277 std::string oauth_token_ = "oauth_token";
278 privacy::ppn::GetInitialDataRequest expected_get_initial_data_request_;
279 };
280
TEST_F(BlindSignAuthTest,TestGetTokensSuccessful)281 TEST_F(BlindSignAuthTest, TestGetTokensSuccessful) {
282 BlindSignHttpResponse fake_public_key_response(
283 200, fake_get_initial_data_response_.SerializeAsString());
284
285 {
286 InSequence seq;
287
288 EXPECT_CALL(
289 mock_http_interface_,
290 DoRequest(
291 Eq(BlindSignHttpRequestType::kGetInitialData), Eq(oauth_token_),
292 Eq(expected_get_initial_data_request_.SerializeAsString()), _))
293 .Times(1)
294 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
295 std::move(get_initial_data_cb)(fake_public_key_response);
296 });
297
298 EXPECT_CALL(mock_http_interface_,
299 DoRequest(Eq(BlindSignHttpRequestType::kAuthAndSign),
300 Eq(oauth_token_), _, _))
301 .Times(1)
302 .WillOnce(Invoke([this](Unused, Unused, const std::string& body,
303 BlindSignHttpCallback callback) {
304 CreateSignResponse(body, false);
305 BlindSignHttpResponse http_response(
306 200, sign_response_.SerializeAsString());
307 std::move(callback)(http_response);
308 }));
309 }
310
311 int num_tokens = 1;
312 QuicheNotification done;
313 SignedTokenCallback callback =
314 [this, &done,
315 num_tokens](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
316 QUICHE_EXPECT_OK(tokens);
317 EXPECT_EQ(tokens->size(), num_tokens);
318 ValidateGetTokensOutput(*tokens);
319 done.Notify();
320 };
321 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
322 std::move(callback));
323 done.WaitForNotification();
324 }
325
TEST_F(BlindSignAuthTest,TestGetTokensFailedNetworkError)326 TEST_F(BlindSignAuthTest, TestGetTokensFailedNetworkError) {
327 EXPECT_CALL(mock_http_interface_,
328 DoRequest(Eq(BlindSignHttpRequestType::kGetInitialData),
329 Eq(oauth_token_), _, _))
330 .Times(1)
331 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
332 std::move(get_initial_data_cb)(
333 absl::InternalError("Failed to create socket"));
334 });
335
336 EXPECT_CALL(mock_http_interface_,
337 DoRequest(Eq(BlindSignHttpRequestType::kAuthAndSign), _, _, _))
338 .Times(0);
339
340 int num_tokens = 1;
341 QuicheNotification done;
342 SignedTokenCallback callback =
343 [&done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
344 EXPECT_THAT(tokens.status().code(), absl::StatusCode::kInternal);
345 done.Notify();
346 };
347 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
348 std::move(callback));
349 done.WaitForNotification();
350 }
351
TEST_F(BlindSignAuthTest,TestGetTokensFailedBadGetInitialDataResponse)352 TEST_F(BlindSignAuthTest, TestGetTokensFailedBadGetInitialDataResponse) {
353 *fake_get_initial_data_response_.mutable_at_public_metadata_public_key()
354 ->mutable_use_case() = "SPAM";
355
356 BlindSignHttpResponse fake_public_key_response(
357 200, fake_get_initial_data_response_.SerializeAsString());
358
359 EXPECT_CALL(
360 mock_http_interface_,
361 DoRequest(Eq(BlindSignHttpRequestType::kGetInitialData), Eq(oauth_token_),
362 Eq(expected_get_initial_data_request_.SerializeAsString()), _))
363 .Times(1)
364 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
365 std::move(get_initial_data_cb)(fake_public_key_response);
366 });
367
368 EXPECT_CALL(mock_http_interface_,
369 DoRequest(Eq(BlindSignHttpRequestType::kAuthAndSign), _, _, _))
370 .Times(0);
371
372 int num_tokens = 1;
373 QuicheNotification done;
374 SignedTokenCallback callback =
375 [&done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
376 EXPECT_THAT(tokens.status().code(), absl::StatusCode::kInvalidArgument);
377 done.Notify();
378 };
379 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
380 std::move(callback));
381 done.WaitForNotification();
382 }
383
TEST_F(BlindSignAuthTest,TestGetTokensFailedBadRSABlindSignaturePublicKey)384 TEST_F(BlindSignAuthTest, TestGetTokensFailedBadRSABlindSignaturePublicKey) {
385 anonymous_tokens::Timestamp start_time;
386 start_time.set_seconds(absl::ToUnixSeconds(absl::Now() + absl::Hours(1)));
387 *public_key_proto_.mutable_key_validity_start_time() = start_time;
388 *fake_get_initial_data_response_.mutable_at_public_metadata_public_key() =
389 public_key_proto_;
390
391 BlindSignHttpResponse fake_public_key_response(
392 200, fake_get_initial_data_response_.SerializeAsString());
393
394 EXPECT_CALL(
395 mock_http_interface_,
396 DoRequest(Eq(BlindSignHttpRequestType::kGetInitialData), Eq(oauth_token_),
397 Eq(expected_get_initial_data_request_.SerializeAsString()), _))
398 .Times(1)
399 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
400 std::move(get_initial_data_cb)(fake_public_key_response);
401 });
402
403 EXPECT_CALL(mock_http_interface_,
404 DoRequest(Eq(BlindSignHttpRequestType::kAuthAndSign), _, _, _))
405 .Times(0);
406
407 int num_tokens = 1;
408 QuicheNotification done;
409 SignedTokenCallback callback =
410 [&done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
411 EXPECT_THAT(tokens.status().code(),
412 absl::StatusCode::kFailedPrecondition);
413 done.Notify();
414 };
415 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
416 std::move(callback));
417 done.WaitForNotification();
418 }
419
TEST_F(BlindSignAuthTest,TestGetTokensFailedBadAuthAndSignResponse)420 TEST_F(BlindSignAuthTest, TestGetTokensFailedBadAuthAndSignResponse) {
421 BlindSignHttpResponse fake_public_key_response(
422 200, fake_get_initial_data_response_.SerializeAsString());
423 {
424 InSequence seq;
425
426 EXPECT_CALL(
427 mock_http_interface_,
428 DoRequest(
429 Eq(BlindSignHttpRequestType::kGetInitialData), Eq(oauth_token_),
430 Eq(expected_get_initial_data_request_.SerializeAsString()), _))
431 .Times(1)
432 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
433 std::move(get_initial_data_cb)(fake_public_key_response);
434 });
435
436 EXPECT_CALL(mock_http_interface_,
437 DoRequest(Eq(BlindSignHttpRequestType::kAuthAndSign),
438 Eq(oauth_token_), _, _))
439 .Times(1)
440 .WillOnce(Invoke([this](Unused, Unused, const std::string& body,
441 BlindSignHttpCallback callback) {
442 CreateSignResponse(body, false);
443 // Add an invalid signature that can't be Base64 decoded.
444 sign_response_.add_blinded_token_signature("invalid_signature%");
445 BlindSignHttpResponse http_response(
446 200, sign_response_.SerializeAsString());
447 std::move(callback)(http_response);
448 }));
449 }
450
451 int num_tokens = 1;
452 QuicheNotification done;
453 SignedTokenCallback callback =
454 [&done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
455 EXPECT_THAT(tokens.status().code(), absl::StatusCode::kInternal);
456 done.Notify();
457 };
458 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
459 std::move(callback));
460 done.WaitForNotification();
461 }
462
TEST_F(BlindSignAuthTest,TestPrivacyPassGetTokensSucceeds)463 TEST_F(BlindSignAuthTest, TestPrivacyPassGetTokensSucceeds) {
464 privacy::ppn::BlindSignAuthOptions options;
465 options.set_enable_privacy_pass(true);
466 blind_sign_auth_ =
467 std::make_unique<BlindSignAuth>(&mock_http_interface_, options);
468
469 public_key_proto_.set_message_mask_type(
470 anonymous_tokens::AT_MESSAGE_MASK_NO_MASK);
471 public_key_proto_.set_message_mask_size(0);
472 *fake_get_initial_data_response_.mutable_at_public_metadata_public_key() =
473 public_key_proto_;
474 BlindSignHttpResponse fake_public_key_response(
475 200, fake_get_initial_data_response_.SerializeAsString());
476 {
477 InSequence seq;
478
479 EXPECT_CALL(
480 mock_http_interface_,
481 DoRequest(
482 Eq(BlindSignHttpRequestType::kGetInitialData), Eq(oauth_token_),
483 Eq(expected_get_initial_data_request_.SerializeAsString()), _))
484 .Times(1)
485 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
486 std::move(get_initial_data_cb)(fake_public_key_response);
487 });
488
489 EXPECT_CALL(mock_http_interface_,
490 DoRequest(Eq(BlindSignHttpRequestType::kAuthAndSign),
491 Eq(oauth_token_), _, _))
492 .Times(1)
493 .WillOnce(Invoke([this](Unused, Unused, const std::string& body,
494 BlindSignHttpCallback callback) {
495 CreateSignResponse(body, /*use_privacy_pass=*/true);
496 BlindSignHttpResponse http_response(
497 200, sign_response_.SerializeAsString());
498 std::move(callback)(http_response);
499 }));
500 }
501
502 int num_tokens = 1;
503 QuicheNotification done;
504 SignedTokenCallback callback =
505 [this, &done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
506 QUICHE_EXPECT_OK(tokens);
507 ValidatePrivacyPassTokensOutput(*tokens);
508 done.Notify();
509 };
510 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
511 std::move(callback));
512 done.WaitForNotification();
513 }
514
TEST_F(BlindSignAuthTest,TestPrivacyPassGetTokensFailsWithBadExtensions)515 TEST_F(BlindSignAuthTest, TestPrivacyPassGetTokensFailsWithBadExtensions) {
516 privacy::ppn::BlindSignAuthOptions options;
517 options.set_enable_privacy_pass(true);
518 blind_sign_auth_ =
519 std::make_unique<BlindSignAuth>(&mock_http_interface_, options);
520
521 public_key_proto_.set_message_mask_type(
522 anonymous_tokens::AT_MESSAGE_MASK_NO_MASK);
523 public_key_proto_.set_message_mask_size(0);
524 *fake_get_initial_data_response_.mutable_at_public_metadata_public_key() =
525 public_key_proto_;
526 fake_get_initial_data_response_.mutable_privacy_pass_data()
527 ->set_public_metadata_extensions("spam");
528 BlindSignHttpResponse fake_public_key_response(
529 200, fake_get_initial_data_response_.SerializeAsString());
530
531 EXPECT_CALL(
532 mock_http_interface_,
533 DoRequest(Eq(BlindSignHttpRequestType::kGetInitialData), Eq(oauth_token_),
534 Eq(expected_get_initial_data_request_.SerializeAsString()), _))
535 .Times(1)
536 .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
537 std::move(get_initial_data_cb)(fake_public_key_response);
538 });
539
540 int num_tokens = 1;
541 QuicheNotification done;
542 SignedTokenCallback callback =
543 [&done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
544 EXPECT_THAT(tokens.status().code(), absl::StatusCode::kInvalidArgument);
545 done.Notify();
546 };
547 blind_sign_auth_->GetTokens(oauth_token_, num_tokens, ProxyLayer::kProxyA,
548 std::move(callback));
549 done.WaitForNotification();
550 }
551
552 } // namespace
553 } // namespace test
554 } // namespace quiche
555