1 #include "quiche/oblivious_http/buffers/oblivious_http_response.h"
2
3 #include <stddef.h>
4 #include <stdint.h>
5 #include <string.h>
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
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/hpke.h"
16 #include "quiche/common/platform/api/quiche_test.h"
17 #include "quiche/oblivious_http/buffers/oblivious_http_request.h"
18 #include "quiche/oblivious_http/common/oblivious_http_header_key_config.h"
19
20 namespace quiche {
21
22 namespace {
GetHpkePrivateKey()23 std::string GetHpkePrivateKey() {
24 absl::string_view hpke_key_hex =
25 "b77431ecfa8f4cfc30d6e467aafa06944dffe28cb9dd1409e33a3045f5adc8a1";
26 std::string hpke_key_bytes;
27 EXPECT_TRUE(absl::HexStringToBytes(hpke_key_hex, &hpke_key_bytes));
28 return hpke_key_bytes;
29 }
30
GetHpkePublicKey()31 std::string GetHpkePublicKey() {
32 absl::string_view public_key =
33 "6d21cfe09fbea5122f9ebc2eb2a69fcc4f06408cd54aac934f012e76fcdcef62";
34 std::string public_key_bytes;
35 EXPECT_TRUE(absl::HexStringToBytes(public_key, &public_key_bytes));
36 return public_key_bytes;
37 }
38
GetSeed()39 std::string GetSeed() {
40 absl::string_view seed =
41 "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736";
42 std::string seed_bytes;
43 EXPECT_TRUE(absl::HexStringToBytes(seed, &seed_bytes));
44 return seed_bytes;
45 }
46
GetSeededEncapsulatedKey()47 std::string GetSeededEncapsulatedKey() {
48 absl::string_view encapsulated_key =
49 "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431";
50 std::string encapsulated_key_bytes;
51 EXPECT_TRUE(
52 absl::HexStringToBytes(encapsulated_key, &encapsulated_key_bytes));
53 return encapsulated_key_bytes;
54 }
55
GetOhttpKeyConfig(uint8_t key_id,uint16_t kem_id,uint16_t kdf_id,uint16_t aead_id)56 const ObliviousHttpHeaderKeyConfig GetOhttpKeyConfig(uint8_t key_id,
57 uint16_t kem_id,
58 uint16_t kdf_id,
59 uint16_t aead_id) {
60 auto ohttp_key_config =
61 ObliviousHttpHeaderKeyConfig::Create(key_id, kem_id, kdf_id, aead_id);
62 EXPECT_TRUE(ohttp_key_config.ok());
63 return ohttp_key_config.value();
64 }
65
GetSeededClientContext(uint8_t key_id,uint16_t kem_id,uint16_t kdf_id,uint16_t aead_id)66 bssl::UniquePtr<EVP_HPKE_CTX> GetSeededClientContext(uint8_t key_id,
67 uint16_t kem_id,
68 uint16_t kdf_id,
69 uint16_t aead_id) {
70 bssl::UniquePtr<EVP_HPKE_CTX> client_ctx(EVP_HPKE_CTX_new());
71 std::string encapsulated_key(EVP_HPKE_MAX_ENC_LENGTH, '\0');
72 size_t enc_len;
73 std::string info = GetOhttpKeyConfig(key_id, kem_id, kdf_id, aead_id)
74 .SerializeRecipientContextInfo();
75
76 EXPECT_TRUE(EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
77 client_ctx.get(), reinterpret_cast<uint8_t *>(encapsulated_key.data()),
78 &enc_len, encapsulated_key.size(), EVP_hpke_x25519_hkdf_sha256(),
79 EVP_hpke_hkdf_sha256(), EVP_hpke_aes_256_gcm(),
80 reinterpret_cast<const uint8_t *>(GetHpkePublicKey().data()),
81 GetHpkePublicKey().size(), reinterpret_cast<const uint8_t *>(info.data()),
82 info.size(), reinterpret_cast<const uint8_t *>(GetSeed().data()),
83 GetSeed().size()));
84 encapsulated_key.resize(enc_len);
85 EXPECT_EQ(encapsulated_key, GetSeededEncapsulatedKey());
86 return client_ctx;
87 }
88
ConstructHpkeKey(absl::string_view hpke_key,const ObliviousHttpHeaderKeyConfig & ohttp_key_config)89 bssl::UniquePtr<EVP_HPKE_KEY> ConstructHpkeKey(
90 absl::string_view hpke_key,
91 const ObliviousHttpHeaderKeyConfig &ohttp_key_config) {
92 bssl::UniquePtr<EVP_HPKE_KEY> bssl_hpke_key(EVP_HPKE_KEY_new());
93 EXPECT_NE(bssl_hpke_key, nullptr);
94 EXPECT_TRUE(EVP_HPKE_KEY_init(
95 bssl_hpke_key.get(), ohttp_key_config.GetHpkeKem(),
96 reinterpret_cast<const uint8_t *>(hpke_key.data()), hpke_key.size()));
97 return bssl_hpke_key;
98 }
99
SetUpObliviousHttpContext(uint8_t key_id,uint16_t kem_id,uint16_t kdf_id,uint16_t aead_id,std::string plaintext)100 ObliviousHttpRequest SetUpObliviousHttpContext(uint8_t key_id, uint16_t kem_id,
101 uint16_t kdf_id,
102 uint16_t aead_id,
103 std::string plaintext) {
104 auto ohttp_key_config = GetOhttpKeyConfig(key_id, kem_id, kdf_id, aead_id);
105 auto client_request_encapsulate =
106 ObliviousHttpRequest::CreateClientWithSeedForTesting(
107 std::move(plaintext), GetHpkePublicKey(), ohttp_key_config,
108 GetSeed());
109 EXPECT_TRUE(client_request_encapsulate.ok());
110 auto oblivious_request =
111 client_request_encapsulate->EncapsulateAndSerialize();
112 auto server_request_decapsulate =
113 ObliviousHttpRequest::CreateServerObliviousRequest(
114 oblivious_request,
115 *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
116 ohttp_key_config);
117 EXPECT_TRUE(server_request_decapsulate.ok());
118 return std::move(server_request_decapsulate.value());
119 }
120
121 // QuicheRandom implementation.
122 // Just fills the buffer with repeated chars that's initialized in seed.
123 class TestQuicheRandom : public QuicheRandom {
124 public:
TestQuicheRandom(char seed)125 TestQuicheRandom(char seed) : seed_(seed) {}
~TestQuicheRandom()126 ~TestQuicheRandom() override {}
127
RandBytes(void * data,size_t len)128 void RandBytes(void *data, size_t len) override { memset(data, seed_, len); }
129
RandUint64()130 uint64_t RandUint64() override {
131 uint64_t random_int;
132 memset(&random_int, seed_, sizeof(random_int));
133 return random_int;
134 }
135
InsecureRandBytes(void * data,size_t len)136 void InsecureRandBytes(void *data, size_t len) override {
137 return RandBytes(data, len);
138 }
InsecureRandUint64()139 uint64_t InsecureRandUint64() override { return RandUint64(); }
140
141 private:
142 char seed_;
143 };
144
GetResponseNonceLength(const EVP_HPKE_CTX & hpke_context)145 size_t GetResponseNonceLength(const EVP_HPKE_CTX &hpke_context) {
146 EXPECT_NE(&hpke_context, nullptr);
147 const EVP_AEAD *evp_hpke_aead =
148 EVP_HPKE_AEAD_aead(EVP_HPKE_CTX_aead(&hpke_context));
149 EXPECT_NE(evp_hpke_aead, nullptr);
150 // Nk = [AEAD key len], is determined by BSSL.
151 const size_t aead_key_len = EVP_AEAD_key_length(evp_hpke_aead);
152 // Nn = [AEAD nonce len], is determined by BSSL.
153 const size_t aead_nonce_len = EVP_AEAD_nonce_length(evp_hpke_aead);
154 const size_t secret_len = std::max(aead_key_len, aead_nonce_len);
155 return secret_len;
156 }
157
TEST(ObliviousHttpResponse,TestDecapsulateReceivedResponse)158 TEST(ObliviousHttpResponse, TestDecapsulateReceivedResponse) {
159 // Construct encrypted payload with plaintext: "test response"
160 absl::string_view encrypted_response =
161 "39d5b03c02c97e216df444e4681007105974d4df1585aae05e7b53f3ccdb55d51f711d48"
162 "eeefbc1a555d6d928e35df33fd23c23846fa7b083e30692f7b";
163 std::string encrypted_response_bytes;
164 ASSERT_TRUE(
165 absl::HexStringToBytes(encrypted_response, &encrypted_response_bytes));
166 auto oblivious_context =
167 SetUpObliviousHttpContext(4, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
168 EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM,
169 "test")
170 .ReleaseContext();
171 auto decapsulated = ObliviousHttpResponse::CreateClientObliviousResponse(
172 std::move(encrypted_response_bytes), oblivious_context);
173 EXPECT_TRUE(decapsulated.ok());
174 auto decrypted = decapsulated->GetPlaintextData();
175 EXPECT_EQ(decrypted, "test response");
176 }
177 } // namespace
178
TEST(ObliviousHttpResponse,EndToEndTestForResponse)179 TEST(ObliviousHttpResponse, EndToEndTestForResponse) {
180 auto oblivious_ctx = ObliviousHttpRequest::Context(
181 GetSeededClientContext(5, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
182 EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM),
183 GetSeededEncapsulatedKey());
184 auto server_response_encapsulate =
185 ObliviousHttpResponse::CreateServerObliviousResponse("test response",
186 oblivious_ctx);
187 EXPECT_TRUE(server_response_encapsulate.ok());
188 auto oblivious_response =
189 server_response_encapsulate->EncapsulateAndSerialize();
190 auto client_response_encapsulate =
191 ObliviousHttpResponse::CreateClientObliviousResponse(oblivious_response,
192 oblivious_ctx);
193 auto decrypted = client_response_encapsulate->GetPlaintextData();
194 EXPECT_EQ(decrypted, "test response");
195 }
196
TEST(ObliviousHttpResponse,TestEncapsulateWithQuicheRandom)197 TEST(ObliviousHttpResponse, TestEncapsulateWithQuicheRandom) {
198 auto random = TestQuicheRandom('z');
199 auto server_seeded_request = SetUpObliviousHttpContext(
200 6, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
201 EVP_HPKE_AES_256_GCM, "test");
202 auto server_request_context =
203 std::move(server_seeded_request).ReleaseContext();
204 auto server_response_encapsulate =
205 ObliviousHttpResponse::CreateServerObliviousResponse(
206 "test response", server_request_context,
207 ObliviousHttpHeaderKeyConfig::kOhttpResponseLabel, &random);
208 EXPECT_TRUE(server_response_encapsulate.ok());
209 std::string response_nonce =
210 server_response_encapsulate->EncapsulateAndSerialize().substr(
211 0, GetResponseNonceLength(*(server_request_context.hpke_context_)));
212 EXPECT_EQ(response_nonce,
213 std::string(
214 GetResponseNonceLength(*(server_request_context.hpke_context_)),
215 'z'));
216 absl::string_view expected_encrypted_response =
217 "2a3271ac4e6a501f51d0264d3dd7d0bc8a06973b58e89c26d6dac06144";
218 std::string expected_encrypted_response_bytes;
219 ASSERT_TRUE(absl::HexStringToBytes(expected_encrypted_response,
220 &expected_encrypted_response_bytes));
221 EXPECT_EQ(
222 server_response_encapsulate->EncapsulateAndSerialize().substr(
223 GetResponseNonceLength(*(server_request_context.hpke_context_))),
224 expected_encrypted_response_bytes);
225 }
226
227 } // namespace quiche
228