BlindSignAuth: Add token issuance APIs for Private Aratea. This use case requires the caller to generate and pass in attestation certificates.

This CL adds the API, implementation will be in follow-up CLs.

PiperOrigin-RevId: 769136951
diff --git a/quiche/blind_sign_auth/blind_sign_auth.cc b/quiche/blind_sign_auth/blind_sign_auth.cc
index c814495..d7f8542 100644
--- a/quiche/blind_sign_auth/blind_sign_auth.cc
+++ b/quiche/blind_sign_auth/blind_sign_auth.cc
@@ -368,9 +368,29 @@
     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) {
+  // TODO(b/421236538): Implement GetAttestationTokens.
+  std::move(callback)(
+      absl::UnimplementedError("GetAttestationTokens is not implemented"));
+}
+
+void BlindSignAuth::AttestAndSign(
+    int /*num_tokens*/, ProxyLayer /*layer*/, std::string /*attestation_data*/,
+    std::optional<std::string> /*token_challenge*/,
+    SignedTokenCallback callback) {
+  // TODO(b/421236538): Implement AttestAndSign.
+  std::move(callback)(
+      absl::UnimplementedError("AttestAndSign is not implemented"));
+}
+
 std::string BlindSignAuth::ConvertBase64ToWebSafeBase64(
     std::string base64_string) {
   absl::c_replace(base64_string, /*old_value=*/'+', /*new_value=*/'-');
@@ -393,6 +413,9 @@
       // type.
       return "chromeipblinding";
     }
+    case BlindSignAuthServiceType::kPrivateAratea: {
+      return "pixel_private_aratea";
+    }
   }
 }
 
diff --git a/quiche/blind_sign_auth/blind_sign_auth.h b/quiche/blind_sign_auth/blind_sign_auth.h
index 37acf27..ccc3118 100644
--- a/quiche/blind_sign_auth/blind_sign_auth.h
+++ b/quiche/blind_sign_auth/blind_sign_auth.h
@@ -38,6 +38,29 @@
                  ProxyLayer proxy_layer, BlindSignAuthServiceType service_type,
                  SignedTokenCallback callback) override;
 
+  // Returns an attestation challenge in a callback.
+  // GetAttestationTokens callbacks will run on the same thread as the
+  // BlindSignMessageInterface callbacks.
+  // Callers can make multiple concurrent requests to GetTokens.
+  // AttestationDataCallback should call AttestAndSign with a separate callback
+  // in order to complete the token issuance protocol.
+  void GetAttestationTokens(int num_tokens, ProxyLayer layer,
+                            AttestationDataCallback callback) override;
+
+  // Returns signed unblinded tokens and their expiration time in a callback.
+  // Tokens are single-use and restricted to the PI use case.
+  // The GetTokens callback will run on the same thread as the
+  // BlindSignMessageInterface callbacks.
+  // This function should be called after the caller has generated
+  // AttestationData using Keystore and the challenge returned in
+  // AttestationDataCallback. If a token challenge is provided, it will be used
+  // in creating the token. Otherwise a default challenge will be used
+  // containing the issuer hostname.
+  void AttestAndSign(int num_tokens, ProxyLayer layer,
+                     std::string attestation_data,
+                     std::optional<std::string> token_challenge,
+                     SignedTokenCallback callback) override;
+
  private:
   void GetInitialDataCallback(
       std::optional<std::string> oauth_token, int num_tokens,
diff --git a/quiche/blind_sign_auth/blind_sign_auth_interface.h b/quiche/blind_sign_auth/blind_sign_auth_interface.h
index 12b6204..7fe3f4b 100644
--- a/quiche/blind_sign_auth/blind_sign_auth_interface.h
+++ b/quiche/blind_sign_auth/blind_sign_auth_interface.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
 #include "absl/time/time.h"
 #include "absl/types/span.h"
 #include "anonymous_tokens/cpp/privacy_pass/token_encodings.h"
@@ -23,6 +24,7 @@
 enum class ProxyLayer : int {
   kProxyA,
   kProxyB,
+  kTerminalLayer,
 };
 
 // BlindSignAuthServiceType indicates which service that tokens will be
@@ -31,6 +33,7 @@
   kChromeIpBlinding,
   kCronetIpBlinding,
   kWebviewIpBlinding,
+  kPrivateAratea,
 };
 
 // A BlindSignToken is used to authenticate a request to a privacy proxy.
@@ -45,6 +48,16 @@
 using SignedTokenCallback =
     SingleUseCallback<void(absl::StatusOr<absl::Span<BlindSignToken>>)>;
 
+// AttestationDataCallback returns a serialized
+// privacy::ppn::PrepareAttestationData proto, which contains an attestation
+// challenge from the issuer server.
+// If the request fails, the callback will return an appropriate error based on
+// the response's HTTP status code.
+// If the request succeeds but the server does not issue a challenge, the
+// callback will return an absl::InternalError.
+using AttestationDataCallback =
+    SingleUseCallback<void(absl::StatusOr<absl::string_view>)>;
+
 // BlindSignAuth provides signed, unblinded tokens to callers.
 class QUICHE_EXPORT BlindSignAuthInterface {
  public:
@@ -55,6 +68,30 @@
                          ProxyLayer proxy_layer,
                          BlindSignAuthServiceType service_type,
                          SignedTokenCallback callback) = 0;
+
+  // Returns an attestation challenge in a callback.
+  // GetAttestationTokens callbacks will run on the same thread as the
+  // BlindSignMessageInterface callbacks.
+  // Callers can make multiple concurrent requests to GetTokens.
+  // ProxyLayer must be either ProxyB or TerminalLayer, NOT ProxyA.
+  // AttestationDataCallback should call AttestAndSign with a separate callback
+  // in order to complete the token issuance protocol.
+  virtual void GetAttestationTokens(int num_tokens, ProxyLayer layer,
+                                    AttestationDataCallback callback) = 0;
+
+  // Returns signed unblinded tokens and their expiration time in a callback.
+  // Tokens are single-use and restricted to the PI use case.
+  // The GetTokens callback will run on the same thread as the
+  // BlindSignMessageInterface callbacks.
+  // This function should be called after the caller has generated
+  // AttestationData using Keystore and the challenge returned in
+  // AttestationDataCallback. If a token challenge is provided, it will be used
+  // in creating the token. Otherwise a default challenge will be used
+  // containing the issuer hostname.
+  virtual void AttestAndSign(int num_tokens, ProxyLayer layer,
+                             std::string attestation_data,
+                             std::optional<std::string> token_challenge,
+                             SignedTokenCallback callback) = 0;
 };
 
 }  // namespace quiche
diff --git a/quiche/blind_sign_auth/cached_blind_sign_auth.cc b/quiche/blind_sign_auth/cached_blind_sign_auth.cc
index 883e2aa..ee5e675 100644
--- a/quiche/blind_sign_auth/cached_blind_sign_auth.cc
+++ b/quiche/blind_sign_auth/cached_blind_sign_auth.cc
@@ -132,4 +132,21 @@
   }
 }
 
+void CachedBlindSignAuth::GetAttestationTokens(
+    int /*num_tokens*/, ProxyLayer /*layer*/,
+    AttestationDataCallback callback) {
+  // TODO(b/421236538): Implement GetAttestationTokens.
+  std::move(callback)(
+      absl::UnimplementedError("GetAttestationTokens is not implemented"));
+}
+
+void CachedBlindSignAuth::AttestAndSign(
+    int /*num_tokens*/, ProxyLayer /*layer*/, std::string /*attestation_data*/,
+    std::optional<std::string> /*token_challenge*/,
+    SignedTokenCallback callback) {
+  // TODO(b/421236538): Implement AttestAndSign.
+  std::move(callback)(
+      absl::UnimplementedError("AttestAndSign is not implemented"));
+}
+
 }  // namespace quiche
diff --git a/quiche/blind_sign_auth/cached_blind_sign_auth.h b/quiche/blind_sign_auth/cached_blind_sign_auth.h
index 7eaa677..15ee48a 100644
--- a/quiche/blind_sign_auth/cached_blind_sign_auth.h
+++ b/quiche/blind_sign_auth/cached_blind_sign_auth.h
@@ -50,6 +50,30 @@
     cached_tokens_.clear();
   }
 
+  // Returns an attestation challenge in a callback.
+  // GetAttestationTokens callbacks will run on the same thread as the
+  // BlindSignMessageInterface callbacks.
+  // Callers can make multiple concurrent requests to GetTokens.
+  // ProxyLayer must be either ProxyB or TerminalLayer, NOT ProxyA.
+  // AttestationDataCallback should call AttestAndSign with a separate callback
+  // in order to complete the token issuance protocol.
+  void GetAttestationTokens(int num_tokens, ProxyLayer layer,
+                            AttestationDataCallback callback) override;
+
+  // Returns signed unblinded tokens and their expiration time in a callback.
+  // Tokens are single-use and restricted to the PI use case.
+  // The GetTokens callback will run on the same thread as the
+  // BlindSignMessageInterface callbacks.
+  // This function should be called after the caller has generated
+  // AttestationData using Keystore and the challenge returned in
+  // AttestationDataCallback. If a token challenge is provided, it will be used
+  // in creating the token. Otherwise a default challenge will be used
+  // containing the issuer hostname.
+  void AttestAndSign(int num_tokens, ProxyLayer layer,
+                     std::string attestation_data,
+                     std::optional<std::string> token_challenge,
+                     SignedTokenCallback callback) override;
+
  private:
   void HandleGetTokensResponse(
       SignedTokenCallback callback, int num_tokens,
diff --git a/quiche/blind_sign_auth/proto/proxy_layer.proto b/quiche/blind_sign_auth/proto/proxy_layer.proto
index 1b4895a..521d336 100644
--- a/quiche/blind_sign_auth/proto/proxy_layer.proto
+++ b/quiche/blind_sign_auth/proto/proxy_layer.proto
@@ -10,4 +10,5 @@
   PROXY_LAYER_UNSPECIFIED = 0;
   PROXY_A = 1;
   PROXY_B = 2;
+  TERMINAL_LAYER = 3;
 }
diff --git a/quiche/blind_sign_auth/test_tools/mock_blind_sign_auth_interface.h b/quiche/blind_sign_auth/test_tools/mock_blind_sign_auth_interface.h
index 6b7981c..22c171f 100644
--- a/quiche/blind_sign_auth/test_tools/mock_blind_sign_auth_interface.h
+++ b/quiche/blind_sign_auth/test_tools/mock_blind_sign_auth_interface.h
@@ -22,6 +22,15 @@
                ProxyLayer proxy_layer, BlindSignAuthServiceType service_type,
                SignedTokenCallback callback),
               (override));
+  MOCK_METHOD(void, GetAttestationTokens,
+              (int num_tokens, ProxyLayer layer,
+               AttestationDataCallback callback),
+              (override));
+  MOCK_METHOD(void, AttestAndSign,
+              (int num_tokens, ProxyLayer layer, std::string attestation_data,
+               std::optional<std::string> token_challenge,
+               SignedTokenCallback callback),
+              (override));
 };
 
 }  // namespace quiche::test