1 #include "quiche/oblivious_http/oblivious_http_client.h"
2 
3 #include <stdint.h>
4 
5 #include <memory>
6 #include <string>
7 #include <utility>
8 
9 #include "absl/status/status.h"
10 #include "absl/status/statusor.h"
11 #include "absl/strings/escaping.h"
12 #include "absl/strings/string_view.h"
13 #include "quiche/common/platform/api/quiche_test.h"
14 #include "quiche/common/platform/api/quiche_thread.h"
15 
16 namespace quiche {
17 
GetHpkePrivateKey()18 std::string GetHpkePrivateKey() {
19   // Dev/Test private key generated using Keystore.
20   absl::string_view hpke_key_hex =
21       "b77431ecfa8f4cfc30d6e467aafa06944dffe28cb9dd1409e33a3045f5adc8a1";
22   std::string hpke_key_bytes;
23   EXPECT_TRUE(absl::HexStringToBytes(hpke_key_hex, &hpke_key_bytes));
24   return hpke_key_bytes;
25 }
26 
GetHpkePublicKey()27 std::string GetHpkePublicKey() {
28   // Dev/Test public key generated using Keystore.
29   absl::string_view public_key =
30       "6d21cfe09fbea5122f9ebc2eb2a69fcc4f06408cd54aac934f012e76fcdcef62";
31   std::string public_key_bytes;
32   EXPECT_TRUE(absl::HexStringToBytes(public_key, &public_key_bytes));
33   return public_key_bytes;
34 }
35 
GetOhttpKeyConfig(uint8_t key_id,uint16_t kem_id,uint16_t kdf_id,uint16_t aead_id)36 const ObliviousHttpHeaderKeyConfig GetOhttpKeyConfig(uint8_t key_id,
37                                                      uint16_t kem_id,
38                                                      uint16_t kdf_id,
39                                                      uint16_t aead_id) {
40   auto ohttp_key_config =
41       ObliviousHttpHeaderKeyConfig::Create(key_id, kem_id, kdf_id, aead_id);
42   EXPECT_TRUE(ohttp_key_config.ok());
43   return ohttp_key_config.value();
44 }
45 
ConstructHpkeKey(absl::string_view hpke_key,const ObliviousHttpHeaderKeyConfig & ohttp_key_config)46 bssl::UniquePtr<EVP_HPKE_KEY> ConstructHpkeKey(
47     absl::string_view hpke_key,
48     const ObliviousHttpHeaderKeyConfig& ohttp_key_config) {
49   bssl::UniquePtr<EVP_HPKE_KEY> bssl_hpke_key(EVP_HPKE_KEY_new());
50   EXPECT_NE(bssl_hpke_key, nullptr);
51   EXPECT_TRUE(EVP_HPKE_KEY_init(
52       bssl_hpke_key.get(), ohttp_key_config.GetHpkeKem(),
53       reinterpret_cast<const uint8_t*>(hpke_key.data()), hpke_key.size()));
54   return bssl_hpke_key;
55 }
56 
TEST(ObliviousHttpClient,TestEncapsulate)57 TEST(ObliviousHttpClient, TestEncapsulate) {
58   auto client = ObliviousHttpClient::Create(
59       GetHpkePublicKey(),
60       GetOhttpKeyConfig(8, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
61                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM));
62   ASSERT_TRUE(client.ok());
63   auto encrypted_req = client->CreateObliviousHttpRequest("test string 1");
64   ASSERT_TRUE(encrypted_req.ok());
65   auto serialized_encrypted_req = encrypted_req->EncapsulateAndSerialize();
66   ASSERT_FALSE(serialized_encrypted_req.empty());
67 }
68 
TEST(ObliviousHttpClient,TestEncryptingMultipleRequestsWithSingleInstance)69 TEST(ObliviousHttpClient, TestEncryptingMultipleRequestsWithSingleInstance) {
70   auto client = ObliviousHttpClient::Create(
71       GetHpkePublicKey(),
72       GetOhttpKeyConfig(1, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
73                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM));
74   ASSERT_TRUE(client.ok());
75   auto ohttp_req_1 = client->CreateObliviousHttpRequest("test string 1");
76   ASSERT_TRUE(ohttp_req_1.ok());
77   auto serialized_ohttp_req_1 = ohttp_req_1->EncapsulateAndSerialize();
78   ASSERT_FALSE(serialized_ohttp_req_1.empty());
79   auto ohttp_req_2 = client->CreateObliviousHttpRequest("test string 2");
80   ASSERT_TRUE(ohttp_req_2.ok());
81   auto serialized_ohttp_req_2 = ohttp_req_2->EncapsulateAndSerialize();
82   ASSERT_FALSE(serialized_ohttp_req_2.empty());
83   EXPECT_NE(serialized_ohttp_req_1, serialized_ohttp_req_2);
84 }
85 
TEST(ObliviousHttpClient,TestInvalidHPKEKey)86 TEST(ObliviousHttpClient, TestInvalidHPKEKey) {
87   // Invalid public key.
88   EXPECT_EQ(ObliviousHttpClient::Create(
89                 "Invalid HPKE key",
90                 GetOhttpKeyConfig(50, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
91                                   EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM))
92                 .status()
93                 .code(),
94             absl::StatusCode::kInvalidArgument);
95   // Empty public key.
96   EXPECT_EQ(ObliviousHttpClient::Create(
97                 /*hpke_public_key*/ "",
98                 GetOhttpKeyConfig(50, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
99                                   EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM))
100                 .status()
101                 .code(),
102             absl::StatusCode::kInvalidArgument);
103 }
104 
TEST(ObliviousHttpClient,TestTwoSamePlaintextsWillGenerateDifferentEncryptedPayloads)105 TEST(ObliviousHttpClient,
106      TestTwoSamePlaintextsWillGenerateDifferentEncryptedPayloads) {
107   // Due to the nature of the encapsulated_key generated in HPKE being unique
108   // for every request, expect different encrypted payloads when encrypting same
109   // plaintexts.
110   auto client = ObliviousHttpClient::Create(
111       GetHpkePublicKey(),
112       GetOhttpKeyConfig(1, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
113                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM));
114   ASSERT_TRUE(client.ok());
115   auto encrypted_request_1 =
116       client->CreateObliviousHttpRequest("same plaintext");
117   ASSERT_TRUE(encrypted_request_1.ok());
118   auto serialized_encrypted_request_1 =
119       encrypted_request_1->EncapsulateAndSerialize();
120   ASSERT_FALSE(serialized_encrypted_request_1.empty());
121   auto encrypted_request_2 =
122       client->CreateObliviousHttpRequest("same plaintext");
123   ASSERT_TRUE(encrypted_request_2.ok());
124   auto serialized_encrypted_request_2 =
125       encrypted_request_2->EncapsulateAndSerialize();
126   ASSERT_FALSE(serialized_encrypted_request_2.empty());
127   EXPECT_NE(serialized_encrypted_request_1, serialized_encrypted_request_2);
128 }
129 
TEST(ObliviousHttpClient,TestObliviousResponseHandling)130 TEST(ObliviousHttpClient, TestObliviousResponseHandling) {
131   auto ohttp_key_config =
132       GetOhttpKeyConfig(1, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
133                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
134   auto encapsulate_req_on_client =
135       ObliviousHttpRequest::CreateClientObliviousRequest(
136           "test", GetHpkePublicKey(), ohttp_key_config);
137   ASSERT_TRUE(encapsulate_req_on_client.ok());
138   auto decapsulate_req_on_gateway =
139       ObliviousHttpRequest::CreateServerObliviousRequest(
140           encapsulate_req_on_client->EncapsulateAndSerialize(),
141           *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
142           ohttp_key_config);
143   ASSERT_TRUE(decapsulate_req_on_gateway.ok());
144   auto gateway_request_context =
145       std::move(decapsulate_req_on_gateway.value()).ReleaseContext();
146   auto encapsulate_resp_on_gateway =
147       ObliviousHttpResponse::CreateServerObliviousResponse(
148           "test response", gateway_request_context);
149   ASSERT_TRUE(encapsulate_resp_on_gateway.ok());
150 
151   auto client =
152       ObliviousHttpClient::Create(GetHpkePublicKey(), ohttp_key_config);
153   ASSERT_TRUE(client.ok());
154   auto client_request_context =
155       std::move(encapsulate_req_on_client.value()).ReleaseContext();
156   auto decapsulate_resp_on_client = client->DecryptObliviousHttpResponse(
157       encapsulate_resp_on_gateway->EncapsulateAndSerialize(),
158       client_request_context);
159   ASSERT_TRUE(decapsulate_resp_on_client.ok());
160   EXPECT_EQ(decapsulate_resp_on_client->GetPlaintextData(), "test response");
161 }
162 
TEST(ObliviousHttpClient,DecryptResponseReceivedByTheClientUsingServersObliviousContext)163 TEST(ObliviousHttpClient,
164      DecryptResponseReceivedByTheClientUsingServersObliviousContext) {
165   auto ohttp_key_config =
166       GetOhttpKeyConfig(1, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
167                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
168   auto encapsulate_req_on_client =
169       ObliviousHttpRequest::CreateClientObliviousRequest(
170           "test", GetHpkePublicKey(), ohttp_key_config);
171   ASSERT_TRUE(encapsulate_req_on_client.ok());
172   auto decapsulate_req_on_gateway =
173       ObliviousHttpRequest::CreateServerObliviousRequest(
174           encapsulate_req_on_client->EncapsulateAndSerialize(),
175           *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
176           ohttp_key_config);
177   ASSERT_TRUE(decapsulate_req_on_gateway.ok());
178   auto gateway_request_context =
179       std::move(decapsulate_req_on_gateway.value()).ReleaseContext();
180   auto encapsulate_resp_on_gateway =
181       ObliviousHttpResponse::CreateServerObliviousResponse(
182           "test response", gateway_request_context);
183   ASSERT_TRUE(encapsulate_resp_on_gateway.ok());
184 
185   auto client =
186       ObliviousHttpClient::Create(GetHpkePublicKey(), ohttp_key_config);
187   ASSERT_TRUE(client.ok());
188   auto decapsulate_resp_on_client = client->DecryptObliviousHttpResponse(
189       encapsulate_resp_on_gateway->EncapsulateAndSerialize(),
190       gateway_request_context);
191   ASSERT_TRUE(decapsulate_resp_on_client.ok());
192   EXPECT_EQ(decapsulate_resp_on_client->GetPlaintextData(), "test response");
193 }
194 
TEST(ObliviousHttpClient,TestWithMultipleThreads)195 TEST(ObliviousHttpClient, TestWithMultipleThreads) {
196   class TestQuicheThread : public QuicheThread {
197    public:
198     TestQuicheThread(const ObliviousHttpClient& client,
199                      std::string request_payload,
200                      ObliviousHttpHeaderKeyConfig ohttp_key_config)
201         : QuicheThread("client_thread"),
202           client_(client),
203           request_payload_(request_payload),
204           ohttp_key_config_(ohttp_key_config) {}
205 
206    protected:
207     void Run() override {
208       auto encrypted_request =
209           client_.CreateObliviousHttpRequest(request_payload_);
210       ASSERT_TRUE(encrypted_request.ok());
211       ASSERT_FALSE(encrypted_request->EncapsulateAndSerialize().empty());
212       // Setup recipient and get encrypted response payload.
213       auto decapsulate_req_on_gateway =
214           ObliviousHttpRequest::CreateServerObliviousRequest(
215               encrypted_request->EncapsulateAndSerialize(),
216               *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config_)),
217               ohttp_key_config_);
218       ASSERT_TRUE(decapsulate_req_on_gateway.ok());
219       auto gateway_request_context =
220           std::move(decapsulate_req_on_gateway.value()).ReleaseContext();
221       auto encapsulate_resp_on_gateway =
222           ObliviousHttpResponse::CreateServerObliviousResponse(
223               "test response", gateway_request_context);
224       ASSERT_TRUE(encapsulate_resp_on_gateway.ok());
225       ASSERT_FALSE(
226           encapsulate_resp_on_gateway->EncapsulateAndSerialize().empty());
227       auto client_request_context =
228           std::move(encrypted_request.value()).ReleaseContext();
229       auto decrypted_response = client_.DecryptObliviousHttpResponse(
230           encapsulate_resp_on_gateway->EncapsulateAndSerialize(),
231           client_request_context);
232       ASSERT_TRUE(decrypted_response.ok());
233       ASSERT_FALSE(decrypted_response->GetPlaintextData().empty());
234     }
235 
236    private:
237     const ObliviousHttpClient& client_;
238     std::string request_payload_;
239     ObliviousHttpHeaderKeyConfig ohttp_key_config_;
240   };
241 
242   auto ohttp_key_config =
243       GetOhttpKeyConfig(1, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
244                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
245   auto client =
246       ObliviousHttpClient::Create(GetHpkePublicKey(), ohttp_key_config);
247 
248   TestQuicheThread t1(*client, "test request 1", ohttp_key_config);
249   TestQuicheThread t2(*client, "test request 2", ohttp_key_config);
250   t1.Start();
251   t2.Start();
252   t1.Join();
253   t2.Join();
254 }
255 
256 }  // namespace quiche
257