• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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