BlindSignAuth: Refactor Privacy Pass auth flow by splitting it into reusable functions.
PiperOrigin-RevId: 776695229
diff --git a/quiche/blind_sign_auth/blind_sign_auth.cc b/quiche/blind_sign_auth/blind_sign_auth.cc
index d7f8542..8c0415d 100644
--- a/quiche/blind_sign_auth/blind_sign_auth.cc
+++ b/quiche/blind_sign_auth/blind_sign_auth.cc
@@ -44,6 +44,30 @@
constexpr absl::string_view kIssuerHostname =
"https://ipprotection-ppissuer.googleapis.com";
+constexpr size_t kExpectedExtensionTypesSize = 5;
+constexpr std::array<uint16_t, kExpectedExtensionTypesSize>
+ kExpectedExtensionTypes = {0x0001, 0x0002, 0xF001, 0xF002, 0xF003};
+
+using privacy::ppn::AuthAndSignRequest;
+using privacy::ppn::AuthAndSignResponse;
+using privacy::ppn::GetInitialDataRequest;
+using privacy::ppn::GetInitialDataResponse;
+using privacy::ppn::PrivacyPassTokenData;
+using anonymous_tokens::AnonymousTokensUseCase;
+using anonymous_tokens::CreatePublicKeyRSA;
+using anonymous_tokens::DecodeExtensions;
+using anonymous_tokens::ExpirationTimestamp;
+using anonymous_tokens::ExtendedTokenRequest;
+using anonymous_tokens::Extensions;
+using anonymous_tokens::GeoHint;
+using anonymous_tokens::MarshalTokenChallenge;
+using anonymous_tokens::ParseUseCase;
+using anonymous_tokens::
+ PrivacyPassRsaBssaPublicMetadataClient;
+using anonymous_tokens::RSAPublicKey;
+using anonymous_tokens::Token;
+using anonymous_tokens::TokenChallenge;
+using anonymous_tokens::ValidateExtensionsOrderAndValues;
} // namespace
@@ -52,7 +76,7 @@
BlindSignAuthServiceType service_type,
SignedTokenCallback callback) {
// Create GetInitialData RPC.
- privacy::ppn::GetInitialDataRequest request;
+ GetInitialDataRequest request;
request.set_use_attestation(false);
request.set_service_type(BlindSignAuthServiceTypeToString(service_type));
request.set_location_granularity(
@@ -75,38 +99,21 @@
ProxyLayer proxy_layer, BlindSignAuthServiceType service_type,
SignedTokenCallback callback,
absl::StatusOr<BlindSignMessageResponse> response) {
- if (!response.ok()) {
- QUICHE_LOG(WARNING) << "GetInitialDataRequest failed: "
- << response.status();
- std::move(callback)(absl::InvalidArgumentError(
- "GetInitialDataRequest failed: invalid response"));
- return;
- }
- absl::StatusCode code = response->status_code();
- if (code != absl::StatusCode::kOk) {
- std::string message =
- absl::StrCat("GetInitialDataRequest failed with code: ", code);
- QUICHE_LOG(WARNING) << message;
- std::move(callback)(absl::InvalidArgumentError(message));
- return;
- }
- // Parse GetInitialDataResponse.
- privacy::ppn::GetInitialDataResponse initial_data_response;
- if (!initial_data_response.ParseFromString(response->body())) {
- QUICHE_LOG(WARNING) << "Failed to parse GetInitialDataResponse";
- std::move(callback)(
- absl::InternalError("Failed to parse GetInitialDataResponse"));
+ absl::StatusOr<GetInitialDataResponse> initial_data_response =
+ ParseGetInitialDataResponseMessage(response);
+ if (!initial_data_response.ok()) {
+ std::move(callback)(initial_data_response.status());
return;
}
// Create token signing requests.
- bool use_privacy_pass_client =
- initial_data_response.has_privacy_pass_data() &&
+ const bool use_privacy_pass_client =
+ initial_data_response->has_privacy_pass_data() &&
auth_options_.enable_privacy_pass();
if (use_privacy_pass_client) {
QUICHE_DVLOG(1) << "Using Privacy Pass client";
- GeneratePrivacyPassTokens(initial_data_response, std::move(oauth_token),
+ GeneratePrivacyPassTokens(*initial_data_response, std::move(oauth_token),
num_tokens, proxy_layer, service_type,
std::move(callback));
} else {
@@ -121,73 +128,18 @@
std::optional<std::string> oauth_token, int num_tokens,
ProxyLayer proxy_layer, BlindSignAuthServiceType service_type,
SignedTokenCallback callback) {
- // Set up values used in the token generation loop.
- anonymous_tokens::RSAPublicKey public_key_proto;
- if (!public_key_proto.ParseFromString(
- initial_data_response.at_public_metadata_public_key()
- .serialized_public_key())) {
- std::move(callback)(
- absl::InvalidArgumentError("Failed to parse Privacy Pass public key"));
+ absl::StatusOr<PrivacyPassContext> pp_context =
+ CreatePrivacyPassContext(initial_data_response);
+ if (!pp_context.ok()) {
+ std::move(callback)(pp_context.status());
return;
}
- absl::StatusOr<bssl::UniquePtr<RSA>> bssl_rsa_key =
- anonymous_tokens::CreatePublicKeyRSA(
- public_key_proto.n(), public_key_proto.e());
- if (!bssl_rsa_key.ok()) {
- QUICHE_LOG(ERROR) << "Failed to create RSA public key: "
- << bssl_rsa_key.status();
- std::move(callback)(absl::InternalError("Failed to create RSA public key"));
- return;
- }
- absl::StatusOr<anonymous_tokens::Extensions> extensions =
- anonymous_tokens::DecodeExtensions(
- initial_data_response.privacy_pass_data()
- .public_metadata_extensions());
- if (!extensions.ok()) {
- QUICHE_LOG(WARNING) << "Failed to decode extensions: "
- << extensions.status();
- std::move(callback)(
- absl::InvalidArgumentError("Failed to decode extensions"));
- return;
- }
- std::vector<uint16_t> kExpectedExtensionTypes = {
- /*ExpirationTimestamp=*/0x0001, /*GeoHint=*/0x0002,
- /*ServiceType=*/0xF001, /*DebugMode=*/0xF002, /*ProxyLayer=*/0xF003};
- // TODO(b/345801768): Improve the API of
- // `anonymous_tokens::ValidateExtensionsOrderAndValues` to
- // avoid any possible TOCTOU problems.
- absl::Status result =
- anonymous_tokens::ValidateExtensionsOrderAndValues(
- *extensions, absl::MakeSpan(kExpectedExtensionTypes), absl::Now());
- if (!result.ok()) {
- QUICHE_LOG(WARNING) << "Failed to validate extensions: " << result;
- std::move(callback)(
- absl::InvalidArgumentError("Failed to validate extensions"));
- return;
- }
- absl::StatusOr<anonymous_tokens::ExpirationTimestamp>
- expiration_timestamp = anonymous_tokens::
- ExpirationTimestamp::FromExtension(extensions->extensions.at(0));
- if (!expiration_timestamp.ok()) {
- QUICHE_LOG(WARNING) << "Failed to parse expiration timestamp: "
- << expiration_timestamp.status();
- std::move(callback)(
- absl::InvalidArgumentError("Failed to parse expiration timestamp"));
- return;
- }
- absl::Time public_metadata_expiry_time =
- absl::FromUnixSeconds(expiration_timestamp->timestamp);
-
- absl::StatusOr<anonymous_tokens::GeoHint> geo_hint =
- anonymous_tokens::GeoHint::FromExtension(
- extensions->extensions.at(1));
- QUICHE_CHECK(geo_hint.ok());
// Create token challenge.
- anonymous_tokens::TokenChallenge challenge;
+ TokenChallenge challenge;
challenge.issuer_name = kIssuerHostname;
absl::StatusOr<std::string> token_challenge =
- anonymous_tokens::MarshalTokenChallenge(challenge);
+ MarshalTokenChallenge(challenge);
if (!token_challenge.ok()) {
QUICHE_LOG(WARNING) << "Failed to marshal token challenge: "
<< token_challenge.status();
@@ -196,78 +148,34 @@
return;
}
- QuicheRandom* random = QuicheRandom::GetInstance();
- // Create vector of Privacy Pass clients, one for each token.
- std::vector<anonymous_tokens::ExtendedTokenRequest>
- extended_token_requests;
- std::vector<std::unique_ptr<anonymous_tokens::
- PrivacyPassRsaBssaPublicMetadataClient>>
- privacy_pass_clients;
- std::vector<std::string> privacy_pass_blinded_tokens;
-
- for (int i = 0; i < num_tokens; i++) {
- // Create client.
- auto client = anonymous_tokens::
- PrivacyPassRsaBssaPublicMetadataClient::Create(*bssl_rsa_key.value());
- if (!client.ok()) {
- QUICHE_LOG(WARNING) << "Failed to create Privacy Pass client: "
- << client.status();
- std::move(callback)(
- absl::InternalError("Failed to create Privacy Pass client"));
- return;
- }
-
- // Create nonce.
- std::string nonce_rand(32, '\0');
- random->RandBytes(nonce_rand.data(), nonce_rand.size());
-
- // Create token request.
- absl::StatusOr<anonymous_tokens::ExtendedTokenRequest>
- extended_token_request = client.value()->CreateTokenRequest(
- *token_challenge, nonce_rand,
- initial_data_response.privacy_pass_data().token_key_id(),
- *extensions);
- if (!extended_token_request.ok()) {
- QUICHE_LOG(WARNING) << "Failed to create ExtendedTokenRequest: "
- << extended_token_request.status();
- std::move(callback)(
- absl::InternalError("Failed to create ExtendedTokenRequest"));
- return;
- }
- privacy_pass_clients.push_back(*std::move(client));
- extended_token_requests.push_back(*extended_token_request);
- privacy_pass_blinded_tokens.push_back(absl::Base64Escape(
- extended_token_request->request.blinded_token_request));
+ absl::StatusOr<GeneratedTokenRequests> token_requests_data =
+ GenerateBlindedTokenRequests(num_tokens, *pp_context->rsa_public_key,
+ *token_challenge, pp_context->token_key_id,
+ pp_context->extensions);
+ if (!token_requests_data.ok()) {
+ std::move(callback)(token_requests_data.status());
+ return;
}
- privacy::ppn::AuthAndSignRequest sign_request;
+ AuthAndSignRequest sign_request;
sign_request.set_service_type(BlindSignAuthServiceTypeToString(service_type));
sign_request.set_key_type(privacy::ppn::AT_PUBLIC_METADATA_KEY_TYPE);
sign_request.set_key_version(
initial_data_response.at_public_metadata_public_key().key_version());
- sign_request.mutable_blinded_token()->Assign(
- privacy_pass_blinded_tokens.begin(), privacy_pass_blinded_tokens.end());
+ *sign_request.mutable_blinded_token() = {
+ token_requests_data->privacy_pass_blinded_tokens_b64.begin(),
+ token_requests_data->privacy_pass_blinded_tokens_b64.end()};
sign_request.mutable_public_metadata_extensions()->assign(
initial_data_response.privacy_pass_data().public_metadata_extensions());
// TODO(b/295924807): deprecate this option after AT server defaults to it
sign_request.set_do_not_use_rsa_public_exponent(true);
sign_request.set_proxy_layer(QuicheProxyLayerToPpnProxyLayer(proxy_layer));
- absl::StatusOr<anonymous_tokens::AnonymousTokensUseCase>
- use_case = anonymous_tokens::ParseUseCase(
- initial_data_response.at_public_metadata_public_key().use_case());
- if (!use_case.ok()) {
- QUICHE_LOG(WARNING) << "Failed to parse use case: " << use_case.status();
- std::move(callback)(absl::InvalidArgumentError("Failed to parse use case"));
- return;
- }
-
BlindSignMessageCallback auth_and_sign_callback =
absl::bind_front(&BlindSignAuth::PrivacyPassAuthAndSignCallback, this,
- std::move(initial_data_response.privacy_pass_data()
- .public_metadata_extensions()),
- public_metadata_expiry_time, *geo_hint, *use_case,
- std::move(privacy_pass_clients), std::move(callback));
+ *std::move(pp_context),
+ std::move(token_requests_data->privacy_pass_clients),
+ std::move(callback));
// TODO(b/304811277): remove other usages of string.data()
fetcher_->DoRequest(BlindSignMessageRequestType::kAuthAndSign, oauth_token,
sign_request.SerializeAsString(),
@@ -275,9 +183,7 @@
}
void BlindSignAuth::PrivacyPassAuthAndSignCallback(
- std::string encoded_extensions, absl::Time public_key_expiry_time,
- anonymous_tokens::GeoHint geo_hint,
- anonymous_tokens::AnonymousTokensUseCase use_case,
+ const PrivacyPassContext& pp_context,
std::vector<std::unique_ptr<anonymous_tokens::
PrivacyPassRsaBssaPublicMetadataClient>>
privacy_pass_clients,
@@ -299,7 +205,7 @@
}
// Decode AuthAndSignResponse.
- privacy::ppn::AuthAndSignResponse sign_response;
+ AuthAndSignResponse sign_response;
if (!sign_response.ParseFromString(response->body())) {
QUICHE_LOG(WARNING) << "Failed to parse AuthAndSignResponse";
std::move(callback)(
@@ -328,7 +234,7 @@
return;
}
- absl::StatusOr<anonymous_tokens::Token> token =
+ absl::StatusOr<Token> token =
privacy_pass_clients[i]->FinalizeToken(unescaped_blinded_sig);
if (!token.ok()) {
QUICHE_LOG(WARNING) << "Failed to finalize token: " << token.status();
@@ -336,8 +242,7 @@
return;
}
- absl::StatusOr<std::string> marshaled_token =
- anonymous_tokens::MarshalToken(*token);
+ absl::StatusOr<std::string> marshaled_token = MarshalToken(*token);
if (!marshaled_token.ok()) {
QUICHE_LOG(WARNING) << "Failed to marshal token: "
<< marshaled_token.status();
@@ -345,35 +250,21 @@
return;
}
- privacy::ppn::PrivacyPassTokenData privacy_pass_token_data;
+ PrivacyPassTokenData privacy_pass_token_data;
privacy_pass_token_data.mutable_token()->assign(
ConvertBase64ToWebSafeBase64(absl::Base64Escape(*marshaled_token)));
privacy_pass_token_data.mutable_encoded_extensions()->assign(
- ConvertBase64ToWebSafeBase64(absl::Base64Escape(encoded_extensions)));
- privacy_pass_token_data.set_use_case_override(use_case);
- tokens_vec.push_back(
- BlindSignToken{privacy_pass_token_data.SerializeAsString(),
- public_key_expiry_time, geo_hint});
+ ConvertBase64ToWebSafeBase64(
+ absl::Base64Escape(pp_context.public_metadata_extensions_str)));
+ privacy_pass_token_data.set_use_case_override(pp_context.use_case);
+ tokens_vec.push_back(BlindSignToken{
+ privacy_pass_token_data.SerializeAsString(),
+ pp_context.public_metadata_expiry_time, pp_context.geo_hint});
}
std::move(callback)(absl::Span<BlindSignToken>(tokens_vec));
}
-privacy::ppn::ProxyLayer BlindSignAuth::QuicheProxyLayerToPpnProxyLayer(
- quiche::ProxyLayer proxy_layer) {
- switch (proxy_layer) {
- case ProxyLayer::kProxyA: {
- return privacy::ppn::ProxyLayer::PROXY_A;
- }
- case ProxyLayer::kProxyB: {
- return privacy::ppn::ProxyLayer::PROXY_B;
- }
- case ProxyLayer::kTerminalLayer: {
- return privacy::ppn::ProxyLayer::TERMINAL_LAYER;
- }
- }
-}
-
void BlindSignAuth::GetAttestationTokens(int /*num_tokens*/,
ProxyLayer /*layer*/,
AttestationDataCallback callback) {
@@ -391,6 +282,158 @@
absl::UnimplementedError("AttestAndSign is not implemented"));
}
+absl::StatusOr<privacy::ppn::GetInitialDataResponse>
+BlindSignAuth::ParseGetInitialDataResponseMessage(
+ const absl::StatusOr<BlindSignMessageResponse>& response) {
+ if (!response.ok()) {
+ QUICHE_LOG(WARNING) << "GetInitialDataRequest failed: "
+ << response.status();
+ return absl::InvalidArgumentError(
+ "GetInitialDataRequest failed: invalid response");
+ }
+ if (absl::StatusCode code = response->status_code();
+ code != absl::StatusCode::kOk) {
+ std::string message =
+ absl::StrCat("GetInitialDataRequest failed with code: ", code);
+ QUICHE_LOG(WARNING) << message;
+ return absl::InvalidArgumentError(message);
+ }
+ // Parse GetInitialDataResponse.
+ GetInitialDataResponse initial_data_response;
+ if (!initial_data_response.ParseFromString(response->body())) {
+ QUICHE_LOG(WARNING) << "Failed to parse GetInitialDataResponse";
+ return absl::InternalError("Failed to parse GetInitialDataResponse");
+ }
+ return initial_data_response;
+}
+
+absl::StatusOr<BlindSignAuth::PrivacyPassContext>
+BlindSignAuth::CreatePrivacyPassContext(
+ const privacy::ppn::GetInitialDataResponse& initial_data_response) {
+ RSAPublicKey public_key_proto;
+ if (!public_key_proto.ParseFromString(
+ initial_data_response.at_public_metadata_public_key()
+ .serialized_public_key())) {
+ return absl::InvalidArgumentError(
+ "Failed to parse Privacy Pass public key");
+ }
+ absl::StatusOr<bssl::UniquePtr<RSA>> bssl_rsa_key =
+ CreatePublicKeyRSA(public_key_proto.n(), public_key_proto.e());
+ if (!bssl_rsa_key.ok()) {
+ return absl::InternalError(absl::StrCat("Failed to create RSA public key: ",
+ bssl_rsa_key.status().ToString()));
+ }
+
+ PrivacyPassContext context;
+ context.rsa_public_key = *std::move(bssl_rsa_key);
+ context.key_version =
+ initial_data_response.at_public_metadata_public_key().key_version();
+ context.token_key_id =
+ initial_data_response.privacy_pass_data().token_key_id();
+ context.public_metadata_extensions_str =
+ initial_data_response.privacy_pass_data().public_metadata_extensions();
+
+ absl::StatusOr<Extensions> extensions =
+ DecodeExtensions(context.public_metadata_extensions_str);
+ if (!extensions.ok()) {
+ return absl::InvalidArgumentError(absl::StrCat(
+ "Failed to decode extensions: ", extensions.status().ToString()));
+ }
+
+ if (absl::Status validation_result = ValidateExtensionsOrderAndValues(
+ *extensions, absl::MakeSpan(kExpectedExtensionTypes), absl::Now());
+ validation_result.ok()) {
+ context.extensions = *std::move(extensions);
+ } else {
+ return absl::InvalidArgumentError(absl::StrCat(
+ "Failed to validate extensions: ", validation_result.ToString()));
+ }
+
+ if (absl::StatusOr<ExpirationTimestamp> expiration_timestamp =
+ ExpirationTimestamp::FromExtension(
+ context.extensions.extensions.at(0));
+ expiration_timestamp.ok()) {
+ context.public_metadata_expiry_time =
+ absl::FromUnixSeconds(expiration_timestamp->timestamp);
+ } else {
+ return absl::InvalidArgumentError(
+ absl::StrCat("Failed to parse expiration timestamp: ",
+ expiration_timestamp.status().ToString()));
+ }
+
+ if (absl::StatusOr<GeoHint> geo_hint =
+ GeoHint::FromExtension(context.extensions.extensions.at(1));
+ geo_hint.ok()) {
+ context.geo_hint = *std::move(geo_hint);
+ } else {
+ return absl::InvalidArgumentError(absl::StrCat(
+ "Failed to parse geo hint: ", geo_hint.status().ToString()));
+ }
+
+ if (absl::StatusOr<AnonymousTokensUseCase> use_case = ParseUseCase(
+ initial_data_response.at_public_metadata_public_key().use_case());
+ use_case.ok()) {
+ context.use_case = *std::move(use_case);
+ } else {
+ return absl::InvalidArgumentError(absl::StrCat(
+ "Failed to parse use case: ", use_case.status().ToString()));
+ }
+
+ return context;
+}
+
+absl::StatusOr<BlindSignAuth::GeneratedTokenRequests>
+BlindSignAuth::GenerateBlindedTokenRequests(
+ int num_tokens, const RSA& rsa_public_key,
+ absl::string_view token_challenge_str, absl::string_view token_key_id,
+ const anonymous_tokens::Extensions& extensions) {
+ GeneratedTokenRequests result;
+ result.privacy_pass_clients.reserve(num_tokens);
+ result.privacy_pass_blinded_tokens_b64.reserve(num_tokens);
+ QuicheRandom* random = QuicheRandom::GetInstance();
+
+ for (int i = 0; i < num_tokens; i++) {
+ absl::StatusOr<std::unique_ptr<PrivacyPassRsaBssaPublicMetadataClient>>
+ client = PrivacyPassRsaBssaPublicMetadataClient::Create(rsa_public_key);
+ if (!client.ok()) {
+ return absl::InternalError(
+ absl::StrCat("Failed to create Privacy Pass client: ",
+ client.status().ToString()));
+ }
+
+ std::string nonce_rand(32, '\0');
+ random->RandBytes(nonce_rand.data(), nonce_rand.size());
+
+ absl::StatusOr<ExtendedTokenRequest> extended_token_request =
+ (*client)->CreateTokenRequest(token_challenge_str, nonce_rand,
+ token_key_id, extensions);
+ if (!extended_token_request.ok()) {
+ return absl::InternalError(
+ absl::StrCat("Failed to create ExtendedTokenRequest: ",
+ extended_token_request.status().ToString()));
+ }
+ result.privacy_pass_clients.push_back(*std::move(client));
+ result.privacy_pass_blinded_tokens_b64.push_back(absl::Base64Escape(
+ extended_token_request->request.blinded_token_request));
+ }
+ return result;
+}
+
+privacy::ppn::ProxyLayer BlindSignAuth::QuicheProxyLayerToPpnProxyLayer(
+ quiche::ProxyLayer proxy_layer) {
+ switch (proxy_layer) {
+ case ProxyLayer::kProxyA: {
+ return privacy::ppn::ProxyLayer::PROXY_A;
+ }
+ case ProxyLayer::kProxyB: {
+ return privacy::ppn::ProxyLayer::PROXY_B;
+ }
+ case ProxyLayer::kTerminalLayer: {
+ return privacy::ppn::ProxyLayer::TERMINAL_LAYER;
+ }
+ }
+}
+
std::string BlindSignAuth::ConvertBase64ToWebSafeBase64(
std::string base64_string) {
absl::c_replace(base64_string, /*old_value=*/'+', /*new_value=*/'-');
diff --git a/quiche/blind_sign_auth/blind_sign_auth.h b/quiche/blind_sign_auth/blind_sign_auth.h
index ccc3118..7ff742c 100644
--- a/quiche/blind_sign_auth/blind_sign_auth.h
+++ b/quiche/blind_sign_auth/blind_sign_auth.h
@@ -62,25 +62,57 @@
SignedTokenCallback callback) override;
private:
+ struct PrivacyPassContext {
+ bssl::UniquePtr<RSA> rsa_public_key;
+ anonymous_tokens::Extensions extensions;
+ absl::Time public_metadata_expiry_time;
+ anonymous_tokens::GeoHint geo_hint;
+ anonymous_tokens::AnonymousTokensUseCase use_case;
+ std::string token_key_id;
+ uint32_t key_version = 0;
+ std::string public_metadata_extensions_str;
+ };
+
+ struct GeneratedTokenRequests {
+ std::vector<std::unique_ptr<anonymous_tokens::
+ PrivacyPassRsaBssaPublicMetadataClient>>
+ privacy_pass_clients;
+ std::vector<std::string> privacy_pass_blinded_tokens_b64;
+ };
+
+ // Helper functions for GetTokens flow without device attestation.
void GetInitialDataCallback(
std::optional<std::string> oauth_token, int num_tokens,
ProxyLayer proxy_layer, BlindSignAuthServiceType service_type,
SignedTokenCallback callback,
absl::StatusOr<BlindSignMessageResponse> response);
+
void GeneratePrivacyPassTokens(
privacy::ppn::GetInitialDataResponse initial_data_response,
std::optional<std::string> oauth_token, int num_tokens,
ProxyLayer proxy_layer, BlindSignAuthServiceType service_type,
SignedTokenCallback callback);
+
void PrivacyPassAuthAndSignCallback(
- std::string encoded_extensions, absl::Time public_key_expiry_time,
- anonymous_tokens::GeoHint geo_hint,
- anonymous_tokens::AnonymousTokensUseCase use_case,
+ const PrivacyPassContext& pp_context,
std::vector<std::unique_ptr<anonymous_tokens::
PrivacyPassRsaBssaPublicMetadataClient>>
privacy_pass_clients,
SignedTokenCallback callback,
absl::StatusOr<BlindSignMessageResponse> response);
+
+ absl::StatusOr<privacy::ppn::GetInitialDataResponse>
+ ParseGetInitialDataResponseMessage(
+ const absl::StatusOr<BlindSignMessageResponse>& response_statusor);
+
+ absl::StatusOr<PrivacyPassContext> CreatePrivacyPassContext(
+ const privacy::ppn::GetInitialDataResponse& initial_data_response);
+
+ absl::StatusOr<GeneratedTokenRequests> GenerateBlindedTokenRequests(
+ int num_tokens, const RSA& rsa_public_key,
+ absl::string_view token_challenge_str, absl::string_view token_key_id,
+ const anonymous_tokens::Extensions& extensions);
+
privacy::ppn::ProxyLayer QuicheProxyLayerToPpnProxyLayer(
quiche::ProxyLayer proxy_layer);
// Replaces '+' and '/' with '-' and '_' in a Base64 string.