[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