Add OHTTP support for custom request and response labels for encryption key generation.

This will be required for protocols that reuse the OHTTP encapsulation format.

PiperOrigin-RevId: 552943211
diff --git a/quiche/oblivious_http/buffers/oblivious_http_integration_test.cc b/quiche/oblivious_http/buffers/oblivious_http_integration_test.cc
index 5d00efc..b9e17f6 100644
--- a/quiche/oblivious_http/buffers/oblivious_http_integration_test.cc
+++ b/quiche/oblivious_http/buffers/oblivious_http_integration_test.cc
@@ -105,4 +105,55 @@
     [](const testing::TestParamInfo<ObliviousHttpParameterizedTest::ParamType>
            &info) { return info.param.test_case_name; });
 
+TEST(ObliviousHttpIntegrationTest, TestWithCustomRequestResponseLabels) {
+  const std::string kRequestLabel = "test_request_label";
+  const std::string kResponseLabel = "test_response_label";
+
+  ObliviousHttpResponseTestStrings test = {"", 4, "test_request_plaintext",
+                                           "test_response_plaintext"};
+
+  auto ohttp_key_config =
+      GetOhttpKeyConfig(test.key_id, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
+                        EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
+  // Round-trip request flow.
+  auto client_req_encap = ObliviousHttpRequest::CreateClientObliviousRequest(
+      test.request_plaintext, GetHpkePublicKey(), ohttp_key_config,
+      kRequestLabel);
+  EXPECT_TRUE(client_req_encap.ok());
+  ASSERT_FALSE(client_req_encap->EncapsulateAndSerialize().empty());
+  auto server_req_decap = ObliviousHttpRequest::CreateServerObliviousRequest(
+      client_req_encap->EncapsulateAndSerialize(),
+      *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
+      ohttp_key_config, kRequestLabel);
+  EXPECT_TRUE(server_req_decap.ok());
+  EXPECT_EQ(server_req_decap->GetPlaintextData(), test.request_plaintext);
+
+  auto failed_server_req_decap =
+      ObliviousHttpRequest::CreateServerObliviousRequest(
+          client_req_encap->EncapsulateAndSerialize(),
+          *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
+          ohttp_key_config);
+  EXPECT_FALSE(failed_server_req_decap.ok());
+
+  // Round-trip response flow.
+  auto server_request_context =
+      std::move(server_req_decap.value()).ReleaseContext();
+  auto server_resp_encap = ObliviousHttpResponse::CreateServerObliviousResponse(
+      test.response_plaintext, server_request_context, kResponseLabel);
+  EXPECT_TRUE(server_resp_encap.ok());
+  ASSERT_FALSE(server_resp_encap->EncapsulateAndSerialize().empty());
+  auto client_request_context =
+      std::move(client_req_encap.value()).ReleaseContext();
+  auto client_resp_decap = ObliviousHttpResponse::CreateClientObliviousResponse(
+      server_resp_encap->EncapsulateAndSerialize(), client_request_context,
+      kResponseLabel);
+  EXPECT_TRUE(client_resp_decap.ok());
+  EXPECT_EQ(client_resp_decap->GetPlaintextData(), test.response_plaintext);
+
+  auto failed_client_resp_decap =
+      ObliviousHttpResponse::CreateClientObliviousResponse(
+          server_resp_encap->EncapsulateAndSerialize(), client_request_context);
+  EXPECT_FALSE(failed_client_resp_decap.ok());
+}
+
 }  // namespace quiche
diff --git a/quiche/oblivious_http/buffers/oblivious_http_request.cc b/quiche/oblivious_http/buffers/oblivious_http_request.cc
index 7c0b2ea..fec5c8f 100644
--- a/quiche/oblivious_http/buffers/oblivious_http_request.cc
+++ b/quiche/oblivious_http/buffers/oblivious_http_request.cc
@@ -40,7 +40,8 @@
 absl::StatusOr<ObliviousHttpRequest>
 ObliviousHttpRequest::CreateServerObliviousRequest(
     absl::string_view encrypted_data, const EVP_HPKE_KEY& gateway_key,
-    const ObliviousHttpHeaderKeyConfig& ohttp_key_config) {
+    const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
+    absl::string_view request_label) {
   if (EVP_HPKE_KEY_kem(&gateway_key) == nullptr) {
     return absl::InvalidArgumentError(
         "Invalid input param. Failed to import gateway_key.");
@@ -65,7 +66,8 @@
         "Failed to extract encapsulation key of expected len=", enc_key_len,
         "from payload."));
   }
-  std::string info = ohttp_key_config.SerializeRecipientContextInfo();
+  std::string info =
+      ohttp_key_config.SerializeRecipientContextInfo(request_label);
   if (!EVP_HPKE_CTX_setup_recipient(
           gateway_ctx.get(), &gateway_key, ohttp_key_config.GetHpkeKdf(),
           ohttp_key_config.GetHpkeAead(),
@@ -97,24 +99,26 @@
 absl::StatusOr<ObliviousHttpRequest>
 ObliviousHttpRequest::CreateClientObliviousRequest(
     std::string plaintext_payload, absl::string_view hpke_public_key,
-    const ObliviousHttpHeaderKeyConfig& ohttp_key_config) {
+    const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
+    absl::string_view request_label) {
   return EncapsulateWithSeed(std::move(plaintext_payload), hpke_public_key,
-                             ohttp_key_config, "");
+                             ohttp_key_config, /*seed=*/"", request_label);
 }
 
 absl::StatusOr<ObliviousHttpRequest>
 ObliviousHttpRequest::CreateClientWithSeedForTesting(
     std::string plaintext_payload, absl::string_view hpke_public_key,
     const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
-    absl::string_view seed) {
+    absl::string_view seed, absl::string_view request_label) {
   return ObliviousHttpRequest::EncapsulateWithSeed(
-      std::move(plaintext_payload), hpke_public_key, ohttp_key_config, seed);
+      std::move(plaintext_payload), hpke_public_key, ohttp_key_config, seed,
+      request_label);
 }
 
 absl::StatusOr<ObliviousHttpRequest> ObliviousHttpRequest::EncapsulateWithSeed(
     std::string plaintext_payload, absl::string_view hpke_public_key,
     const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
-    absl::string_view seed) {
+    absl::string_view seed, absl::string_view request_label) {
   if (plaintext_payload.empty() || hpke_public_key.empty()) {
     return absl::InvalidArgumentError("Invalid input.");
   }
@@ -130,7 +134,8 @@
   // Setup the sender (client)
   std::string encapsulated_key(EVP_HPKE_MAX_ENC_LENGTH, '\0');
   size_t enc_len;
-  std::string info = ohttp_key_config.SerializeRecipientContextInfo();
+  std::string info =
+      ohttp_key_config.SerializeRecipientContextInfo(request_label);
   if (seed.empty()) {
     if (!EVP_HPKE_CTX_setup_sender(
             client_ctx.get(),
diff --git a/quiche/oblivious_http/buffers/oblivious_http_request.h b/quiche/oblivious_http/buffers/oblivious_http_request.h
index 58a555b..0678ff5 100644
--- a/quiche/oblivious_http/buffers/oblivious_http_request.h
+++ b/quiche/oblivious_http/buffers/oblivious_http_request.h
@@ -54,20 +54,26 @@
   // Generic Usecase : server-side calls this method in the context of Request.
   static absl::StatusOr<ObliviousHttpRequest> CreateServerObliviousRequest(
       absl::string_view encrypted_data, const EVP_HPKE_KEY& gateway_key,
-      const ObliviousHttpHeaderKeyConfig& ohttp_key_config);
+      const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
+      absl::string_view request_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel);
 
   // Constructs an OHTTP request for the given `plaintext_payload`.
   // On success, returns obj that callers will use to `EncapsulateAndSerialize`
   // OHttp request.
   static absl::StatusOr<ObliviousHttpRequest> CreateClientObliviousRequest(
       std::string plaintext_payload, absl::string_view hpke_public_key,
-      const ObliviousHttpHeaderKeyConfig& ohttp_key_config);
+      const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
+      absl::string_view request_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel);
 
   // Same as above but accepts a random number seed for testing.
   static absl::StatusOr<ObliviousHttpRequest> CreateClientWithSeedForTesting(
       std::string plaintext_payload, absl::string_view hpke_public_key,
       const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
-      absl::string_view seed);
+      absl::string_view seed,
+      absl::string_view request_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel);
 
   // Movable.
   ObliviousHttpRequest(ObliviousHttpRequest&& other) = default;
@@ -106,7 +112,7 @@
   static absl::StatusOr<ObliviousHttpRequest> EncapsulateWithSeed(
       std::string plaintext_payload, absl::string_view hpke_public_key,
       const ObliviousHttpHeaderKeyConfig& ohttp_key_config,
-      absl::string_view seed);
+      absl::string_view seed, absl::string_view request_label);
 
   // This field will be empty after calling `ReleaseContext()`.
   absl::optional<Context> oblivious_http_request_context_;
diff --git a/quiche/oblivious_http/buffers/oblivious_http_response.cc b/quiche/oblivious_http/buffers/oblivious_http_response.cc
index ea1936d..3496be9 100644
--- a/quiche/oblivious_http/buffers/oblivious_http_response.cc
+++ b/quiche/oblivious_http/buffers/oblivious_http_response.cc
@@ -47,7 +47,8 @@
 absl::StatusOr<ObliviousHttpResponse>
 ObliviousHttpResponse::CreateClientObliviousResponse(
     std::string encrypted_data,
-    ObliviousHttpRequest::Context& oblivious_http_request_context) {
+    ObliviousHttpRequest::Context& oblivious_http_request_context,
+    absl::string_view resp_label) {
   if (oblivious_http_request_context.hpke_context_ == nullptr) {
     return absl::FailedPreconditionError(
         "HPKE context wasn't initialized before proceeding with this Response "
@@ -91,7 +92,7 @@
   // Steps (1, 3 to 5) + AEAD context SetUp before 6th step is performed in
   // CommonOperations.
   auto common_ops_st = CommonOperationsToEncapDecap(
-      response_nonce, oblivious_http_request_context,
+      response_nonce, oblivious_http_request_context, resp_label,
       aead_params_st.value().aead_key_len,
       aead_params_st.value().aead_nonce_len, aead_params_st.value().secret_len);
   if (!common_ops_st.ok()) {
@@ -131,7 +132,7 @@
 ObliviousHttpResponse::CreateServerObliviousResponse(
     std::string plaintext_payload,
     ObliviousHttpRequest::Context& oblivious_http_request_context,
-    QuicheRandom* quiche_random) {
+    absl::string_view response_label, QuicheRandom* quiche_random) {
   if (oblivious_http_request_context.hpke_context_ == nullptr) {
     return absl::FailedPreconditionError(
         "HPKE context wasn't initialized before proceeding with this Response "
@@ -168,7 +169,7 @@
   // Steps (1, 3 to 5) + AEAD context SetUp before 6th step is performed in
   // CommonOperations.
   auto common_ops_st = CommonOperationsToEncapDecap(
-      response_nonce, oblivious_http_request_context,
+      response_nonce, oblivious_http_request_context, response_label,
       aead_params_st.value().aead_key_len,
       aead_params_st.value().aead_nonce_len, aead_params_st.value().secret_len);
   if (!common_ops_st.ok()) {
@@ -246,8 +247,8 @@
 ObliviousHttpResponse::CommonOperationsToEncapDecap(
     absl::string_view response_nonce,
     ObliviousHttpRequest::Context& oblivious_http_request_context,
-    const size_t aead_key_len, const size_t aead_nonce_len,
-    const size_t secret_len) {
+    absl::string_view resp_label, const size_t aead_key_len,
+    const size_t aead_nonce_len, const size_t secret_len) {
   if (response_nonce.empty()) {
     return absl::InvalidArgumentError("Invalid input params.");
   }
@@ -256,8 +257,6 @@
   // key and nonce associated with context.
   // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#section-4.2-2.1
   std::string secret(secret_len, '\0');
-  absl::string_view resp_label =
-      ObliviousHttpHeaderKeyConfig::kOhttpResponseLabel;
   if (!EVP_HPKE_CTX_export(oblivious_http_request_context.hpke_context_.get(),
                            reinterpret_cast<uint8_t*>(secret.data()),
                            secret.size(),
diff --git a/quiche/oblivious_http/buffers/oblivious_http_response.h b/quiche/oblivious_http/buffers/oblivious_http_response.h
index 82b388d..2bc7caf 100644
--- a/quiche/oblivious_http/buffers/oblivious_http_response.h
+++ b/quiche/oblivious_http/buffers/oblivious_http_response.h
@@ -9,6 +9,7 @@
 #include "absl/strings/string_view.h"
 #include "quiche/common/quiche_random.h"
 #include "quiche/oblivious_http/buffers/oblivious_http_request.h"
+#include "quiche/oblivious_http/common/oblivious_http_header_key_config.h"
 
 namespace quiche {
 
@@ -21,7 +22,9 @@
   // alive only for the lifetime of this factory method call.
   static absl::StatusOr<ObliviousHttpResponse> CreateClientObliviousResponse(
       std::string encrypted_data,
-      ObliviousHttpRequest::Context& oblivious_http_request_context);
+      ObliviousHttpRequest::Context& oblivious_http_request_context,
+      absl::string_view resp_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpResponseLabel);
 
   // Encrypt the input param `plaintext_payload` and create OHttp response using
   // ObliviousHttpContext context obj that was returned from
@@ -39,6 +42,8 @@
   static absl::StatusOr<ObliviousHttpResponse> CreateServerObliviousResponse(
       std::string plaintext_payload,
       ObliviousHttpRequest::Context& oblivious_http_request_context,
+      absl::string_view resp_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpResponseLabel,
       QuicheRandom* quiche_random = nullptr);
 
   // Copyable.
@@ -87,8 +92,8 @@
   static absl::StatusOr<CommonOperationsResult> CommonOperationsToEncapDecap(
       absl::string_view response_nonce,
       ObliviousHttpRequest::Context& oblivious_http_request_context,
-      const size_t aead_key_len, const size_t aead_nonce_len,
-      const size_t secret_len);
+      absl::string_view resp_label, const size_t aead_key_len,
+      const size_t aead_nonce_len, const size_t secret_len);
   std::string encrypted_data_;
   std::string response_plaintext_;
 };
diff --git a/quiche/oblivious_http/buffers/oblivious_http_response_test.cc b/quiche/oblivious_http/buffers/oblivious_http_response_test.cc
index b2147d7..4178c73 100644
--- a/quiche/oblivious_http/buffers/oblivious_http_response_test.cc
+++ b/quiche/oblivious_http/buffers/oblivious_http_response_test.cc
@@ -15,6 +15,7 @@
 #include "openssl/hpke.h"
 #include "quiche/common/platform/api/quiche_test.h"
 #include "quiche/oblivious_http/buffers/oblivious_http_request.h"
+#include "quiche/oblivious_http/common/oblivious_http_header_key_config.h"
 
 namespace quiche {
 
@@ -190,7 +191,8 @@
       std::move(server_seeded_request).ReleaseContext();
   auto server_response_encapsulate =
       ObliviousHttpResponse::CreateServerObliviousResponse(
-          "test response", server_request_context, &random);
+          "test response", server_request_context,
+          ObliviousHttpHeaderKeyConfig::kOhttpResponseLabel, &random);
   EXPECT_TRUE(server_response_encapsulate.ok());
   std::string response_nonce =
       server_response_encapsulate->EncapsulateAndSerialize().substr(
diff --git a/quiche/oblivious_http/common/oblivious_http_header_key_config.cc b/quiche/oblivious_http/common/oblivious_http_header_key_config.cc
index b0103c2..3693268 100644
--- a/quiche/oblivious_http/common/oblivious_http_header_key_config.cc
+++ b/quiche/oblivious_http/common/oblivious_http_header_key_config.cc
@@ -115,13 +115,13 @@
   return aead.value();
 }
 
-std::string ObliviousHttpHeaderKeyConfig::SerializeRecipientContextInfo()
-    const {
+std::string ObliviousHttpHeaderKeyConfig::SerializeRecipientContextInfo(
+    absl::string_view request_label) const {
   uint8_t zero_byte = 0x00;
-  int buf_len = kOhttpRequestLabel.size() + kHeaderLength + sizeof(zero_byte);
+  int buf_len = request_label.size() + kHeaderLength + sizeof(zero_byte);
   std::string info(buf_len, '\0');
   QuicheDataWriter writer(info.size(), info.data());
-  QUICHE_CHECK(writer.WriteStringPiece(kOhttpRequestLabel));
+  QUICHE_CHECK(writer.WriteStringPiece(request_label));
   QUICHE_CHECK(writer.WriteUInt8(zero_byte));  // Zero byte.
   QUICHE_CHECK(writer.WriteUInt8(key_id_));
   QUICHE_CHECK(writer.WriteUInt16(kem_id_));
diff --git a/quiche/oblivious_http/common/oblivious_http_header_key_config.h b/quiche/oblivious_http/common/oblivious_http_header_key_config.h
index 488561b..37599a0 100644
--- a/quiche/oblivious_http/common/oblivious_http_header_key_config.h
+++ b/quiche/oblivious_http/common/oblivious_http_header_key_config.h
@@ -55,11 +55,13 @@
   uint16_t GetHpkeKdfId() const { return kdf_id_; }
   uint16_t GetHpkeAeadId() const { return aead_id_; }
 
-  // Build HPKE context info ["message/bhttp request", 0x00, keyID(1 byte),
+  // Build HPKE context info [request_label, 0x00, keyID(1 byte),
   // kemID(2 bytes), kdfID(2 bytes), aeadID(2 bytes)] in network byte order and
   // return a sequence of bytes(bytestring).
   // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#section-4.1-10
-  std::string SerializeRecipientContextInfo() const;
+  std::string SerializeRecipientContextInfo(
+      absl::string_view request_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel) const;
 
   // Parses the below Header
   // [keyID(1 byte), kemID(2 bytes), kdfID(2 bytes), aeadID(2 bytes)]
diff --git a/quiche/oblivious_http/oblivious_http_gateway.cc b/quiche/oblivious_http/oblivious_http_gateway.cc
index b2d2e88..e788369 100644
--- a/quiche/oblivious_http/oblivious_http_gateway.cc
+++ b/quiche/oblivious_http/oblivious_http_gateway.cc
@@ -51,17 +51,18 @@
 
 absl::StatusOr<ObliviousHttpRequest>
 ObliviousHttpGateway::DecryptObliviousHttpRequest(
-    absl::string_view encrypted_data) const {
+    absl::string_view encrypted_data, absl::string_view request_label) const {
   return ObliviousHttpRequest::CreateServerObliviousRequest(
-      encrypted_data, *(server_hpke_key_), ohttp_key_config_);
+      encrypted_data, *(server_hpke_key_), ohttp_key_config_, request_label);
 }
 
 absl::StatusOr<ObliviousHttpResponse>
 ObliviousHttpGateway::CreateObliviousHttpResponse(
     std::string plaintext_data,
-    ObliviousHttpRequest::Context& oblivious_http_request_context) const {
+    ObliviousHttpRequest::Context& oblivious_http_request_context,
+    absl::string_view response_label) const {
   return ObliviousHttpResponse::CreateServerObliviousResponse(
-      std::move(plaintext_data), oblivious_http_request_context,
+      std::move(plaintext_data), oblivious_http_request_context, response_label,
       quiche_random_);
 }
 
diff --git a/quiche/oblivious_http/oblivious_http_gateway.h b/quiche/oblivious_http/oblivious_http_gateway.h
index ae6c746..cd02841 100644
--- a/quiche/oblivious_http/oblivious_http_gateway.h
+++ b/quiche/oblivious_http/oblivious_http_gateway.h
@@ -55,7 +55,9 @@
   //    ohttp_server_object.DecryptObliviousHttpRequest(<encrypted binary http
   //    2>);
   absl::StatusOr<ObliviousHttpRequest> DecryptObliviousHttpRequest(
-      absl::string_view encrypted_data) const;
+      absl::string_view encrypted_data,
+      absl::string_view request_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel) const;
 
   // After `DecryptObliviousHttpRequest` operation, callers on server-side will
   // extract `oblivious_http_request_context` from the returned object
@@ -63,7 +65,9 @@
   // response flow back to the client.
   absl::StatusOr<ObliviousHttpResponse> CreateObliviousHttpResponse(
       std::string plaintext_data,
-      ObliviousHttpRequest::Context& oblivious_http_request_context) const;
+      ObliviousHttpRequest::Context& oblivious_http_request_context,
+      absl::string_view response_label =
+          ObliviousHttpHeaderKeyConfig::kOhttpResponseLabel) const;
 
  private:
   explicit ObliviousHttpGateway(