[SM][iOS] CL 1/n: Refactor BlindSignAuth to accept generic attestation data (v2)

- Refactor BlindSignAuth to accept google::protobuf::Any for attestation data to enable cross-platform compatibility.

- Please Note: This is v2 of the CL. The original CL (cl/934771494) was rolled back because it broke postsubmit compilation for `pricli` targets (under //security/oak/tools/pricli). The breakage occurred because `pricli` was still using the old V1 callback signature (expecting absl::Span<const std::string>) while the CL refactored it to expect google::protobuf::Any.

- This v2 CL fixes the breakage by updating `pricli` (token_fetcher.cc and BUILD) to wrap its attestation data in `google::protobuf::StringValue` and pack it into the `Any` proto, resolving the compilation mismatch.

- Tested and verified that all pricli and BlindSignAuth tests pass:
Sponge Link: http://sponge2/e463c14f-ba7e-4eef-94cd-5c93ee68d3d7

#sm-ios

PiperOrigin-RevId: 941150217
diff --git a/quiche/blind_sign_auth/blind_sign_auth.cc b/quiche/blind_sign_auth/blind_sign_auth.cc
index de86473..767a192 100644
--- a/quiche/blind_sign_auth/blind_sign_auth.cc
+++ b/quiche/blind_sign_auth/blind_sign_auth.cc
@@ -45,8 +45,6 @@
   return value == 0 ? "" : absl::StrCat(value);
 }
 
-constexpr absl::string_view kAttestationProtoTypeUrl =
-    "type.googleapis.com/privacy.ppn.AndroidAttestationData";
 constexpr absl::string_view kIssuerHostname =
     "https://ipprotection-ppissuer.googleapis.com";
 constexpr size_t kExpectedExtensionTypesSize = 5;
@@ -374,7 +372,7 @@
 void BlindSignAuth::AttestAndSign(
     int num_tokens, privacy::ppn::GetInitialDataResponse initial_data_response,
     SignedTokenCallback callback,
-    absl::StatusOr<absl::Span<const std::string>> attestation_data,
+    absl::StatusOr<google::protobuf::Any> attestation_data,
     std::optional<const absl::string_view> token_challenge) {
   absl::StatusOr<PrivacyPassContext> pp_context =
       CreatePrivacyPassContext(initial_data_response);
@@ -412,29 +410,13 @@
     return;
   }
 
-  // Create AndroidAttestationData.
-  AndroidAttestationData android_attestation_data;
   if (!attestation_data.ok()) {
     std::move(callback)(attestation_data.status());
     return;
   }
-  if (attestation_data->empty()) {
-    std::move(callback)(
-        absl::InvalidArgumentError("Attestation data is empty"));
-    return;
-  }
-  for (absl::string_view cert : *attestation_data) {
-    android_attestation_data.add_hardware_backed_certs(cert);
-  }
-
-  Any attestation_data_proto_any;
-  attestation_data_proto_any.set_type_url(kAttestationProtoTypeUrl);
-  attestation_data_proto_any.set_value(
-      android_attestation_data.SerializeAsString());
 
   AttestationData attestation_data_proto;
-  *attestation_data_proto.mutable_attestation_data() =
-      attestation_data_proto_any;
+  *attestation_data_proto.mutable_attestation_data() = *attestation_data;
 
   // Create AttestAndSignRequest.
   AttestAndSignRequest sign_request;
diff --git a/quiche/blind_sign_auth/blind_sign_auth.h b/quiche/blind_sign_auth/blind_sign_auth.h
index 15accf7..8a4a10c 100644
--- a/quiche/blind_sign_auth/blind_sign_auth.h
+++ b/quiche/blind_sign_auth/blind_sign_auth.h
@@ -136,12 +136,11 @@
       int num_tokens, AttestationDataCallback attestation_data_callback,
       SignedTokenCallback token_callback,
       absl::StatusOr<BlindSignMessageResponse> response);
-  void AttestAndSign(
-      int num_tokens,
-      privacy::ppn::GetInitialDataResponse initial_data_response,
-      SignedTokenCallback callback,
-      absl::StatusOr<absl::Span<const std::string>> attestation_data,
-      std::optional<const absl::string_view> token_challenge);
+  void AttestAndSign(int num_tokens,
+                     privacy::ppn::GetInitialDataResponse initial_data_response,
+                     SignedTokenCallback callback,
+                     absl::StatusOr<google::protobuf::Any> attestation_data,
+                     std::optional<const absl::string_view> token_challenge);
   void AttestAndSignCallback(
       PrivacyPassContext pp_context,
       const std::vector<std::unique_ptr<
diff --git a/quiche/blind_sign_auth/blind_sign_auth_interface.h b/quiche/blind_sign_auth/blind_sign_auth_interface.h
index 4058b6d..8715a58 100644
--- a/quiche/blind_sign_auth/blind_sign_auth_interface.h
+++ b/quiche/blind_sign_auth/blind_sign_auth_interface.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <utility>
 
+#include "google/protobuf/any.pb.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "absl/time/time.h"
@@ -54,9 +55,8 @@
 
 // This callback is used by the caller to return generated
 // attestation data and a token challenge to the BlindSignAuth library.
-using AttestAndSignCallback =
-    SingleUseCallback<void(absl::StatusOr<absl::Span<const std::string>>,
-                           std::optional<absl::string_view>)>;
+using AttestAndSignCallback = SingleUseCallback<void(
+    absl::StatusOr<google::protobuf::Any>, std::optional<absl::string_view>)>;
 
 // AttestationDataCallback returns a serialized
 // privacy::ppn::PrepareAttestationData proto, which contains an attestation
diff --git a/quiche/blind_sign_auth/blind_sign_auth_test.cc b/quiche/blind_sign_auth/blind_sign_auth_test.cc
index 2b2f3d4..dcffc92 100644
--- a/quiche/blind_sign_auth/blind_sign_auth_test.cc
+++ b/quiche/blind_sign_auth/blind_sign_auth_test.cc
@@ -678,10 +678,16 @@
       [](absl::string_view attestation_nonce,
          AttestAndSignCallback attest_and_sign_callback) {
         EXPECT_EQ(attestation_nonce, "test_attestation_nonce");
-        std::vector<std::string> hardware_backed_certs = {
-            "fake_hardware_backed_cert"};
+        privacy::ppn::AndroidAttestationData android_attestation_data;
+        android_attestation_data.add_hardware_backed_certs(
+            "fake_hardware_backed_cert");
+        google::protobuf::Any attestation_data_any;
+        attestation_data_any.set_type_url(
+            "type.googleapis.com/privacy.ppn.AndroidAttestationData");
+        attestation_data_any.set_value(
+            android_attestation_data.SerializeAsString());
         std::move(attest_and_sign_callback)(
-            /*attestation_data=*/hardware_backed_certs,
+            /*attestation_data=*/attestation_data_any,
             /*token_challenge=*/std::nullopt);
       };
 
@@ -796,6 +802,80 @@
   done.WaitForNotification();
 }
 
+TEST_F(BlindSignAuthTest, GetAttestationTokensMalformedTypeUrl) {
+  BlindSignMessageResponse fake_initial_data_attestation_response(
+      absl::StatusCode::kOk,
+      fake_get_initial_data_response_attestation_.SerializeAsString());
+
+  EXPECT_CALL(mock_message_interface(),
+              DoRequest(Eq(BlindSignMessageRequestType::kGetInitialData), _,
+                        Eq(expected_get_initial_data_request_attestation_
+                               .SerializeAsString()),
+                        _))
+      .Times(1)
+      .WillOnce([=](auto&&, auto&&, auto&&, auto get_initial_data_cb) {
+        std::move(get_initial_data_cb)(fake_initial_data_attestation_response);
+      });
+
+  // Since BlindSignAuth passes the Any payload blindly to the backend,
+  // we just test that it is correctly serialized and sent.
+  EXPECT_CALL(
+      mock_message_interface(),
+      DoRequest(Eq(BlindSignMessageRequestType::kAttestAndSign), _, _, _))
+      .Times(1)
+      .WillOnce([this](Unused, Unused, const std::string& body,
+                       BlindSignMessageCallback attest_callback) {
+        privacy::ppn::AttestAndSignRequest request;
+        ASSERT_TRUE(request.ParseFromString(body));
+        EXPECT_EQ(request.attestation().attestation_data().type_url(),
+                  "type.googleapis.com/unknown.TypeUrl");
+        EXPECT_EQ(request.attestation().attestation_data().value(),
+                  "malformed_data");
+
+        // Construct fake response
+        privacy::ppn::AttestAndSignResponse response;
+        for (const auto& request_token : request.blinded_tokens()) {
+          std::string decoded_blinded_token;
+          ASSERT_TRUE(
+              absl::Base64Unescape(request_token, &decoded_blinded_token));
+          absl::StatusOr<std::string> signature =
+              anonymous_tokens::TestSignWithPublicMetadata(
+                  decoded_blinded_token,
+                  fake_get_initial_data_response_attestation_
+                      .privacy_pass_data()
+                      .public_metadata_extensions(),
+                  *rsa_private_key_, false);
+          QUICHE_EXPECT_OK(signature);
+          response.add_blinded_token_signatures(absl::Base64Escape(*signature));
+        }
+        BlindSignMessageResponse mock_resp(absl::StatusCode::kOk,
+                                           response.SerializeAsString());
+        std::move(attest_callback)(mock_resp);
+      });
+
+  absl::Notification done;
+  AttestationDataCallback callback =
+      [](absl::string_view /*attestation_nonce*/,
+         AttestAndSignCallback attest_and_sign_callback) {
+        google::protobuf::Any attestation_data_any;
+        attestation_data_any.set_type_url(
+            "type.googleapis.com/unknown.TypeUrl");
+        attestation_data_any.set_value("malformed_data");
+        std::move(attest_and_sign_callback)(
+            /*attestation_data=*/attestation_data_any,
+            /*token_challenge=*/std::nullopt);
+      };
+  SignedTokenCallback signed_token_callback =
+      [&done](absl::StatusOr<absl::Span<BlindSignToken>> tokens) {
+        EXPECT_TRUE(tokens.ok());
+        done.Notify();
+      };
+  blind_sign_auth_->GetAttestationTokens(
+      /*num_tokens=*/1, ProxyLayer::kProxyA, std::move(callback),
+      std::move(signed_token_callback));
+  done.WaitForNotification();
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quiche