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