1 /* Copyright (c) 2014, 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 <stdint.h>
16 #include <string.h>
17
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <openssl/aead.h>
23 #include <openssl/cipher.h>
24 #include <openssl/err.h>
25
26 #include "../fipsmodule/cipher/internal.h"
27 #include "../internal.h"
28 #include "../test/file_test.h"
29 #include "../test/test_util.h"
30 #include "../test/wycheproof_util.h"
31
32
33 struct KnownAEAD {
34 const char name[40];
35 const EVP_AEAD *(*func)(void);
36 const char *test_vectors;
37 // limited_implementation indicates that tests that assume a generic AEAD
38 // interface should not be performed. For example, the key-wrap AEADs only
39 // handle inputs that are a multiple of eight bytes in length and the TLS CBC
40 // AEADs have the concept of “direction”.
41 bool limited_implementation;
42 // truncated_tags is true if the AEAD supports truncating tags to arbitrary
43 // lengths.
44 bool truncated_tags;
45 // variable_nonce is true if the AEAD supports a variable nonce length.
46 bool variable_nonce;
47 // ad_len, if non-zero, is the required length of the AD.
48 size_t ad_len;
49 };
50
51 static const struct KnownAEAD kAEADs[] = {
52 {"AES_128_GCM", EVP_aead_aes_128_gcm, "aes_128_gcm_tests.txt", false, true,
53 true, 0},
54 {"AES_128_GCM_NIST", EVP_aead_aes_128_gcm, "nist_cavp/aes_128_gcm.txt",
55 false, true, true, 0},
56 {"AES_192_GCM", EVP_aead_aes_192_gcm, "aes_192_gcm_tests.txt", false, true,
57 true, 0},
58 {"AES_256_GCM", EVP_aead_aes_256_gcm, "aes_256_gcm_tests.txt", false, true,
59 true, 0},
60 {"AES_256_GCM_NIST", EVP_aead_aes_256_gcm, "nist_cavp/aes_256_gcm.txt",
61 false, true, true, 0},
62 {"AES_128_GCM_SIV", EVP_aead_aes_128_gcm_siv, "aes_128_gcm_siv_tests.txt",
63 false, false, false, 0},
64 {"AES_256_GCM_SIV", EVP_aead_aes_256_gcm_siv, "aes_256_gcm_siv_tests.txt",
65 false, false, false, 0},
66 {"ChaCha20Poly1305", EVP_aead_chacha20_poly1305,
67 "chacha20_poly1305_tests.txt", false, true, false, 0},
68 {"XChaCha20Poly1305", EVP_aead_xchacha20_poly1305,
69 "xchacha20_poly1305_tests.txt", false, true, false, 0},
70 {"AES_128_CBC_SHA1_TLS", EVP_aead_aes_128_cbc_sha1_tls,
71 "aes_128_cbc_sha1_tls_tests.txt", true, false, false, 11},
72 {"AES_128_CBC_SHA1_TLSImplicitIV",
73 EVP_aead_aes_128_cbc_sha1_tls_implicit_iv,
74 "aes_128_cbc_sha1_tls_implicit_iv_tests.txt", true, false, false, 11},
75 {"AES_128_CBC_SHA256_TLS", EVP_aead_aes_128_cbc_sha256_tls,
76 "aes_128_cbc_sha256_tls_tests.txt", true, false, false, 11},
77 {"AES_256_CBC_SHA1_TLS", EVP_aead_aes_256_cbc_sha1_tls,
78 "aes_256_cbc_sha1_tls_tests.txt", true, false, false, 11},
79 {"AES_256_CBC_SHA1_TLSImplicitIV",
80 EVP_aead_aes_256_cbc_sha1_tls_implicit_iv,
81 "aes_256_cbc_sha1_tls_implicit_iv_tests.txt", true, false, false, 11},
82 {"AES_256_CBC_SHA256_TLS", EVP_aead_aes_256_cbc_sha256_tls,
83 "aes_256_cbc_sha256_tls_tests.txt", true, false, false, 11},
84 {"AES_256_CBC_SHA384_TLS", EVP_aead_aes_256_cbc_sha384_tls,
85 "aes_256_cbc_sha384_tls_tests.txt", true, false, false, 11},
86 {"DES_EDE3_CBC_SHA1_TLS", EVP_aead_des_ede3_cbc_sha1_tls,
87 "des_ede3_cbc_sha1_tls_tests.txt", true, false, false, 11},
88 {"DES_EDE3_CBC_SHA1_TLSImplicitIV",
89 EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv,
90 "des_ede3_cbc_sha1_tls_implicit_iv_tests.txt", true, false, false, 11},
91 {"AES_128_CTR_HMAC_SHA256", EVP_aead_aes_128_ctr_hmac_sha256,
92 "aes_128_ctr_hmac_sha256.txt", false, true, false, 0},
93 {"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256,
94 "aes_256_ctr_hmac_sha256.txt", false, true, false, 0},
95 {"AES_128_CCM_BLUETOOTH", EVP_aead_aes_128_ccm_bluetooth,
96 "aes_128_ccm_bluetooth_tests.txt", false, false, false, 0},
97 {"AES_128_CCM_BLUETOOTH_8", EVP_aead_aes_128_ccm_bluetooth_8,
98 "aes_128_ccm_bluetooth_8_tests.txt", false, false, false, 0},
99 };
100
101 class PerAEADTest : public testing::TestWithParam<KnownAEAD> {
102 public:
aead()103 const EVP_AEAD *aead() { return GetParam().func(); }
104 };
105
106 INSTANTIATE_TEST_SUITE_P(All, PerAEADTest, testing::ValuesIn(kAEADs),
107 [](const testing::TestParamInfo<KnownAEAD> ¶ms)
__anon383ad5bb0102(const testing::TestParamInfo<KnownAEAD> ¶ms) 108 -> std::string { return params.param.name; });
109
110 // Tests an AEAD against a series of test vectors from a file, using the
111 // FileTest format. As an example, here's a valid test case:
112 //
113 // KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
114 // NONCE: 978105dfce667bf4
115 // IN: 6a4583908d
116 // AD: b654574932
117 // CT: 5294265a60
118 // TAG: 1d45758621762e061368e68868e2f929
TEST_P(PerAEADTest,TestVector)119 TEST_P(PerAEADTest, TestVector) {
120 std::string test_vectors = "crypto/cipher_extra/test/";
121 test_vectors += GetParam().test_vectors;
122 FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
123 std::vector<uint8_t> key, nonce, in, ad, ct, tag;
124 ASSERT_TRUE(t->GetBytes(&key, "KEY"));
125 ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
126 ASSERT_TRUE(t->GetBytes(&in, "IN"));
127 ASSERT_TRUE(t->GetBytes(&ad, "AD"));
128 ASSERT_TRUE(t->GetBytes(&ct, "CT"));
129 ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
130 size_t tag_len = tag.size();
131 if (t->HasAttribute("TAG_LEN")) {
132 // Legacy AEADs are MAC-then-encrypt and may include padding in the TAG
133 // field. TAG_LEN contains the actual size of the digest in that case.
134 std::string tag_len_str;
135 ASSERT_TRUE(t->GetAttribute(&tag_len_str, "TAG_LEN"));
136 tag_len = strtoul(tag_len_str.c_str(), nullptr, 10);
137 ASSERT_TRUE(tag_len);
138 }
139
140 bssl::ScopedEVP_AEAD_CTX ctx;
141 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
142 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_seal));
143
144 std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead()));
145 if (!t->HasAttribute("NO_SEAL")) {
146 size_t out_len;
147 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
148 nonce.data(), nonce.size(), in.data(),
149 in.size(), ad.data(), ad.size()));
150 out.resize(out_len);
151
152 ASSERT_EQ(out.size(), ct.size() + tag.size());
153 EXPECT_EQ(Bytes(ct), Bytes(out.data(), ct.size()));
154 EXPECT_EQ(Bytes(tag), Bytes(out.data() + ct.size(), tag.size()));
155 } else {
156 out.resize(ct.size() + tag.size());
157 OPENSSL_memcpy(out.data(), ct.data(), ct.size());
158 OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size());
159 }
160
161 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
162 // reset after each operation.
163 ctx.Reset();
164 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
165 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
166
167 std::vector<uint8_t> out2(out.size());
168 size_t out2_len;
169 int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
170 nonce.data(), nonce.size(), out.data(),
171 out.size(), ad.data(), ad.size());
172 if (t->HasAttribute("FAILS")) {
173 ASSERT_FALSE(ret) << "Decrypted bad data.";
174 ERR_clear_error();
175 return;
176 }
177
178 ASSERT_TRUE(ret) << "Failed to decrypt.";
179 out2.resize(out2_len);
180 EXPECT_EQ(Bytes(in), Bytes(out2));
181
182 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
183 // reset after each operation.
184 ctx.Reset();
185 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
186 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
187
188 // Garbage at the end isn't ignored.
189 out.push_back(0);
190 out2.resize(out.size());
191 EXPECT_FALSE(EVP_AEAD_CTX_open(
192 ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(),
193 nonce.size(), out.data(), out.size(), ad.data(), ad.size()))
194 << "Decrypted bad data with trailing garbage.";
195 ERR_clear_error();
196
197 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
198 // reset after each operation.
199 ctx.Reset();
200 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
201 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
202
203 // Verify integrity is checked.
204 out[0] ^= 0x80;
205 out.resize(out.size() - 1);
206 out2.resize(out.size());
207 EXPECT_FALSE(EVP_AEAD_CTX_open(
208 ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(),
209 nonce.size(), out.data(), out.size(), ad.data(), ad.size()))
210 << "Decrypted bad data with corrupted byte.";
211 ERR_clear_error();
212 });
213 }
214
TEST_P(PerAEADTest,TestExtraInput)215 TEST_P(PerAEADTest, TestExtraInput) {
216 const KnownAEAD &aead_config = GetParam();
217 if (!aead()->seal_scatter_supports_extra_in) {
218 return;
219 }
220
221 const std::string test_vectors =
222 "crypto/cipher_extra/test/" + std::string(aead_config.test_vectors);
223 FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
224 if (t->HasAttribute("NO_SEAL") ||
225 t->HasAttribute("FAILS")) {
226 t->SkipCurrent();
227 return;
228 }
229
230 std::vector<uint8_t> key, nonce, in, ad, ct, tag;
231 ASSERT_TRUE(t->GetBytes(&key, "KEY"));
232 ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
233 ASSERT_TRUE(t->GetBytes(&in, "IN"));
234 ASSERT_TRUE(t->GetBytes(&ad, "AD"));
235 ASSERT_TRUE(t->GetBytes(&ct, "CT"));
236 ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
237
238 bssl::ScopedEVP_AEAD_CTX ctx;
239 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key.data(), key.size(),
240 tag.size(), nullptr));
241 std::vector<uint8_t> out_tag(EVP_AEAD_max_overhead(aead()) + in.size());
242 std::vector<uint8_t> out(in.size());
243
244 for (size_t extra_in_size = 0; extra_in_size < in.size(); extra_in_size++) {
245 size_t tag_bytes_written;
246 SCOPED_TRACE(extra_in_size);
247 ASSERT_TRUE(EVP_AEAD_CTX_seal_scatter(
248 ctx.get(), out.data(), out_tag.data(), &tag_bytes_written,
249 out_tag.size(), nonce.data(), nonce.size(), in.data(),
250 in.size() - extra_in_size, in.data() + in.size() - extra_in_size,
251 extra_in_size, ad.data(), ad.size()));
252
253 ASSERT_EQ(tag_bytes_written, extra_in_size + tag.size());
254
255 memcpy(out.data() + in.size() - extra_in_size, out_tag.data(),
256 extra_in_size);
257
258 EXPECT_EQ(Bytes(ct), Bytes(out.data(), in.size()));
259 EXPECT_EQ(Bytes(tag), Bytes(out_tag.data() + extra_in_size,
260 tag_bytes_written - extra_in_size));
261 }
262 });
263 }
264
TEST_P(PerAEADTest,TestVectorScatterGather)265 TEST_P(PerAEADTest, TestVectorScatterGather) {
266 std::string test_vectors = "crypto/cipher_extra/test/";
267 const KnownAEAD &aead_config = GetParam();
268 test_vectors += aead_config.test_vectors;
269 FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
270 std::vector<uint8_t> key, nonce, in, ad, ct, tag;
271 ASSERT_TRUE(t->GetBytes(&key, "KEY"));
272 ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
273 ASSERT_TRUE(t->GetBytes(&in, "IN"));
274 ASSERT_TRUE(t->GetBytes(&ad, "AD"));
275 ASSERT_TRUE(t->GetBytes(&ct, "CT"));
276 ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
277 size_t tag_len = tag.size();
278 if (t->HasAttribute("TAG_LEN")) {
279 // Legacy AEADs are MAC-then-encrypt and may include padding in the TAG
280 // field. TAG_LEN contains the actual size of the digest in that case.
281 std::string tag_len_str;
282 ASSERT_TRUE(t->GetAttribute(&tag_len_str, "TAG_LEN"));
283 tag_len = strtoul(tag_len_str.c_str(), nullptr, 10);
284 ASSERT_TRUE(tag_len);
285 }
286
287 bssl::ScopedEVP_AEAD_CTX ctx;
288 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
289 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_seal));
290
291 std::vector<uint8_t> out(in.size());
292 std::vector<uint8_t> out_tag(EVP_AEAD_max_overhead(aead()));
293 if (!t->HasAttribute("NO_SEAL")) {
294 size_t out_tag_len;
295 ASSERT_TRUE(EVP_AEAD_CTX_seal_scatter(
296 ctx.get(), out.data(), out_tag.data(), &out_tag_len, out_tag.size(),
297 nonce.data(), nonce.size(), in.data(), in.size(), nullptr, 0,
298 ad.data(), ad.size()));
299 out_tag.resize(out_tag_len);
300
301 ASSERT_EQ(out.size(), ct.size());
302 ASSERT_EQ(out_tag.size(), tag.size());
303 EXPECT_EQ(Bytes(ct), Bytes(out.data(), ct.size()));
304 EXPECT_EQ(Bytes(tag), Bytes(out_tag.data(), tag.size()));
305 } else {
306 out.resize(ct.size());
307 out_tag.resize(tag.size());
308 OPENSSL_memcpy(out.data(), ct.data(), ct.size());
309 OPENSSL_memcpy(out_tag.data(), tag.data(), tag.size());
310 }
311
312 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
313 // reset after each operation.
314 ctx.Reset();
315 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
316 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
317
318 std::vector<uint8_t> out2(out.size());
319 int ret = EVP_AEAD_CTX_open_gather(
320 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
321 out.size(), out_tag.data(), out_tag.size(), ad.data(), ad.size());
322
323 // Skip decryption for AEADs that don't implement open_gather().
324 if (!ret) {
325 int err = ERR_peek_error();
326 if (ERR_GET_LIB(err) == ERR_LIB_CIPHER &&
327 ERR_GET_REASON(err) == CIPHER_R_CTRL_NOT_IMPLEMENTED) {
328 t->SkipCurrent();
329 return;
330 }
331 }
332
333 if (t->HasAttribute("FAILS")) {
334 ASSERT_FALSE(ret) << "Decrypted bad data";
335 ERR_clear_error();
336 return;
337 }
338
339 ASSERT_TRUE(ret) << "Failed to decrypt: "
340 << ERR_reason_error_string(ERR_get_error());
341 EXPECT_EQ(Bytes(in), Bytes(out2));
342
343 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
344 // reset after each operation.
345 ctx.Reset();
346 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
347 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
348
349 // Garbage at the end isn't ignored.
350 out_tag.push_back(0);
351 out2.resize(out.size());
352 EXPECT_FALSE(EVP_AEAD_CTX_open_gather(
353 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
354 out.size(), out_tag.data(), out_tag.size(), ad.data(), ad.size()))
355 << "Decrypted bad data with trailing garbage.";
356 ERR_clear_error();
357
358 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
359 // reset after each operation.
360 ctx.Reset();
361 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
362 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
363
364 // Verify integrity is checked.
365 out_tag[0] ^= 0x80;
366 out_tag.resize(out_tag.size() - 1);
367 out2.resize(out.size());
368 EXPECT_FALSE(EVP_AEAD_CTX_open_gather(
369 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
370 out.size(), out_tag.data(), out_tag.size(), ad.data(), ad.size()))
371 << "Decrypted bad data with corrupted byte.";
372 ERR_clear_error();
373
374 ctx.Reset();
375 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
376 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
377
378 // Check edge case for tag length.
379 EXPECT_FALSE(EVP_AEAD_CTX_open_gather(
380 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
381 out.size(), out_tag.data(), 0, ad.data(), ad.size()))
382 << "Decrypted bad data with corrupted byte.";
383 ERR_clear_error();
384 });
385 }
386
TEST_P(PerAEADTest,CleanupAfterInitFailure)387 TEST_P(PerAEADTest, CleanupAfterInitFailure) {
388 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
389 OPENSSL_memset(key, 0, sizeof(key));
390 const size_t key_len = EVP_AEAD_key_length(aead());
391 ASSERT_GE(sizeof(key), key_len);
392
393 EVP_AEAD_CTX ctx;
394 ASSERT_FALSE(EVP_AEAD_CTX_init(
395 &ctx, aead(), key, key_len,
396 9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */));
397 ERR_clear_error();
398
399 // Running a second, failed _init should not cause a memory leak.
400 ASSERT_FALSE(EVP_AEAD_CTX_init(
401 &ctx, aead(), key, key_len,
402 9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */));
403 ERR_clear_error();
404
405 // Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a
406 // no-op.
407 EVP_AEAD_CTX_cleanup(&ctx);
408 }
409
TEST_P(PerAEADTest,TruncatedTags)410 TEST_P(PerAEADTest, TruncatedTags) {
411 if (!GetParam().truncated_tags) {
412 return;
413 }
414
415 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
416 OPENSSL_memset(key, 0, sizeof(key));
417 const size_t key_len = EVP_AEAD_key_length(aead());
418 ASSERT_GE(sizeof(key), key_len);
419
420 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
421 OPENSSL_memset(nonce, 0, sizeof(nonce));
422 const size_t nonce_len = EVP_AEAD_nonce_length(aead());
423 ASSERT_GE(sizeof(nonce), nonce_len);
424
425 bssl::ScopedEVP_AEAD_CTX ctx;
426 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key, key_len,
427 1 /* one byte tag */, NULL /* ENGINE */));
428
429 const uint8_t plaintext[1] = {'A'};
430
431 uint8_t ciphertext[128];
432 size_t ciphertext_len;
433 constexpr uint8_t kSentinel = 42;
434 OPENSSL_memset(ciphertext, kSentinel, sizeof(ciphertext));
435
436 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len,
437 sizeof(ciphertext), nonce, nonce_len, plaintext,
438 sizeof(plaintext), nullptr /* ad */, 0));
439
440 for (size_t i = ciphertext_len; i < sizeof(ciphertext); i++) {
441 // Sealing must not write past where it said it did.
442 EXPECT_EQ(kSentinel, ciphertext[i])
443 << "Sealing wrote off the end of the buffer.";
444 }
445
446 const size_t overhead_used = ciphertext_len - sizeof(plaintext);
447 const size_t expected_overhead =
448 1 + EVP_AEAD_max_overhead(aead()) - EVP_AEAD_max_tag_len(aead());
449 EXPECT_EQ(overhead_used, expected_overhead)
450 << "AEAD is probably ignoring request to truncate tags.";
451
452 uint8_t plaintext2[sizeof(plaintext) + 16];
453 OPENSSL_memset(plaintext2, kSentinel, sizeof(plaintext2));
454
455 size_t plaintext2_len;
456 ASSERT_TRUE(EVP_AEAD_CTX_open(
457 ctx.get(), plaintext2, &plaintext2_len, sizeof(plaintext2), nonce,
458 nonce_len, ciphertext, ciphertext_len, nullptr /* ad */, 0))
459 << "Opening with truncated tag didn't work.";
460
461 for (size_t i = plaintext2_len; i < sizeof(plaintext2); i++) {
462 // Likewise, opening should also stay within bounds.
463 EXPECT_EQ(kSentinel, plaintext2[i])
464 << "Opening wrote off the end of the buffer.";
465 }
466
467 EXPECT_EQ(Bytes(plaintext), Bytes(plaintext2, plaintext2_len));
468 }
469
TEST_P(PerAEADTest,AliasedBuffers)470 TEST_P(PerAEADTest, AliasedBuffers) {
471 if (GetParam().limited_implementation) {
472 return;
473 }
474
475 const size_t key_len = EVP_AEAD_key_length(aead());
476 const size_t nonce_len = EVP_AEAD_nonce_length(aead());
477 const size_t max_overhead = EVP_AEAD_max_overhead(aead());
478
479 std::vector<uint8_t> key(key_len, 'a');
480 bssl::ScopedEVP_AEAD_CTX ctx;
481 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key.data(), key_len,
482 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
483
484 static const uint8_t kPlaintext[260] =
485 "testing123456testing123456testing123456testing123456testing123456testing"
486 "123456testing123456testing123456testing123456testing123456testing123456t"
487 "esting123456testing123456testing123456testing123456testing123456testing1"
488 "23456testing123456testing123456testing12345";
489 const std::vector<size_t> offsets = {
490 0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63,
491 64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257,
492 };
493
494 std::vector<uint8_t> nonce(nonce_len, 'b');
495 std::vector<uint8_t> valid_encryption(sizeof(kPlaintext) + max_overhead);
496 size_t valid_encryption_len;
497 ASSERT_TRUE(EVP_AEAD_CTX_seal(
498 ctx.get(), valid_encryption.data(), &valid_encryption_len,
499 sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, kPlaintext,
500 sizeof(kPlaintext), nullptr, 0))
501 << "EVP_AEAD_CTX_seal failed with disjoint buffers.";
502
503 // Test with out != in which we expect to fail.
504 std::vector<uint8_t> buffer(2 + valid_encryption_len);
505 uint8_t *in = buffer.data() + 1;
506 uint8_t *out1 = buffer.data();
507 uint8_t *out2 = buffer.data() + 2;
508
509 OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext));
510 size_t out_len;
511 EXPECT_FALSE(EVP_AEAD_CTX_seal(
512 ctx.get(), out1 /* in - 1 */, &out_len, sizeof(kPlaintext) + max_overhead,
513 nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0));
514 EXPECT_FALSE(EVP_AEAD_CTX_seal(
515 ctx.get(), out2 /* in + 1 */, &out_len, sizeof(kPlaintext) + max_overhead,
516 nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0));
517 ERR_clear_error();
518
519 OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len);
520 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out1 /* in - 1 */, &out_len,
521 valid_encryption_len, nonce.data(), nonce_len,
522 in, valid_encryption_len, nullptr, 0));
523 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out2 /* in + 1 */, &out_len,
524 valid_encryption_len, nonce.data(), nonce_len,
525 in, valid_encryption_len, nullptr, 0));
526 ERR_clear_error();
527
528 // Test with out == in, which we expect to work.
529 OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext));
530
531 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
532 sizeof(kPlaintext) + max_overhead, nonce.data(),
533 nonce_len, in, sizeof(kPlaintext), nullptr, 0));
534 EXPECT_EQ(Bytes(valid_encryption.data(), valid_encryption_len),
535 Bytes(in, out_len));
536
537 OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len);
538 ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
539 nonce.data(), nonce_len, in,
540 valid_encryption_len, nullptr, 0));
541 EXPECT_EQ(Bytes(kPlaintext), Bytes(in, out_len));
542 }
543
TEST_P(PerAEADTest,UnalignedInput)544 TEST_P(PerAEADTest, UnalignedInput) {
545 alignas(64) uint8_t key[EVP_AEAD_MAX_KEY_LENGTH + 1];
546 alignas(64) uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH + 1];
547 alignas(64) uint8_t plaintext[32 + 1];
548 alignas(64) uint8_t ad[32 + 1];
549 OPENSSL_memset(key, 'K', sizeof(key));
550 OPENSSL_memset(nonce, 'N', sizeof(nonce));
551 OPENSSL_memset(plaintext, 'P', sizeof(plaintext));
552 OPENSSL_memset(ad, 'A', sizeof(ad));
553 const size_t key_len = EVP_AEAD_key_length(aead());
554 ASSERT_GE(sizeof(key) - 1, key_len);
555 const size_t nonce_len = EVP_AEAD_nonce_length(aead());
556 ASSERT_GE(sizeof(nonce) - 1, nonce_len);
557 const size_t ad_len =
558 GetParam().ad_len != 0 ? GetParam().ad_len : sizeof(ad) - 1;
559 ASSERT_GE(sizeof(ad) - 1, ad_len);
560
561 // Encrypt some input.
562 bssl::ScopedEVP_AEAD_CTX ctx;
563 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
564 ctx.get(), aead(), key + 1, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH,
565 evp_aead_seal));
566 alignas(64) uint8_t ciphertext[sizeof(plaintext) + EVP_AEAD_MAX_OVERHEAD];
567 size_t ciphertext_len;
568 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), ciphertext + 1, &ciphertext_len,
569 sizeof(ciphertext) - 1, nonce + 1, nonce_len,
570 plaintext + 1, sizeof(plaintext) - 1, ad + 1,
571 ad_len));
572
573 // It must successfully decrypt.
574 alignas(64) uint8_t out[sizeof(ciphertext)];
575 ctx.Reset();
576 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
577 ctx.get(), aead(), key + 1, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH,
578 evp_aead_open));
579 size_t out_len;
580 ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out + 1, &out_len, sizeof(out) - 1,
581 nonce + 1, nonce_len, ciphertext + 1,
582 ciphertext_len, ad + 1, ad_len));
583 EXPECT_EQ(Bytes(plaintext + 1, sizeof(plaintext) - 1),
584 Bytes(out + 1, out_len));
585 }
586
TEST_P(PerAEADTest,Overflow)587 TEST_P(PerAEADTest, Overflow) {
588 alignas(64) uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
589 OPENSSL_memset(key, 'K', sizeof(key));
590
591 bssl::ScopedEVP_AEAD_CTX ctx;
592 const size_t max_tag_len = EVP_AEAD_max_tag_len(aead());
593 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(ctx.get(), aead(), key,
594 EVP_AEAD_key_length(aead()),
595 max_tag_len, evp_aead_seal));
596
597 uint8_t plaintext[1] = {0};
598 uint8_t ciphertext[1024] = {0};
599 size_t ciphertext_len;
600 // The AEAD must not overflow when calculating the ciphertext length.
601 ASSERT_FALSE(EVP_AEAD_CTX_seal(
602 ctx.get(), ciphertext, &ciphertext_len, sizeof(ciphertext), nullptr, 0,
603 plaintext, std::numeric_limits<size_t>::max() - max_tag_len + 1, nullptr,
604 0));
605 ERR_clear_error();
606
607 // (Can't test the scatter interface because it'll attempt to zero the output
608 // buffer on error and the primary output buffer is implicitly the same size
609 // as the input.)
610 }
611
TEST_P(PerAEADTest,InvalidNonceLength)612 TEST_P(PerAEADTest, InvalidNonceLength) {
613 size_t valid_nonce_len = EVP_AEAD_nonce_length(aead());
614 std::vector<size_t> nonce_lens;
615 if (valid_nonce_len != 0) {
616 // Other than the implicit IV TLS "AEAD"s, none of our AEADs allow empty
617 // nonces. In particular, although AES-GCM was incorrectly specified with
618 // variable-length nonces, it does not allow the empty nonce.
619 nonce_lens.push_back(0);
620 }
621 if (!GetParam().variable_nonce) {
622 nonce_lens.push_back(valid_nonce_len + 1);
623 if (valid_nonce_len != 0) {
624 nonce_lens.push_back(valid_nonce_len - 1);
625 }
626 }
627
628 static const uint8_t kZeros[EVP_AEAD_MAX_KEY_LENGTH] = {0};
629 const size_t ad_len = GetParam().ad_len != 0 ? GetParam().ad_len : 16;
630 ASSERT_LE(ad_len, sizeof(kZeros));
631
632 for (size_t nonce_len : nonce_lens) {
633 SCOPED_TRACE(nonce_len);
634 uint8_t buf[256];
635 size_t len;
636 std::vector<uint8_t> nonce(nonce_len);
637 bssl::ScopedEVP_AEAD_CTX ctx;
638 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
639 ctx.get(), aead(), kZeros, EVP_AEAD_key_length(aead()),
640 EVP_AEAD_DEFAULT_TAG_LENGTH, evp_aead_seal));
641
642 EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
643 nonce.data(), nonce.size(), nullptr /* in */,
644 0, kZeros /* ad */, ad_len));
645 uint32_t err = ERR_get_error();
646 EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
647 // TODO(davidben): Merge these errors. https://crbug.com/boringssl/129.
648 if (ERR_GET_REASON(err) != CIPHER_R_UNSUPPORTED_NONCE_SIZE) {
649 EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
650 }
651
652 ctx.Reset();
653 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
654 ctx.get(), aead(), kZeros, EVP_AEAD_key_length(aead()),
655 EVP_AEAD_DEFAULT_TAG_LENGTH, evp_aead_open));
656 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
657 nonce.data(), nonce.size(), kZeros /* in */,
658 sizeof(kZeros), kZeros /* ad */, ad_len));
659 err = ERR_get_error();
660 EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
661 if (ERR_GET_REASON(err) != CIPHER_R_UNSUPPORTED_NONCE_SIZE) {
662 EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
663 }
664 }
665 }
666
TEST(AEADTest,AESCCMLargeAD)667 TEST(AEADTest, AESCCMLargeAD) {
668 static const std::vector<uint8_t> kKey(16, 'A');
669 static const std::vector<uint8_t> kNonce(13, 'N');
670 static const std::vector<uint8_t> kAD(65536, 'D');
671 static const std::vector<uint8_t> kPlaintext = {
672 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
673 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
674 static const std::vector<uint8_t> kCiphertext = {
675 0xa2, 0x12, 0x3f, 0x0b, 0x07, 0xd5, 0x02, 0xff,
676 0xa9, 0xcd, 0xa0, 0xf3, 0x69, 0x1c, 0x49, 0x0c};
677 static const std::vector<uint8_t> kTag = {0x4a, 0x31, 0x82, 0x96};
678
679 // Test AES-128-CCM-Bluetooth.
680 bssl::ScopedEVP_AEAD_CTX ctx;
681 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_ccm_bluetooth(),
682 kKey.data(), kKey.size(),
683 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
684
685 std::vector<uint8_t> out(kCiphertext.size() + kTag.size());
686 size_t out_len;
687 EXPECT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
688 kNonce.data(), kNonce.size(), kPlaintext.data(),
689 kPlaintext.size(), kAD.data(), kAD.size()));
690
691 ASSERT_EQ(out_len, kCiphertext.size() + kTag.size());
692 EXPECT_EQ(Bytes(kCiphertext), Bytes(out.data(), kCiphertext.size()));
693 EXPECT_EQ(Bytes(kTag), Bytes(out.data() + kCiphertext.size(), kTag.size()));
694
695 EXPECT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
696 kNonce.data(), kNonce.size(), out.data(),
697 out.size(), kAD.data(), kAD.size()));
698
699 ASSERT_EQ(out_len, kPlaintext.size());
700 EXPECT_EQ(Bytes(kPlaintext), Bytes(out.data(), kPlaintext.size()));
701 }
702
RunWycheproofTestCase(FileTest * t,const EVP_AEAD * aead)703 static void RunWycheproofTestCase(FileTest *t, const EVP_AEAD *aead) {
704 t->IgnoreInstruction("ivSize");
705
706 std::vector<uint8_t> aad, ct, iv, key, msg, tag;
707 ASSERT_TRUE(t->GetBytes(&aad, "aad"));
708 ASSERT_TRUE(t->GetBytes(&ct, "ct"));
709 ASSERT_TRUE(t->GetBytes(&iv, "iv"));
710 ASSERT_TRUE(t->GetBytes(&key, "key"));
711 ASSERT_TRUE(t->GetBytes(&msg, "msg"));
712 ASSERT_TRUE(t->GetBytes(&tag, "tag"));
713 std::string tag_size_str;
714 ASSERT_TRUE(t->GetInstruction(&tag_size_str, "tagSize"));
715 size_t tag_size = static_cast<size_t>(atoi(tag_size_str.c_str()));
716 ASSERT_EQ(0u, tag_size % 8);
717 tag_size /= 8;
718 WycheproofResult result;
719 ASSERT_TRUE(GetWycheproofResult(t, &result));
720
721 std::vector<uint8_t> ct_and_tag = ct;
722 ct_and_tag.insert(ct_and_tag.end(), tag.begin(), tag.end());
723
724 bssl::ScopedEVP_AEAD_CTX ctx;
725 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key.size(),
726 tag_size, nullptr));
727 std::vector<uint8_t> out(msg.size());
728 size_t out_len;
729 // Wycheproof tags small AES-GCM IVs as "acceptable" and otherwise does not
730 // use it in AEADs. Any AES-GCM IV that isn't 96 bits is absurd, but our API
731 // supports those, so we treat "acceptable" as "valid" here.
732 if (result != WycheproofResult::kInvalid) {
733 // Decryption should succeed.
734 ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
735 iv.data(), iv.size(), ct_and_tag.data(),
736 ct_and_tag.size(), aad.data(), aad.size()));
737 EXPECT_EQ(Bytes(msg), Bytes(out.data(), out_len));
738
739 // Decryption in-place should succeed.
740 out = ct_and_tag;
741 ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
742 iv.data(), iv.size(), out.data(), out.size(),
743 aad.data(), aad.size()));
744 EXPECT_EQ(Bytes(msg), Bytes(out.data(), out_len));
745
746 // AEADs are deterministic, so encryption should produce the same result.
747 out.resize(ct_and_tag.size());
748 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
749 iv.data(), iv.size(), msg.data(), msg.size(),
750 aad.data(), aad.size()));
751 EXPECT_EQ(Bytes(ct_and_tag), Bytes(out.data(), out_len));
752
753 // Encrypt in-place.
754 out = msg;
755 out.resize(ct_and_tag.size());
756 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
757 iv.data(), iv.size(), out.data(), msg.size(),
758 aad.data(), aad.size()));
759 EXPECT_EQ(Bytes(ct_and_tag), Bytes(out.data(), out_len));
760 } else {
761 // Decryption should fail.
762 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
763 iv.data(), iv.size(), ct_and_tag.data(),
764 ct_and_tag.size(), aad.data(), aad.size()));
765
766 // Decryption in-place should also fail.
767 out = ct_and_tag;
768 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
769 iv.data(), iv.size(), out.data(), out.size(),
770 aad.data(), aad.size()));
771 }
772 }
773
TEST(AEADTest,WycheproofAESGCMSIV)774 TEST(AEADTest, WycheproofAESGCMSIV) {
775 FileTestGTest("third_party/wycheproof_testvectors/aes_gcm_siv_test.txt",
776 [](FileTest *t) {
777 std::string key_size_str;
778 ASSERT_TRUE(t->GetInstruction(&key_size_str, "keySize"));
779 const EVP_AEAD *aead;
780 switch (atoi(key_size_str.c_str())) {
781 case 128:
782 aead = EVP_aead_aes_128_gcm_siv();
783 break;
784 case 256:
785 aead = EVP_aead_aes_256_gcm_siv();
786 break;
787 default:
788 FAIL() << "Unknown key size: " << key_size_str;
789 }
790
791 RunWycheproofTestCase(t, aead);
792 });
793 }
794
TEST(AEADTest,WycheproofAESGCM)795 TEST(AEADTest, WycheproofAESGCM) {
796 FileTestGTest("third_party/wycheproof_testvectors/aes_gcm_test.txt",
797 [](FileTest *t) {
798 std::string key_size_str;
799 ASSERT_TRUE(t->GetInstruction(&key_size_str, "keySize"));
800 const EVP_AEAD *aead;
801 switch (atoi(key_size_str.c_str())) {
802 case 128:
803 aead = EVP_aead_aes_128_gcm();
804 break;
805 case 192:
806 aead = EVP_aead_aes_192_gcm();
807 break;
808 case 256:
809 aead = EVP_aead_aes_256_gcm();
810 break;
811 default:
812 FAIL() << "Unknown key size: " << key_size_str;
813 }
814
815 RunWycheproofTestCase(t, aead);
816 });
817 }
818
TEST(AEADTest,WycheproofChaCha20Poly1305)819 TEST(AEADTest, WycheproofChaCha20Poly1305) {
820 FileTestGTest("third_party/wycheproof_testvectors/chacha20_poly1305_test.txt",
821 [](FileTest *t) {
822 t->IgnoreInstruction("keySize");
823 RunWycheproofTestCase(t, EVP_aead_chacha20_poly1305());
824 });
825 }
826