1 /* Copyright (c) 2020, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <cstdint>
16 #include <limits>
17 #include <string>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <openssl/base.h>
23 #include <openssl/curve25519.h>
24 #include <openssl/digest.h>
25 #include <openssl/err.h>
26 #include <openssl/evp.h>
27 #include <openssl/sha.h>
28 #include <openssl/span.h>
29
30 #include "../test/file_test.h"
31 #include "../test/test_util.h"
32 #include "internal.h"
33
34
35 namespace bssl {
36 namespace {
37
38 enum class HPKEMode {
39 kBase = 0,
40 kPSK = 1,
41 };
42
43 // HPKETestVector corresponds to one array member in the published
44 // test-vectors.json.
45 class HPKETestVector {
46 public:
47 explicit HPKETestVector() = default;
48 ~HPKETestVector() = default;
49
50 bool ReadFromFileTest(FileTest *t);
51
Verify() const52 void Verify() const {
53 ScopedEVP_HPKE_CTX sender_ctx;
54 ScopedEVP_HPKE_CTX receiver_ctx;
55
56 switch (mode_) {
57 case HPKEMode::kBase:
58 ASSERT_GT(secret_key_e_.size(), 0u);
59 ASSERT_EQ(psk_.size(), 0u);
60 ASSERT_EQ(psk_id_.size(), 0u);
61
62 // Set up the sender.
63 ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_for_test(
64 sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
65 info_.data(), info_.size(), secret_key_e_.data(),
66 public_key_e_.data()));
67
68 // Set up the receiver.
69 ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
70 receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
71 public_key_r_.data(), secret_key_r_.data(), info_.data(),
72 info_.size()));
73 break;
74
75 case HPKEMode::kPSK:
76 ASSERT_GT(secret_key_e_.size(), 0u);
77 ASSERT_GT(psk_.size(), 0u);
78 ASSERT_GT(psk_id_.size(), 0u);
79
80 // Set up the sender.
81 ASSERT_TRUE(EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
82 sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
83 info_.data(), info_.size(), psk_.data(), psk_.size(),
84 psk_id_.data(), psk_id_.size(), secret_key_e_.data(),
85 public_key_e_.data()));
86
87 // Set up the receiver.
88 ASSERT_TRUE(EVP_HPKE_CTX_setup_psk_r_x25519(
89 receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
90 public_key_r_.data(), secret_key_r_.data(), info_.data(),
91 info_.size(), psk_.data(), psk_.size(), psk_id_.data(),
92 psk_id_.size()));
93 break;
94 default:
95 FAIL() << "Unsupported mode";
96 return;
97 }
98
99 VerifyEncryptions(sender_ctx.get(), receiver_ctx.get());
100 VerifyExports(sender_ctx.get());
101 VerifyExports(receiver_ctx.get());
102 }
103
104 private:
VerifyEncryptions(EVP_HPKE_CTX * sender_ctx,EVP_HPKE_CTX * receiver_ctx) const105 void VerifyEncryptions(EVP_HPKE_CTX *sender_ctx,
106 EVP_HPKE_CTX *receiver_ctx) const {
107 for (const Encryption &task : encryptions_) {
108 std::vector<uint8_t> encrypted(task.plaintext.size() +
109 EVP_HPKE_CTX_max_overhead(sender_ctx));
110 size_t encrypted_len;
111 ASSERT_TRUE(EVP_HPKE_CTX_seal(
112 sender_ctx, encrypted.data(), &encrypted_len, encrypted.size(),
113 task.plaintext.data(), task.plaintext.size(), task.aad.data(),
114 task.aad.size()));
115
116 ASSERT_EQ(Bytes(encrypted.data(), encrypted_len), Bytes(task.ciphertext));
117
118 std::vector<uint8_t> decrypted(task.ciphertext.size());
119 size_t decrypted_len;
120 ASSERT_TRUE(EVP_HPKE_CTX_open(
121 receiver_ctx, decrypted.data(), &decrypted_len, decrypted.size(),
122 task.ciphertext.data(), task.ciphertext.size(), task.aad.data(),
123 task.aad.size()));
124
125 ASSERT_EQ(Bytes(decrypted.data(), decrypted_len), Bytes(task.plaintext));
126 }
127 }
128
VerifyExports(EVP_HPKE_CTX * ctx) const129 void VerifyExports(EVP_HPKE_CTX *ctx) const {
130 for (const Export &task : exports_) {
131 std::vector<uint8_t> exported_secret(task.export_length);
132
133 ASSERT_TRUE(EVP_HPKE_CTX_export(
134 ctx, exported_secret.data(), exported_secret.size(),
135 task.exporter_context.data(), task.exporter_context.size()));
136 ASSERT_EQ(Bytes(exported_secret), Bytes(task.exported_value));
137 }
138 }
139
140 struct Encryption {
141 std::vector<uint8_t> aad;
142 std::vector<uint8_t> ciphertext;
143 std::vector<uint8_t> plaintext;
144 };
145
146 struct Export {
147 std::vector<uint8_t> exporter_context;
148 size_t export_length;
149 std::vector<uint8_t> exported_value;
150 };
151
152 HPKEMode mode_;
153 uint16_t kdf_id_;
154 uint16_t aead_id_;
155 std::vector<uint8_t> context_;
156 std::vector<uint8_t> info_;
157 std::vector<uint8_t> public_key_e_;
158 std::vector<uint8_t> secret_key_e_;
159 std::vector<uint8_t> public_key_r_;
160 std::vector<uint8_t> secret_key_r_;
161 std::vector<Encryption> encryptions_;
162 std::vector<Export> exports_;
163 std::vector<uint8_t> psk_; // Empty when mode is not PSK.
164 std::vector<uint8_t> psk_id_; // Empty when mode is not PSK.
165 };
166
167 // Match FileTest's naming scheme for duplicated attribute names.
BuildAttrName(const std::string & name,int iter)168 std::string BuildAttrName(const std::string &name, int iter) {
169 return iter == 1 ? name : name + "/" + std::to_string(iter);
170 }
171
172 // Parses |s| as an unsigned integer of type T and writes the value to |out|.
173 // Returns true on success. If the integer value exceeds the maximum T value,
174 // returns false.
175 template <typename T>
ParseIntSafe(T * out,const std::string & s)176 bool ParseIntSafe(T *out, const std::string &s) {
177 T value = 0;
178 for (char c : s) {
179 if (c < '0' || c > '9') {
180 return false;
181 }
182 if (value > (std::numeric_limits<T>::max() - (c - '0')) / 10) {
183 return false;
184 }
185 value = 10 * value + (c - '0');
186 }
187 *out = value;
188 return true;
189 }
190
191 // Read the |key| attribute from |file_test| and convert it to an integer.
192 template <typename T>
FileTestReadInt(FileTest * file_test,T * out,const std::string & key)193 bool FileTestReadInt(FileTest *file_test, T *out, const std::string &key) {
194 std::string s;
195 return file_test->GetAttribute(&s, key) && ParseIntSafe(out, s);
196 }
197
198
ReadFromFileTest(FileTest * t)199 bool HPKETestVector::ReadFromFileTest(FileTest *t) {
200 uint8_t mode_tmp;
201 if (!FileTestReadInt(t, &mode_tmp, "mode")) {
202 return false;
203 }
204 mode_ = static_cast<HPKEMode>(mode_tmp);
205
206 if (!FileTestReadInt(t, &kdf_id_, "kdf_id") ||
207 !FileTestReadInt(t, &aead_id_, "aead_id") ||
208 !t->GetBytes(&info_, "info") ||
209 !t->GetBytes(&secret_key_r_, "skRm") ||
210 !t->GetBytes(&public_key_r_, "pkRm") ||
211 !t->GetBytes(&secret_key_e_, "skEm") ||
212 !t->GetBytes(&public_key_e_, "pkEm")) {
213 return false;
214 }
215
216 if (mode_ == HPKEMode::kPSK) {
217 if (!t->GetBytes(&psk_, "psk") ||
218 !t->GetBytes(&psk_id_, "psk_id")) {
219 return false;
220 }
221 }
222
223 for (int i = 1; t->HasAttribute(BuildAttrName("aad", i)); i++) {
224 Encryption encryption;
225 if (!t->GetBytes(&encryption.aad, BuildAttrName("aad", i)) ||
226 !t->GetBytes(&encryption.ciphertext, BuildAttrName("ciphertext", i)) ||
227 !t->GetBytes(&encryption.plaintext, BuildAttrName("plaintext", i))) {
228 return false;
229 }
230 encryptions_.push_back(std::move(encryption));
231 }
232
233 for (int i = 1; t->HasAttribute(BuildAttrName("exporter_context", i)); i++) {
234 Export exp;
235 if (!t->GetBytes(&exp.exporter_context,
236 BuildAttrName("exporter_context", i)) ||
237 !FileTestReadInt(t, &exp.export_length, BuildAttrName("L", i)) ||
238 !t->GetBytes(&exp.exported_value, BuildAttrName("exported_value", i))) {
239 return false;
240 }
241 exports_.push_back(std::move(exp));
242 }
243 return true;
244 }
245
246 } // namespace
247
TEST(HPKETest,VerifyTestVectors)248 TEST(HPKETest, VerifyTestVectors) {
249 FileTestGTest("crypto/hpke/hpke_test_vectors.txt", [](FileTest *t) {
250 HPKETestVector test_vec;
251 EXPECT_TRUE(test_vec.ReadFromFileTest(t));
252 test_vec.Verify();
253 });
254 }
255
256 // The test vectors used fixed sender ephemeral keys, while HPKE itself
257 // generates new keys for each context. Test this codepath by checking we can
258 // decrypt our own messages.
TEST(HPKETest,RoundTrip)259 TEST(HPKETest, RoundTrip) {
260 uint16_t kdf_ids[] = {EVP_HPKE_HKDF_SHA256, EVP_HPKE_HKDF_SHA384,
261 EVP_HPKE_HKDF_SHA512};
262 uint16_t aead_ids[] = {EVP_HPKE_AEAD_AES_GCM_128, EVP_HPKE_AEAD_AES_GCM_256,
263 EVP_HPKE_AEAD_CHACHA20POLY1305};
264
265 const uint8_t info_a[] = {1, 1, 2, 3, 5, 8};
266 const uint8_t info_b[] = {42, 42, 42};
267 const uint8_t ad_a[] = {1, 2, 4, 8, 16};
268 const uint8_t ad_b[] = {7};
269 Span<const uint8_t> info_values[] = {{nullptr, 0}, info_a, info_b};
270 Span<const uint8_t> ad_values[] = {{nullptr, 0}, ad_a, ad_b};
271
272 // Generate the receiver's keypair.
273 uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
274 uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
275 X25519_keypair(public_key_r, secret_key_r);
276
277 for (uint16_t kdf_id : kdf_ids) {
278 for (uint16_t aead_id : aead_ids) {
279 for (const Span<const uint8_t> &info : info_values) {
280 for (const Span<const uint8_t> &ad : ad_values) {
281 // Set up the sender.
282 ScopedEVP_HPKE_CTX sender_ctx;
283 uint8_t enc[X25519_PUBLIC_VALUE_LEN];
284 ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519(
285 sender_ctx.get(), enc, kdf_id, aead_id, public_key_r, info.data(),
286 info.size()));
287
288 // Set up the receiver.
289 ScopedEVP_HPKE_CTX receiver_ctx;
290 ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
291 receiver_ctx.get(), kdf_id, aead_id, enc, public_key_r,
292 secret_key_r, info.data(), info.size()));
293
294 const char kCleartextPayload[] = "foobar";
295
296 // Have sender encrypt message for the receiver.
297 std::vector<uint8_t> ciphertext(
298 sizeof(kCleartextPayload) +
299 EVP_HPKE_CTX_max_overhead(sender_ctx.get()));
300 size_t ciphertext_len;
301 ASSERT_TRUE(EVP_HPKE_CTX_seal(
302 sender_ctx.get(), ciphertext.data(), &ciphertext_len,
303 ciphertext.size(),
304 reinterpret_cast<const uint8_t *>(kCleartextPayload),
305 sizeof(kCleartextPayload), ad.data(), ad.size()));
306
307 // Have receiver decrypt the message.
308 std::vector<uint8_t> cleartext(ciphertext.size());
309 size_t cleartext_len;
310 ASSERT_TRUE(EVP_HPKE_CTX_open(receiver_ctx.get(), cleartext.data(),
311 &cleartext_len, cleartext.size(),
312 ciphertext.data(), ciphertext_len,
313 ad.data(), ad.size()));
314
315 // Verify that decrypted message matches the original.
316 ASSERT_EQ(Bytes(cleartext.data(), cleartext_len),
317 Bytes(kCleartextPayload, sizeof(kCleartextPayload)));
318 }
319 }
320 }
321 }
322 }
323
324 // Verify that the DH operations inside Encap() and Decap() both fail when the
325 // public key is on a small-order point in the curve.
TEST(HPKETest,X25519EncapSmallOrderPoint)326 TEST(HPKETest, X25519EncapSmallOrderPoint) {
327 // Borrowed from X25519Test.SmallOrder.
328 static const uint8_t kSmallOrderPoint[32] = {
329 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3,
330 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32,
331 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8,
332 };
333
334 // Generate a valid keypair for the receiver.
335 uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
336 uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
337 X25519_keypair(public_key_r, secret_key_r);
338
339 uint16_t kdf_ids[] = {EVP_HPKE_HKDF_SHA256, EVP_HPKE_HKDF_SHA384,
340 EVP_HPKE_HKDF_SHA512};
341 uint16_t aead_ids[] = {EVP_HPKE_AEAD_AES_GCM_128, EVP_HPKE_AEAD_AES_GCM_256,
342 EVP_HPKE_AEAD_CHACHA20POLY1305};
343
344 for (uint16_t kdf_id : kdf_ids) {
345 for (uint16_t aead_id : aead_ids) {
346 // Set up the sender, passing in kSmallOrderPoint as |peer_public_value|.
347 ScopedEVP_HPKE_CTX sender_ctx;
348 uint8_t enc[X25519_PUBLIC_VALUE_LEN];
349 ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519(
350 sender_ctx.get(), enc, kdf_id, aead_id, kSmallOrderPoint, nullptr,
351 0));
352
353 // Set up the receiver, passing in kSmallOrderPoint as |enc|.
354 ScopedEVP_HPKE_CTX receiver_ctx;
355 ASSERT_FALSE(EVP_HPKE_CTX_setup_base_r_x25519(
356 receiver_ctx.get(), kdf_id, aead_id, kSmallOrderPoint, public_key_r,
357 secret_key_r, nullptr, 0));
358 }
359 }
360 }
361
362 // Test that Seal() fails when the context has been initialized as a receiver.
TEST(HPKETest,ReceiverInvalidSeal)363 TEST(HPKETest, ReceiverInvalidSeal) {
364 const uint8_t kMockEnc[X25519_PUBLIC_VALUE_LEN] = {0xff};
365 const char kCleartextPayload[] = "foobar";
366
367 // Generate the receiver's keypair.
368 uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
369 uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
370 X25519_keypair(public_key_r, secret_key_r);
371
372 // Set up the receiver.
373 ScopedEVP_HPKE_CTX receiver_ctx;
374 ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
375 receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
376 kMockEnc, public_key_r, secret_key_r, nullptr, 0));
377
378 // Call Seal() on the receiver.
379 size_t ciphertext_len;
380 uint8_t ciphertext[100];
381 ASSERT_FALSE(EVP_HPKE_CTX_seal(
382 receiver_ctx.get(), ciphertext, &ciphertext_len, sizeof(ciphertext),
383 reinterpret_cast<const uint8_t *>(kCleartextPayload),
384 sizeof(kCleartextPayload), nullptr, 0));
385 }
386
387 // Test that Open() fails when the context has been initialized as a sender.
TEST(HPKETest,SenderInvalidOpen)388 TEST(HPKETest, SenderInvalidOpen) {
389 const uint8_t kMockCiphertext[100] = {0xff};
390 const size_t kMockCiphertextLen = 80;
391
392 // Generate the receiver's keypair.
393 uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
394 uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
395 X25519_keypair(public_key_r, secret_key_r);
396
397 // Set up the sender.
398 ScopedEVP_HPKE_CTX sender_ctx;
399 uint8_t enc[X25519_PUBLIC_VALUE_LEN];
400 ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519(
401 sender_ctx.get(), enc, EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
402 public_key_r, nullptr, 0));
403
404 // Call Open() on the sender.
405 uint8_t cleartext[128];
406 size_t cleartext_len;
407 ASSERT_FALSE(EVP_HPKE_CTX_open(sender_ctx.get(), cleartext, &cleartext_len,
408 sizeof(cleartext), kMockCiphertext,
409 kMockCiphertextLen, nullptr, 0));
410 }
411
412 // Test that the PSK variants of Setup functions fail when any of the PSK inputs
413 // are empty.
TEST(HPKETest,EmptyPSK)414 TEST(HPKETest, EmptyPSK) {
415 const uint8_t kMockEnc[X25519_PUBLIC_VALUE_LEN] = {0xff};
416 const std::vector<uint8_t> kPSKValues[] = {std::vector<uint8_t>(100, 0xff),
417 {}};
418
419 // Generate the receiver's keypair.
420 uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
421 uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
422 X25519_keypair(public_key_r, secret_key_r);
423
424 // Vary the PSK and PSKID inputs for the sender and receiver, trying all four
425 // permutations of empty and nonempty inputs.
426
427 for (const auto &psk : kPSKValues) {
428 for (const auto &psk_id : kPSKValues) {
429 const bool kExpectSuccess = psk.size() > 0 && psk_id.size() > 0;
430
431 ASSERT_EQ(ERR_get_error(), 0u);
432
433 ScopedEVP_HPKE_CTX sender_ctx;
434 uint8_t enc[X25519_PUBLIC_VALUE_LEN];
435 ASSERT_EQ(EVP_HPKE_CTX_setup_psk_s_x25519(
436 sender_ctx.get(), enc, EVP_HPKE_HKDF_SHA256,
437 EVP_HPKE_AEAD_AES_GCM_128, public_key_r, nullptr, 0,
438 psk.data(), psk.size(), psk_id.data(), psk_id.size()),
439 kExpectSuccess);
440
441 if (!kExpectSuccess) {
442 uint32_t err = ERR_get_error();
443 EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
444 EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
445 }
446 ERR_clear_error();
447
448 ScopedEVP_HPKE_CTX receiver_ctx;
449 ASSERT_EQ(
450 EVP_HPKE_CTX_setup_psk_r_x25519(
451 receiver_ctx.get(), EVP_HPKE_HKDF_SHA256,
452 EVP_HPKE_AEAD_AES_GCM_128, kMockEnc, public_key_r, secret_key_r,
453 nullptr, 0, psk.data(), psk.size(), psk_id.data(), psk_id.size()),
454 kExpectSuccess);
455
456 if (!kExpectSuccess) {
457 uint32_t err = ERR_get_error();
458 EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
459 EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
460 }
461 ERR_clear_error();
462 }
463 }
464 }
465
TEST(HPKETest,InternalParseIntSafe)466 TEST(HPKETest, InternalParseIntSafe) {
467 uint8_t u8 = 0xff;
468 ASSERT_FALSE(ParseIntSafe(&u8, "-1"));
469
470 ASSERT_TRUE(ParseIntSafe(&u8, "0"));
471 ASSERT_EQ(u8, 0);
472
473 ASSERT_TRUE(ParseIntSafe(&u8, "255"));
474 ASSERT_EQ(u8, 255);
475
476 ASSERT_FALSE(ParseIntSafe(&u8, "256"));
477
478 uint16_t u16 = 0xffff;
479 ASSERT_TRUE(ParseIntSafe(&u16, "257"));
480 ASSERT_EQ(u16, 257);
481
482 ASSERT_TRUE(ParseIntSafe(&u16, "65535"));
483 ASSERT_EQ(u16, 65535);
484
485 ASSERT_FALSE(ParseIntSafe(&u16, "65536"));
486 }
487
488
489 } // namespace bssl
490