| #include <stdint.h> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/strings/escaping.h" | |
| #include "absl/strings/string_view.h" | |
| #include "openssl/hpke.h" | |
| #include "quiche/common/platform/api/quiche_test.h" | |
| #include "quiche/oblivious_http/buffers/oblivious_http_response.h" | |
| namespace quiche { | |
| namespace { | |
| struct ObliviousHttpResponseTestStrings { | |
| std::string test_case_name; | |
| uint8_t key_id; | |
| std::string request_plaintext; | |
| std::string response_plaintext; | |
| }; | |
| std::string GetHpkePrivateKey() { | |
| absl::string_view hpke_key_hex = | |
| "b77431ecfa8f4cfc30d6e467aafa06944dffe28cb9dd1409e33a3045f5adc8a1"; | |
| std::string hpke_key_bytes; | |
| EXPECT_TRUE(absl::HexStringToBytes(hpke_key_hex, &hpke_key_bytes)); | |
| return hpke_key_bytes; | |
| } | |
| std::string GetHpkePublicKey() { | |
| absl::string_view public_key = | |
| "6d21cfe09fbea5122f9ebc2eb2a69fcc4f06408cd54aac934f012e76fcdcef62"; | |
| std::string public_key_bytes; | |
| EXPECT_TRUE(absl::HexStringToBytes(public_key, &public_key_bytes)); | |
| return public_key_bytes; | |
| } | |
| ObliviousHttpHeaderKeyConfig GetOhttpKeyConfig(uint8_t key_id, uint16_t kem_id, | |
| uint16_t kdf_id, | |
| uint16_t aead_id) { | |
| auto ohttp_key_config = | |
| ObliviousHttpHeaderKeyConfig::Create(key_id, kem_id, kdf_id, aead_id); | |
| EXPECT_TRUE(ohttp_key_config.ok()); | |
| return std::move(ohttp_key_config.value()); | |
| } | |
| bssl::UniquePtr<EVP_HPKE_KEY> ConstructHpkeKey( | |
| absl::string_view hpke_key, | |
| const ObliviousHttpHeaderKeyConfig &ohttp_key_config) { | |
| bssl::UniquePtr<EVP_HPKE_KEY> bssl_hpke_key(EVP_HPKE_KEY_new()); | |
| EXPECT_NE(bssl_hpke_key, nullptr); | |
| EXPECT_TRUE(EVP_HPKE_KEY_init( | |
| bssl_hpke_key.get(), ohttp_key_config.GetHpkeKem(), | |
| reinterpret_cast<const uint8_t *>(hpke_key.data()), hpke_key.size())); | |
| return bssl_hpke_key; | |
| } | |
| } // namespace | |
| using ObliviousHttpParameterizedTest = | |
| test::QuicheTestWithParam<ObliviousHttpResponseTestStrings>; | |
| TEST_P(ObliviousHttpParameterizedTest, TestEndToEndWithOfflineStrings) { | |
| // For each test case, verify end to end request-handling and | |
| // response-handling. | |
| const ObliviousHttpResponseTestStrings &test = GetParam(); | |
| 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); | |
| 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); | |
| EXPECT_TRUE(server_req_decap.ok()); | |
| EXPECT_EQ(server_req_decap->GetPlaintextData(), test.request_plaintext); | |
| // 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); | |
| 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); | |
| EXPECT_TRUE(client_resp_decap.ok()); | |
| EXPECT_EQ(client_resp_decap->GetPlaintextData(), test.response_plaintext); | |
| } | |
| INSTANTIATE_TEST_SUITE_P( | |
| ObliviousHttpParameterizedTests, ObliviousHttpParameterizedTest, | |
| testing::ValuesIn<ObliviousHttpResponseTestStrings>( | |
| {{"test_case_1", 4, "test request 1", "test response 1"}, | |
| {"test_case_2", 6, "test request 2", "test response 2"}, | |
| {"test_case_3", 7, "test request 3", "test response 3"}, | |
| {"test_case_4", 2, "test request 4", "test response 4"}, | |
| {"test_case_5", 1, "test request 5", "test response 5"}, | |
| {"test_case_6", 7, "test request 6", "test response 6"}, | |
| {"test_case_7", 3, "test request 7", "test response 7"}, | |
| {"test_case_8", 9, "test request 8", "test response 8"}, | |
| {"test_case_9", 3, "test request 9", "test response 9"}, | |
| {"test_case_10", 4, "test request 10", "test response 10"}}), | |
| [](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 |