1 #include "quiche/oblivious_http/buffers/oblivious_http_request.h"
2 
3 #include <stddef.h>
4 
5 #include <cstdint>
6 #include <memory>
7 #include <string>
8 #include <utility>
9 
10 #include "absl/status/status.h"
11 #include "absl/status/statusor.h"
12 #include "absl/strings/escaping.h"
13 #include "absl/strings/str_cat.h"
14 #include "absl/strings/string_view.h"
15 #include "openssl/hkdf.h"
16 #include "openssl/hpke.h"
17 #include "quiche/common/platform/api/quiche_test.h"
18 #include "quiche/common/quiche_data_reader.h"
19 #include "quiche/oblivious_http/common/oblivious_http_header_key_config.h"
20 
21 namespace quiche {
22 
23 namespace {
24 const uint32_t kHeaderLength = ObliviousHttpHeaderKeyConfig::kHeaderLength;
GetHpkePrivateKey()25 std::string GetHpkePrivateKey() {
26   absl::string_view hpke_key_hex =
27       "b77431ecfa8f4cfc30d6e467aafa06944dffe28cb9dd1409e33a3045f5adc8a1";
28   std::string hpke_key_bytes;
29   EXPECT_TRUE(absl::HexStringToBytes(hpke_key_hex, &hpke_key_bytes));
30   return hpke_key_bytes;
31 }
32 
GetHpkePublicKey()33 std::string GetHpkePublicKey() {
34   absl::string_view public_key =
35       "6d21cfe09fbea5122f9ebc2eb2a69fcc4f06408cd54aac934f012e76fcdcef62";
36   std::string public_key_bytes;
37   EXPECT_TRUE(absl::HexStringToBytes(public_key, &public_key_bytes));
38   return public_key_bytes;
39 }
40 
GetAlternativeHpkePublicKey()41 std::string GetAlternativeHpkePublicKey() {
42   absl::string_view public_key =
43       "6d21cfe09fbea5122f9ebc2eb2a69fcc4f06408cd54aac934f012e76fcdcef63";
44   std::string public_key_bytes;
45   EXPECT_TRUE(absl::HexStringToBytes(public_key, &public_key_bytes));
46   return public_key_bytes;
47 }
48 
GetSeed()49 std::string GetSeed() {
50   absl::string_view seed =
51       "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736";
52   std::string seed_bytes;
53   EXPECT_TRUE(absl::HexStringToBytes(seed, &seed_bytes));
54   return seed_bytes;
55 }
56 
GetSeededEncapsulatedKey()57 std::string GetSeededEncapsulatedKey() {
58   absl::string_view encapsulated_key =
59       "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431";
60   std::string encapsulated_key_bytes;
61   EXPECT_TRUE(
62       absl::HexStringToBytes(encapsulated_key, &encapsulated_key_bytes));
63   return encapsulated_key_bytes;
64 }
65 
ConstructHpkeKey(absl::string_view hpke_key,const ObliviousHttpHeaderKeyConfig & ohttp_key_config)66 bssl::UniquePtr<EVP_HPKE_KEY> ConstructHpkeKey(
67     absl::string_view hpke_key,
68     const ObliviousHttpHeaderKeyConfig &ohttp_key_config) {
69   bssl::UniquePtr<EVP_HPKE_KEY> bssl_hpke_key(EVP_HPKE_KEY_new());
70   EXPECT_NE(bssl_hpke_key, nullptr);
71   EXPECT_TRUE(EVP_HPKE_KEY_init(
72       bssl_hpke_key.get(), ohttp_key_config.GetHpkeKem(),
73       reinterpret_cast<const uint8_t *>(hpke_key.data()), hpke_key.size()));
74   return bssl_hpke_key;
75 }
76 
GetOhttpKeyConfig(uint8_t key_id,uint16_t kem_id,uint16_t kdf_id,uint16_t aead_id)77 const ObliviousHttpHeaderKeyConfig GetOhttpKeyConfig(uint8_t key_id,
78                                                      uint16_t kem_id,
79                                                      uint16_t kdf_id,
80                                                      uint16_t aead_id) {
81   auto ohttp_key_config =
82       ObliviousHttpHeaderKeyConfig::Create(key_id, kem_id, kdf_id, aead_id);
83   EXPECT_TRUE(ohttp_key_config.ok());
84   return std::move(ohttp_key_config.value());
85 }
86 }  // namespace
87 
88 // Direct test example from OHttp spec.
89 // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#appendix-A
TEST(ObliviousHttpRequest,TestDecapsulateWithSpecAppendixAExample)90 TEST(ObliviousHttpRequest, TestDecapsulateWithSpecAppendixAExample) {
91   auto ohttp_key_config =
92       GetOhttpKeyConfig(/*key_id=*/1, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
93                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_128_GCM);
94 
95   // X25519 Secret key (priv key).
96   // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#appendix-A-2
97   constexpr absl::string_view kX25519SecretKey =
98       "3c168975674b2fa8e465970b79c8dcf09f1c741626480bd4c6162fc5b6a98e1a";
99 
100   // Encapsulated request.
101   // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#appendix-A-14
102   constexpr absl::string_view kEncapsulatedRequest =
103       "010020000100014b28f881333e7c164ffc499ad9796f877f4e1051ee6d31bad19dec96c2"
104       "08b4726374e469135906992e1268c594d2a10c695d858c40a026e7965e7d86b83dd440b2"
105       "c0185204b4d63525";
106 
107   // Initialize Request obj to Decapsulate (decrypt).
108   std::string encapsulated_request_bytes;
109   ASSERT_TRUE(absl::HexStringToBytes(kEncapsulatedRequest,
110                                      &encapsulated_request_bytes));
111   std::string x25519_secret_key_bytes;
112   ASSERT_TRUE(
113       absl::HexStringToBytes(kX25519SecretKey, &x25519_secret_key_bytes));
114   auto instance = ObliviousHttpRequest::CreateServerObliviousRequest(
115       encapsulated_request_bytes,
116       *(ConstructHpkeKey(x25519_secret_key_bytes, ohttp_key_config)),
117       ohttp_key_config);
118   ASSERT_TRUE(instance.ok());
119   auto decrypted = instance->GetPlaintextData();
120 
121   // Encapsulated/Ephemeral public key.
122   // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#appendix-A-10
123   constexpr absl::string_view kExpectedEphemeralPublicKey =
124       "4b28f881333e7c164ffc499ad9796f877f4e1051ee6d31bad19dec96c208b472";
125   std::string expected_ephemeral_public_key_bytes;
126   ASSERT_TRUE(absl::HexStringToBytes(kExpectedEphemeralPublicKey,
127                                      &expected_ephemeral_public_key_bytes));
128   auto oblivious_request_context = std::move(instance.value()).ReleaseContext();
129   EXPECT_EQ(oblivious_request_context.encapsulated_key_,
130             expected_ephemeral_public_key_bytes);
131 
132   // Binary HTTP message.
133   // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#appendix-A-6
134   constexpr absl::string_view kExpectedBinaryHTTPMessage =
135       "00034745540568747470730b6578616d706c652e636f6d012f";
136   std::string expected_binary_http_message_bytes;
137   ASSERT_TRUE(absl::HexStringToBytes(kExpectedBinaryHTTPMessage,
138                                      &expected_binary_http_message_bytes));
139   EXPECT_EQ(decrypted, expected_binary_http_message_bytes);
140 }
141 
TEST(ObliviousHttpRequest,TestEncapsulatedRequestStructure)142 TEST(ObliviousHttpRequest, TestEncapsulatedRequestStructure) {
143   uint8_t test_key_id = 7;
144   uint16_t test_kem_id = EVP_HPKE_DHKEM_X25519_HKDF_SHA256;
145   uint16_t test_kdf_id = EVP_HPKE_HKDF_SHA256;
146   uint16_t test_aead_id = EVP_HPKE_AES_256_GCM;
147   std::string plaintext = "test";
148   auto instance = ObliviousHttpRequest::CreateClientObliviousRequest(
149       plaintext, GetHpkePublicKey(),
150       GetOhttpKeyConfig(test_key_id, test_kem_id, test_kdf_id, test_aead_id));
151   ASSERT_TRUE(instance.ok());
152   auto payload_bytes = instance->EncapsulateAndSerialize();
153   EXPECT_GE(payload_bytes.size(), kHeaderLength);
154   // Parse header.
155   QuicheDataReader reader(payload_bytes);
156   uint8_t key_id;
157   EXPECT_TRUE(reader.ReadUInt8(&key_id));
158   EXPECT_EQ(key_id, test_key_id);
159   uint16_t kem_id;
160   EXPECT_TRUE(reader.ReadUInt16(&kem_id));
161   EXPECT_EQ(kem_id, test_kem_id);
162   uint16_t kdf_id;
163   EXPECT_TRUE(reader.ReadUInt16(&kdf_id));
164   EXPECT_EQ(kdf_id, test_kdf_id);
165   uint16_t aead_id;
166   EXPECT_TRUE(reader.ReadUInt16(&aead_id));
167   EXPECT_EQ(aead_id, test_aead_id);
168   auto client_request_context = std::move(instance.value()).ReleaseContext();
169   auto client_encapsulated_key = client_request_context.encapsulated_key_;
170   EXPECT_EQ(client_encapsulated_key.size(), X25519_PUBLIC_VALUE_LEN);
171   auto enc_key_plus_ciphertext = payload_bytes.substr(kHeaderLength);
172   auto packed_encapsulated_key =
173       enc_key_plus_ciphertext.substr(0, X25519_PUBLIC_VALUE_LEN);
174   EXPECT_EQ(packed_encapsulated_key, client_encapsulated_key);
175   auto ciphertext = enc_key_plus_ciphertext.substr(X25519_PUBLIC_VALUE_LEN);
176   EXPECT_GE(ciphertext.size(), plaintext.size());
177 }
178 
TEST(ObliviousHttpRequest,TestDeterministicSeededOhttpRequest)179 TEST(ObliviousHttpRequest, TestDeterministicSeededOhttpRequest) {
180   auto ohttp_key_config =
181       GetOhttpKeyConfig(4, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
182                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
183   auto encapsulated = ObliviousHttpRequest::CreateClientWithSeedForTesting(
184       "test", GetHpkePublicKey(), ohttp_key_config, GetSeed());
185   ASSERT_TRUE(encapsulated.ok());
186   auto encapsulated_request = encapsulated->EncapsulateAndSerialize();
187   auto ohttp_request_context = std::move(encapsulated.value()).ReleaseContext();
188   EXPECT_EQ(ohttp_request_context.encapsulated_key_,
189             GetSeededEncapsulatedKey());
190   absl::string_view expected_encrypted_request =
191       "9f37cfed07d0111ecd2c34f794671759bcbd922a";
192   std::string expected_encrypted_request_bytes;
193   ASSERT_TRUE(absl::HexStringToBytes(expected_encrypted_request,
194                                      &expected_encrypted_request_bytes));
195   EXPECT_NE(ohttp_request_context.hpke_context_, nullptr);
196   size_t encapsulated_key_len = EVP_HPKE_KEM_enc_len(
197       EVP_HPKE_CTX_kem(ohttp_request_context.hpke_context_.get()));
198   int encrypted_payload_offset = kHeaderLength + encapsulated_key_len;
199   EXPECT_EQ(encapsulated_request.substr(encrypted_payload_offset),
200             expected_encrypted_request_bytes);
201 }
202 
TEST(ObliviousHttpRequest,TestSeededEncapsulatedKeySamePlaintextsSameCiphertexts)203 TEST(ObliviousHttpRequest,
204      TestSeededEncapsulatedKeySamePlaintextsSameCiphertexts) {
205   auto ohttp_key_config =
206       GetOhttpKeyConfig(8, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
207                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
208   auto req_with_same_plaintext_1 =
209       ObliviousHttpRequest::CreateClientWithSeedForTesting(
210           "same plaintext", GetHpkePublicKey(), ohttp_key_config, GetSeed());
211   ASSERT_TRUE(req_with_same_plaintext_1.ok());
212   auto ciphertext_1 = req_with_same_plaintext_1->EncapsulateAndSerialize();
213   auto req_with_same_plaintext_2 =
214       ObliviousHttpRequest::CreateClientWithSeedForTesting(
215           "same plaintext", GetHpkePublicKey(), ohttp_key_config, GetSeed());
216   ASSERT_TRUE(req_with_same_plaintext_2.ok());
217   auto ciphertext_2 = req_with_same_plaintext_2->EncapsulateAndSerialize();
218   EXPECT_EQ(ciphertext_1, ciphertext_2);
219 }
220 
TEST(ObliviousHttpRequest,TestSeededEncapsulatedKeyDifferentPlaintextsDifferentCiphertexts)221 TEST(ObliviousHttpRequest,
222      TestSeededEncapsulatedKeyDifferentPlaintextsDifferentCiphertexts) {
223   auto ohttp_key_config =
224       GetOhttpKeyConfig(8, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
225                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
226   auto req_with_different_plaintext_1 =
227       ObliviousHttpRequest::CreateClientWithSeedForTesting(
228           "different 1", GetHpkePublicKey(), ohttp_key_config, GetSeed());
229   ASSERT_TRUE(req_with_different_plaintext_1.ok());
230   auto ciphertext_1 = req_with_different_plaintext_1->EncapsulateAndSerialize();
231   auto req_with_different_plaintext_2 =
232       ObliviousHttpRequest::CreateClientWithSeedForTesting(
233           "different 2", GetHpkePublicKey(), ohttp_key_config, GetSeed());
234   ASSERT_TRUE(req_with_different_plaintext_2.ok());
235   auto ciphertext_2 = req_with_different_plaintext_2->EncapsulateAndSerialize();
236   EXPECT_NE(ciphertext_1, ciphertext_2);
237 }
238 
TEST(ObliviousHttpRequest,TestInvalidInputsOnClientSide)239 TEST(ObliviousHttpRequest, TestInvalidInputsOnClientSide) {
240   auto ohttp_key_config =
241       GetOhttpKeyConfig(30, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
242                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
243   // Empty plaintext.
244   EXPECT_EQ(ObliviousHttpRequest::CreateClientObliviousRequest(
245                 /*plaintext_payload*/ "", GetHpkePublicKey(), ohttp_key_config)
246                 .status()
247                 .code(),
248             absl::StatusCode::kInvalidArgument);
249   // Empty HPKE public key.
250   EXPECT_EQ(ObliviousHttpRequest::CreateClientObliviousRequest(
251                 "some plaintext",
252                 /*hpke_public_key*/ "", ohttp_key_config)
253                 .status()
254                 .code(),
255             absl::StatusCode::kInvalidArgument);
256 }
257 
TEST(ObliviousHttpRequest,TestInvalidInputsOnServerSide)258 TEST(ObliviousHttpRequest, TestInvalidInputsOnServerSide) {
259   auto ohttp_key_config =
260       GetOhttpKeyConfig(4, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
261                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
262   // Empty encrypted payload.
263   EXPECT_EQ(ObliviousHttpRequest::CreateServerObliviousRequest(
264                 /*encrypted_data*/ "",
265                 *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
266                 ohttp_key_config)
267                 .status()
268                 .code(),
269             absl::StatusCode::kInvalidArgument);
270   // Empty EVP_HPKE_KEY struct.
271   EXPECT_EQ(ObliviousHttpRequest::CreateServerObliviousRequest(
272                 absl::StrCat(ohttp_key_config.SerializeOhttpPayloadHeader(),
273                              GetSeededEncapsulatedKey(),
274                              "9f37cfed07d0111ecd2c34f794671759bcbd922a"),
275                 /*gateway_key*/ {}, ohttp_key_config)
276                 .status()
277                 .code(),
278             absl::StatusCode::kInvalidArgument);
279 }
280 
TEST(ObliviousHttpRequest,EndToEndTestForRequest)281 TEST(ObliviousHttpRequest, EndToEndTestForRequest) {
282   auto ohttp_key_config =
283       GetOhttpKeyConfig(5, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
284                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
285   auto encapsulate = ObliviousHttpRequest::CreateClientObliviousRequest(
286       "test", GetHpkePublicKey(), ohttp_key_config);
287   ASSERT_TRUE(encapsulate.ok());
288   auto oblivious_request = encapsulate->EncapsulateAndSerialize();
289   auto decapsulate = ObliviousHttpRequest::CreateServerObliviousRequest(
290       oblivious_request,
291       *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
292       ohttp_key_config);
293   ASSERT_TRUE(decapsulate.ok());
294   auto decrypted = decapsulate->GetPlaintextData();
295   EXPECT_EQ(decrypted, "test");
296 }
297 
TEST(ObliviousHttpRequest,EndToEndTestForRequestWithWrongKey)298 TEST(ObliviousHttpRequest, EndToEndTestForRequestWithWrongKey) {
299   auto ohttp_key_config =
300       GetOhttpKeyConfig(5, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
301                         EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
302   auto encapsulate = ObliviousHttpRequest::CreateClientObliviousRequest(
303       "test", GetAlternativeHpkePublicKey(), ohttp_key_config);
304   ASSERT_TRUE(encapsulate.ok());
305   auto oblivious_request = encapsulate->EncapsulateAndSerialize();
306   auto decapsulate = ObliviousHttpRequest::CreateServerObliviousRequest(
307       oblivious_request,
308       *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
309       ohttp_key_config);
310   EXPECT_EQ(decapsulate.status().code(), absl::StatusCode::kInvalidArgument);
311 }
312 }  // namespace quiche
313