1 #include "quiche/oblivious_http/common/oblivious_http_header_key_config.h"
2
3 #include <cstdint>
4 #include <string>
5
6 #include "absl/strings/escaping.h"
7 #include "absl/strings/str_cat.h"
8 #include "openssl/hpke.h"
9 #include "quiche/common/platform/api/quiche_logging.h"
10 #include "quiche/common/platform/api/quiche_test.h"
11 #include "quiche/common/quiche_data_writer.h"
12
13 namespace quiche {
14 namespace {
15 using ::testing::AllOf;
16 using ::testing::Property;
17 using ::testing::StrEq;
18 using ::testing::UnorderedElementsAre;
19 using ::testing::UnorderedElementsAreArray;
20
21 /**
22 * Build Request header.
23 */
BuildHeader(uint8_t key_id,uint16_t kem_id,uint16_t kdf_id,uint16_t aead_id)24 std::string BuildHeader(uint8_t key_id, uint16_t kem_id, uint16_t kdf_id,
25 uint16_t aead_id) {
26 int buf_len =
27 sizeof(key_id) + sizeof(kem_id) + sizeof(kdf_id) + sizeof(aead_id);
28 std::string hdr(buf_len, '\0');
29 QuicheDataWriter writer(hdr.size(), hdr.data());
30 EXPECT_TRUE(writer.WriteUInt8(key_id));
31 EXPECT_TRUE(writer.WriteUInt16(kem_id)); // kemID
32 EXPECT_TRUE(writer.WriteUInt16(kdf_id)); // kdfID
33 EXPECT_TRUE(writer.WriteUInt16(aead_id)); // aeadID
34 return hdr;
35 }
36
GetSerializedKeyConfig(ObliviousHttpKeyConfigs::OhttpKeyConfig & key_config)37 std::string GetSerializedKeyConfig(
38 ObliviousHttpKeyConfigs::OhttpKeyConfig& key_config) {
39 uint16_t symmetric_algs_length =
40 key_config.symmetric_algorithms.size() *
41 (sizeof(key_config.symmetric_algorithms.cbegin()->kdf_id) +
42 sizeof(key_config.symmetric_algorithms.cbegin()->aead_id));
43 int buf_len = sizeof(key_config.key_id) + sizeof(key_config.kem_id) +
44 key_config.public_key.size() + sizeof(symmetric_algs_length) +
45 symmetric_algs_length;
46 std::string ohttp_key(buf_len, '\0');
47 QuicheDataWriter writer(ohttp_key.size(), ohttp_key.data());
48 EXPECT_TRUE(writer.WriteUInt8(key_config.key_id));
49 EXPECT_TRUE(writer.WriteUInt16(key_config.kem_id));
50 EXPECT_TRUE(writer.WriteStringPiece(key_config.public_key));
51 EXPECT_TRUE(writer.WriteUInt16(symmetric_algs_length));
52 for (const auto& symmetric_alg : key_config.symmetric_algorithms) {
53 EXPECT_TRUE(writer.WriteUInt16(symmetric_alg.kdf_id));
54 EXPECT_TRUE(writer.WriteUInt16(symmetric_alg.aead_id));
55 }
56 return ohttp_key;
57 }
58
TEST(ObliviousHttpHeaderKeyConfig,TestSerializeRecipientContextInfo)59 TEST(ObliviousHttpHeaderKeyConfig, TestSerializeRecipientContextInfo) {
60 uint8_t key_id = 3;
61 uint16_t kem_id = EVP_HPKE_DHKEM_X25519_HKDF_SHA256;
62 uint16_t kdf_id = EVP_HPKE_HKDF_SHA256;
63 uint16_t aead_id = EVP_HPKE_AES_256_GCM;
64 absl::string_view ohttp_req_label = "message/bhttp request";
65 std::string expected(ohttp_req_label);
66 uint8_t zero_byte = 0x00;
67 int buf_len = ohttp_req_label.size() + sizeof(zero_byte) + sizeof(key_id) +
68 sizeof(kem_id) + sizeof(kdf_id) + sizeof(aead_id);
69 expected.reserve(buf_len);
70 expected.push_back(zero_byte);
71 std::string ohttp_cfg(BuildHeader(key_id, kem_id, kdf_id, aead_id));
72 expected.insert(expected.end(), ohttp_cfg.begin(), ohttp_cfg.end());
73 auto instance =
74 ObliviousHttpHeaderKeyConfig::Create(key_id, kem_id, kdf_id, aead_id);
75 ASSERT_TRUE(instance.ok());
76 EXPECT_EQ(instance.value().SerializeRecipientContextInfo(), expected);
77 }
78
TEST(ObliviousHttpHeaderKeyConfig,TestValidKeyConfig)79 TEST(ObliviousHttpHeaderKeyConfig, TestValidKeyConfig) {
80 auto valid_key_config = ObliviousHttpHeaderKeyConfig::Create(
81 2, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
82 EVP_HPKE_AES_256_GCM);
83 ASSERT_TRUE(valid_key_config.ok());
84 }
85
TEST(ObliviousHttpHeaderKeyConfig,TestInvalidKeyConfig)86 TEST(ObliviousHttpHeaderKeyConfig, TestInvalidKeyConfig) {
87 auto invalid_kem = ObliviousHttpHeaderKeyConfig::Create(
88 3, 0, EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
89 EXPECT_EQ(invalid_kem.status().code(), absl::StatusCode::kInvalidArgument);
90 auto invalid_kdf = ObliviousHttpHeaderKeyConfig::Create(
91 3, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, 0, EVP_HPKE_AES_256_GCM);
92 EXPECT_EQ(invalid_kdf.status().code(), absl::StatusCode::kInvalidArgument);
93 auto invalid_aead = ObliviousHttpHeaderKeyConfig::Create(
94 3, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256, 0);
95 EXPECT_EQ(invalid_kdf.status().code(), absl::StatusCode::kInvalidArgument);
96 }
97
TEST(ObliviousHttpHeaderKeyConfig,TestParsingValidHeader)98 TEST(ObliviousHttpHeaderKeyConfig, TestParsingValidHeader) {
99 auto instance = ObliviousHttpHeaderKeyConfig::Create(
100 5, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
101 EVP_HPKE_AES_256_GCM);
102 ASSERT_TRUE(instance.ok());
103 std::string good_hdr(BuildHeader(5, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
104 EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM));
105 ASSERT_TRUE(instance.value().ParseOhttpPayloadHeader(good_hdr).ok());
106 }
107
TEST(ObliviousHttpHeaderKeyConfig,TestParsingInvalidHeader)108 TEST(ObliviousHttpHeaderKeyConfig, TestParsingInvalidHeader) {
109 auto instance = ObliviousHttpHeaderKeyConfig::Create(
110 8, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
111 EVP_HPKE_AES_256_GCM);
112 ASSERT_TRUE(instance.ok());
113 std::string keyid_mismatch_hdr(
114 BuildHeader(0, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
115 EVP_HPKE_AES_256_GCM));
116 EXPECT_EQ(instance.value().ParseOhttpPayloadHeader(keyid_mismatch_hdr).code(),
117 absl::StatusCode::kInvalidArgument);
118 std::string invalid_hpke_hdr(BuildHeader(8, 0, 0, 0));
119 EXPECT_EQ(instance.value().ParseOhttpPayloadHeader(invalid_hpke_hdr).code(),
120 absl::StatusCode::kInvalidArgument);
121 }
122
TEST(ObliviousHttpHeaderKeyConfig,TestParsingKeyIdFromObliviousHttpRequest)123 TEST(ObliviousHttpHeaderKeyConfig, TestParsingKeyIdFromObliviousHttpRequest) {
124 std::string key_id(sizeof(uint8_t), '\0');
125 QuicheDataWriter writer(key_id.size(), key_id.data());
126 EXPECT_TRUE(writer.WriteUInt8(99));
127 auto parsed_key_id =
128 ObliviousHttpHeaderKeyConfig::ParseKeyIdFromObliviousHttpRequestPayload(
129 key_id);
130 ASSERT_TRUE(parsed_key_id.ok());
131 EXPECT_EQ(parsed_key_id.value(), 99);
132 }
133
TEST(ObliviousHttpHeaderKeyConfig,TestCopyable)134 TEST(ObliviousHttpHeaderKeyConfig, TestCopyable) {
135 auto obj1 = ObliviousHttpHeaderKeyConfig::Create(
136 4, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
137 EVP_HPKE_AES_256_GCM);
138 ASSERT_TRUE(obj1.ok());
139 auto copy_obj1_to_obj2 = obj1.value();
140 EXPECT_EQ(copy_obj1_to_obj2.kHeaderLength, obj1->kHeaderLength);
141 EXPECT_EQ(copy_obj1_to_obj2.SerializeRecipientContextInfo(),
142 obj1->SerializeRecipientContextInfo());
143 }
144
TEST(ObliviousHttpHeaderKeyConfig,TestSerializeOhttpPayloadHeader)145 TEST(ObliviousHttpHeaderKeyConfig, TestSerializeOhttpPayloadHeader) {
146 auto instance = ObliviousHttpHeaderKeyConfig::Create(
147 7, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
148 EVP_HPKE_AES_128_GCM);
149 ASSERT_TRUE(instance.ok());
150 EXPECT_EQ(instance->SerializeOhttpPayloadHeader(),
151 BuildHeader(7, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
152 EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_128_GCM));
153 }
154
155 MATCHER_P(HasKeyId, id, "") {
156 *result_listener << "has key_id=" << arg.GetKeyId();
157 return arg.GetKeyId() == id;
158 }
159 MATCHER_P(HasKemId, id, "") {
160 *result_listener << "has kem_id=" << arg.GetHpkeKemId();
161 return arg.GetHpkeKemId() == id;
162 }
163 MATCHER_P(HasKdfId, id, "") {
164 *result_listener << "has kdf_id=" << arg.GetHpkeKdfId();
165 return arg.GetHpkeKdfId() == id;
166 }
167 MATCHER_P(HasAeadId, id, "") {
168 *result_listener << "has aead_id=" << arg.GetHpkeAeadId();
169 return arg.GetHpkeAeadId() == id;
170 }
171
TEST(ObliviousHttpKeyConfigs,SingleKeyConfig)172 TEST(ObliviousHttpKeyConfigs, SingleKeyConfig) {
173 std::string key;
174 ASSERT_TRUE(absl::HexStringToBytes(
175 "4b0020f83e0a17cbdb18d2684dd2a9b087a43e5f3fa3fa27a049bc746a6e97a1e0244b00"
176 "0400010002",
177 &key));
178 auto configs = ObliviousHttpKeyConfigs::ParseConcatenatedKeys(key).value();
179 EXPECT_THAT(configs, Property(&ObliviousHttpKeyConfigs::NumKeys, 1));
180 EXPECT_THAT(
181 configs.PreferredConfig(),
182 AllOf(HasKeyId(0x4b), HasKemId(EVP_HPKE_DHKEM_X25519_HKDF_SHA256),
183 HasKdfId(EVP_HPKE_HKDF_SHA256), HasAeadId(EVP_HPKE_AES_256_GCM)));
184 std::string expected_public_key;
185 ASSERT_TRUE(absl::HexStringToBytes(
186 "f83e0a17cbdb18d2684dd2a9b087a43e5f3fa3fa27a049bc746a6e97a1e0244b",
187 &expected_public_key));
188 EXPECT_THAT(
189 configs.GetPublicKeyForId(configs.PreferredConfig().GetKeyId()).value(),
190 StrEq(expected_public_key));
191 }
192
TEST(ObliviousHttpKeyConfigs,TwoSimilarKeyConfigs)193 TEST(ObliviousHttpKeyConfigs, TwoSimilarKeyConfigs) {
194 std::string key;
195 ASSERT_TRUE(absl::HexStringToBytes(
196 "4b0020f83e0a17cbdb18d2684dd2a9b087a43e5f3fa3fa27a049bc746a6e97a1e0244b00"
197 "0400010002" // Intentional concatenation
198 "4f0020f83e0a17cbdb18d2684dd2a9b087a43e5f3fa3fa27a049bc746a6e97a1e0244b00"
199 "0400010001",
200 &key));
201 EXPECT_THAT(ObliviousHttpKeyConfigs::ParseConcatenatedKeys(key).value(),
202 Property(&ObliviousHttpKeyConfigs::NumKeys, 2));
203 EXPECT_THAT(
204 ObliviousHttpKeyConfigs::ParseConcatenatedKeys(key)->PreferredConfig(),
205 AllOf(HasKeyId(0x4f), HasKemId(EVP_HPKE_DHKEM_X25519_HKDF_SHA256),
206 HasKdfId(EVP_HPKE_HKDF_SHA256), HasAeadId(EVP_HPKE_AES_128_GCM)));
207 }
208
TEST(ObliviousHttpKeyConfigs,RFCExample)209 TEST(ObliviousHttpKeyConfigs, RFCExample) {
210 std::string key;
211 ASSERT_TRUE(absl::HexStringToBytes(
212 "01002031e1f05a740102115220e9af918f738674aec95f54db6e04eb705aae8e79815500"
213 "080001000100010003",
214 &key));
215 auto configs = ObliviousHttpKeyConfigs::ParseConcatenatedKeys(key).value();
216 EXPECT_THAT(configs, Property(&ObliviousHttpKeyConfigs::NumKeys, 1));
217 EXPECT_THAT(
218 configs.PreferredConfig(),
219 AllOf(HasKeyId(0x01), HasKemId(EVP_HPKE_DHKEM_X25519_HKDF_SHA256),
220 HasKdfId(EVP_HPKE_HKDF_SHA256), HasAeadId(EVP_HPKE_AES_128_GCM)));
221 std::string expected_public_key;
222 ASSERT_TRUE(absl::HexStringToBytes(
223 "31e1f05a740102115220e9af918f738674aec95f54db6e04eb705aae8e798155",
224 &expected_public_key));
225 EXPECT_THAT(
226 configs.GetPublicKeyForId(configs.PreferredConfig().GetKeyId()).value(),
227 StrEq(expected_public_key));
228 }
229
TEST(ObliviousHttpKeyConfigs,DuplicateKeyId)230 TEST(ObliviousHttpKeyConfigs, DuplicateKeyId) {
231 std::string key;
232 ASSERT_TRUE(absl::HexStringToBytes(
233 "4b0020f83e0a17cbdb18d2684dd2a9b087a43e5f3fa3fa27a049bc746a6e97a1e0244b00"
234 "0400010002" // Intentional concatenation
235 "4b0020f83e0a17cbdb18d2684dd2a9b087a43e5f3fa3fb27a049bc746a6e97a1e0244b00"
236 "0400010001",
237 &key));
238 EXPECT_FALSE(ObliviousHttpKeyConfigs::ParseConcatenatedKeys(key).ok());
239 }
240
TEST(ObliviousHttpHeaderKeyConfigs,TestCreateWithSingleKeyConfig)241 TEST(ObliviousHttpHeaderKeyConfigs, TestCreateWithSingleKeyConfig) {
242 auto instance = ObliviousHttpHeaderKeyConfig::Create(
243 123, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
244 EVP_HPKE_CHACHA20_POLY1305);
245 EXPECT_TRUE(instance.ok());
246 std::string test_public_key(
247 EVP_HPKE_KEM_public_key_len(instance->GetHpkeKem()), 'a');
248 auto configs =
249 ObliviousHttpKeyConfigs::Create(instance.value(), test_public_key);
250 EXPECT_TRUE(configs.ok());
251 auto serialized_key = configs->GenerateConcatenatedKeys();
252 EXPECT_TRUE(serialized_key.ok());
253 auto ohttp_configs =
254 ObliviousHttpKeyConfigs::ParseConcatenatedKeys(serialized_key.value());
255 EXPECT_TRUE(ohttp_configs.ok());
256 ASSERT_EQ(ohttp_configs->PreferredConfig().GetKeyId(), 123);
257 auto parsed_public_key = ohttp_configs->GetPublicKeyForId(123);
258 EXPECT_TRUE(parsed_public_key.ok());
259 EXPECT_EQ(parsed_public_key.value(), test_public_key);
260 }
261
TEST(ObliviousHttpHeaderKeyConfigs,TestCreateWithWithMultipleKeys)262 TEST(ObliviousHttpHeaderKeyConfigs, TestCreateWithWithMultipleKeys) {
263 std::string expected_preferred_public_key(32, 'b');
264 ObliviousHttpKeyConfigs::OhttpKeyConfig config1 = {
265 100,
266 EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
267 std::string(32, 'a'),
268 {{EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM}}};
269 ObliviousHttpKeyConfigs::OhttpKeyConfig config2 = {
270 200,
271 EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
272 expected_preferred_public_key,
273 {{EVP_HPKE_HKDF_SHA256, EVP_HPKE_CHACHA20_POLY1305}}};
274 auto configs = ObliviousHttpKeyConfigs::Create({config1, config2});
275 EXPECT_TRUE(configs.ok());
276 auto serialized_key = configs->GenerateConcatenatedKeys();
277 EXPECT_TRUE(serialized_key.ok());
278 ASSERT_EQ(serialized_key.value(),
279 absl::StrCat(GetSerializedKeyConfig(config2),
280 GetSerializedKeyConfig(config1)));
281 auto ohttp_configs =
282 ObliviousHttpKeyConfigs::ParseConcatenatedKeys(serialized_key.value());
283 EXPECT_TRUE(ohttp_configs.ok());
284 ASSERT_EQ(ohttp_configs->NumKeys(), 2);
285 EXPECT_THAT(configs->PreferredConfig(),
286 AllOf(HasKeyId(200), HasKemId(EVP_HPKE_DHKEM_X25519_HKDF_SHA256),
287 HasKdfId(EVP_HPKE_HKDF_SHA256),
288 HasAeadId(EVP_HPKE_CHACHA20_POLY1305)));
289 auto parsed_preferred_public_key = ohttp_configs->GetPublicKeyForId(
290 ohttp_configs->PreferredConfig().GetKeyId());
291 EXPECT_TRUE(parsed_preferred_public_key.ok());
292 EXPECT_EQ(parsed_preferred_public_key.value(), expected_preferred_public_key);
293 }
294
TEST(ObliviousHttpHeaderKeyConfigs,TestCreateWithInvalidConfigs)295 TEST(ObliviousHttpHeaderKeyConfigs, TestCreateWithInvalidConfigs) {
296 ASSERT_EQ(ObliviousHttpKeyConfigs::Create({}).status().code(),
297 absl::StatusCode::kInvalidArgument);
298 ASSERT_EQ(ObliviousHttpKeyConfigs::Create(
299 {{100, 2, std::string(32, 'a'), {{2, 3}, {4, 5}}},
300 {200, 6, std::string(32, 'b'), {{7, 8}, {9, 10}}}})
301 .status()
302 .code(),
303 absl::StatusCode::kInvalidArgument);
304
305 EXPECT_EQ(
306 ObliviousHttpKeyConfigs::Create(
307 {{123,
308 EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
309 "invalid key length" /*expected length for given kem_id is 32*/,
310 {{EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_128_GCM}}}})
311 .status()
312 .code(),
313 absl::StatusCode::kInvalidArgument);
314 }
315
TEST(ObliviousHttpHeaderKeyConfigs,TestCreateSingleKeyConfigWithInvalidConfig)316 TEST(ObliviousHttpHeaderKeyConfigs,
317 TestCreateSingleKeyConfigWithInvalidConfig) {
318 const auto sample_ohttp_hdr_config = ObliviousHttpHeaderKeyConfig::Create(
319 123, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
320 EVP_HPKE_AES_128_GCM);
321 ASSERT_TRUE(sample_ohttp_hdr_config.ok());
322 ASSERT_EQ(ObliviousHttpKeyConfigs::Create(sample_ohttp_hdr_config.value(),
323 "" /*empty public_key*/)
324 .status()
325 .code(),
326 absl::StatusCode::kInvalidArgument);
327 EXPECT_EQ(ObliviousHttpKeyConfigs::Create(
328 sample_ohttp_hdr_config.value(),
329 "invalid key length" /*expected length for given kem_id is 32*/)
330 .status()
331 .code(),
332 absl::StatusCode::kInvalidArgument);
333 }
334
TEST(ObliviousHttpHeaderKeyConfigs,TestHashImplWithObliviousStruct)335 TEST(ObliviousHttpHeaderKeyConfigs, TestHashImplWithObliviousStruct) {
336 // Insert different symmetric algorithms 50 times.
337 absl::flat_hash_set<ObliviousHttpKeyConfigs::SymmetricAlgorithmsConfig>
338 symmetric_algs_set;
339 for (int i = 0; i < 50; ++i) {
340 symmetric_algs_set.insert({EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_128_GCM});
341 symmetric_algs_set.insert({EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM});
342 symmetric_algs_set.insert(
343 {EVP_HPKE_HKDF_SHA256, EVP_HPKE_CHACHA20_POLY1305});
344 }
345 ASSERT_EQ(symmetric_algs_set.size(), 3);
346 EXPECT_THAT(symmetric_algs_set,
347 UnorderedElementsAreArray<
348 ObliviousHttpKeyConfigs::SymmetricAlgorithmsConfig>({
349 {EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_128_GCM},
350 {EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM},
351 {EVP_HPKE_HKDF_SHA256, EVP_HPKE_CHACHA20_POLY1305},
352 }));
353
354 // Insert different Key configs 50 times.
355 absl::flat_hash_set<ObliviousHttpKeyConfigs::OhttpKeyConfig>
356 ohttp_key_configs_set;
357 ObliviousHttpKeyConfigs::OhttpKeyConfig expected_key_config{
358 100,
359 EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
360 std::string(32, 'c'),
361 {{EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_128_GCM},
362 {EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM}}};
363 for (int i = 0; i < 50; ++i) {
364 ohttp_key_configs_set.insert(expected_key_config);
365 }
366 ASSERT_EQ(ohttp_key_configs_set.size(), 1);
367 EXPECT_THAT(ohttp_key_configs_set, UnorderedElementsAre(expected_key_config));
368 }
369
370 } // namespace
371 } // namespace quiche
372