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