blob: a40d673c2da739f47c33e6afa3918718a9115640 [file] [log] [blame]
David Benjamin074e3d22015-05-10 01:51:26 -04001/* 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
David Benjamin6757fbf2017-05-24 00:50:35 -040020#include <gtest/gtest.h>
21
David Benjaminf0e935d2016-09-06 18:10:19 -040022#include <openssl/aead.h>
David Benjamin6757fbf2017-05-24 00:50:35 -040023#include <openssl/cipher.h>
David Benjamin074e3d22015-05-10 01:51:26 -040024#include <openssl/err.h>
25
Martin Kreichgauerd977eaa2017-06-26 10:16:50 -070026#include "../fipsmodule/cipher/internal.h"
David Benjamin17cf2cb2016-12-13 01:07:13 -050027#include "../internal.h"
David Benjamin074e3d22015-05-10 01:51:26 -040028#include "../test/file_test.h"
David Benjamin6757fbf2017-05-24 00:50:35 -040029#include "../test/test_util.h"
David Benjamin074e3d22015-05-10 01:51:26 -040030
Adam Langleydf447ba2016-12-01 08:24:24 -080031
David Benjamin6757fbf2017-05-24 00:50:35 -040032struct KnownAEAD {
33 const char name[40];
34 const EVP_AEAD *(*func)(void);
35 const char *test_vectors;
36 // limited_implementation indicates that tests that assume a generic AEAD
37 // interface should not be performed. For example, the key-wrap AEADs only
38 // handle inputs that are a multiple of eight bytes in length and the
39 // SSLv3/TLS AEADs have the concept of “direction”.
40 bool limited_implementation;
41 // truncated_tags is true if the AEAD supports truncating tags to arbitrary
42 // lengths.
43 bool truncated_tags;
David Benjamin733f46e2017-06-01 14:35:13 -040044 // ad_len, if non-zero, is the required length of the AD.
45 size_t ad_len;
David Benjamin6757fbf2017-05-24 00:50:35 -040046};
47
48static const struct KnownAEAD kAEADs[] = {
David Benjamin733f46e2017-06-01 14:35:13 -040049 {"AES_128_GCM", EVP_aead_aes_128_gcm, "aes_128_gcm_tests.txt", false, true,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070050 0},
David Benjamin6757fbf2017-05-24 00:50:35 -040051 {"AES_128_GCM_NIST", EVP_aead_aes_128_gcm, "nist_cavp/aes_128_gcm.txt",
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070052 false, true, 0},
David Benjamin733f46e2017-06-01 14:35:13 -040053 {"AES_256_GCM", EVP_aead_aes_256_gcm, "aes_256_gcm_tests.txt", false, true,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070054 0},
David Benjamin6757fbf2017-05-24 00:50:35 -040055 {"AES_256_GCM_NIST", EVP_aead_aes_256_gcm, "nist_cavp/aes_256_gcm.txt",
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070056 false, true, 0},
David Benjamin733f46e2017-06-01 14:35:13 -040057#if !defined(OPENSSL_SMALL)
David Benjamin6757fbf2017-05-24 00:50:35 -040058 {"AES_128_GCM_SIV", EVP_aead_aes_128_gcm_siv, "aes_128_gcm_siv_tests.txt",
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070059 false, false, 0},
David Benjamin6757fbf2017-05-24 00:50:35 -040060 {"AES_256_GCM_SIV", EVP_aead_aes_256_gcm_siv, "aes_256_gcm_siv_tests.txt",
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070061 false, false, 0},
David Benjamin733f46e2017-06-01 14:35:13 -040062#endif
David Benjamin6757fbf2017-05-24 00:50:35 -040063 {"ChaCha20Poly1305", EVP_aead_chacha20_poly1305,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070064 "chacha20_poly1305_tests.txt", false, true, 0},
David Benjamin6757fbf2017-05-24 00:50:35 -040065 {"AES_128_CBC_SHA1_TLS", EVP_aead_aes_128_cbc_sha1_tls,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070066 "aes_128_cbc_sha1_tls_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040067 {"AES_128_CBC_SHA1_TLSImplicitIV",
68 EVP_aead_aes_128_cbc_sha1_tls_implicit_iv,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070069 "aes_128_cbc_sha1_tls_implicit_iv_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040070 {"AES_128_CBC_SHA256_TLS", EVP_aead_aes_128_cbc_sha256_tls,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070071 "aes_128_cbc_sha256_tls_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040072 {"AES_256_CBC_SHA1_TLS", EVP_aead_aes_256_cbc_sha1_tls,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070073 "aes_256_cbc_sha1_tls_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040074 {"AES_256_CBC_SHA1_TLSImplicitIV",
75 EVP_aead_aes_256_cbc_sha1_tls_implicit_iv,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070076 "aes_256_cbc_sha1_tls_implicit_iv_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040077 {"AES_256_CBC_SHA256_TLS", EVP_aead_aes_256_cbc_sha256_tls,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070078 "aes_256_cbc_sha256_tls_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040079 {"AES_256_CBC_SHA384_TLS", EVP_aead_aes_256_cbc_sha384_tls,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070080 "aes_256_cbc_sha384_tls_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040081 {"DES_EDE3_CBC_SHA1_TLS", EVP_aead_des_ede3_cbc_sha1_tls,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070082 "des_ede3_cbc_sha1_tls_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040083 {"DES_EDE3_CBC_SHA1_TLSImplicitIV",
84 EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070085 "des_ede3_cbc_sha1_tls_implicit_iv_tests.txt", true, false, 11},
David Benjamin6757fbf2017-05-24 00:50:35 -040086 {"AES_128_CBC_SHA1_SSL3", EVP_aead_aes_128_cbc_sha1_ssl3,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070087 "aes_128_cbc_sha1_ssl3_tests.txt", true, false, 9},
David Benjamin6757fbf2017-05-24 00:50:35 -040088 {"AES_256_CBC_SHA1_SSL3", EVP_aead_aes_256_cbc_sha1_ssl3,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070089 "aes_256_cbc_sha1_ssl3_tests.txt", true, false, 9},
David Benjamin6757fbf2017-05-24 00:50:35 -040090 {"DES_EDE3_CBC_SHA1_SSL3", EVP_aead_des_ede3_cbc_sha1_ssl3,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070091 "des_ede3_cbc_sha1_ssl3_tests.txt", true, false, 9},
David Benjamin6757fbf2017-05-24 00:50:35 -040092 {"AES_128_CTR_HMAC_SHA256", EVP_aead_aes_128_ctr_hmac_sha256,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070093 "aes_128_ctr_hmac_sha256.txt", false, true, 0},
David Benjamin6757fbf2017-05-24 00:50:35 -040094 {"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256,
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -070095 "aes_256_ctr_hmac_sha256.txt", false, true, 0},
David Benjamin6757fbf2017-05-24 00:50:35 -040096};
Adam Langleydf447ba2016-12-01 08:24:24 -080097
David Benjamin6757fbf2017-05-24 00:50:35 -040098class PerAEADTest : public testing::TestWithParam<KnownAEAD> {
99 public:
100 const EVP_AEAD *aead() { return GetParam().func(); }
101};
102
103INSTANTIATE_TEST_CASE_P(, PerAEADTest, testing::ValuesIn(kAEADs),
104 [](const testing::TestParamInfo<KnownAEAD> &params)
105 -> std::string { return params.param.name; });
106
107// Tests an AEAD against a series of test vectors from a file, using the
108// FileTest format. As an example, here's a valid test case:
David Benjamin074e3d22015-05-10 01:51:26 -0400109//
110// KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
111// NONCE: 978105dfce667bf4
112// IN: 6a4583908d
113// AD: b654574932
114// CT: 5294265a60
115// TAG: 1d45758621762e061368e68868e2f929
David Benjamin6757fbf2017-05-24 00:50:35 -0400116TEST_P(PerAEADTest, TestVector) {
117 std::string test_vectors = "crypto/cipher_extra/test/";
118 test_vectors += GetParam().test_vectors;
119 FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
120 std::vector<uint8_t> key, nonce, in, ad, ct, tag;
121 ASSERT_TRUE(t->GetBytes(&key, "KEY"));
122 ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
123 ASSERT_TRUE(t->GetBytes(&in, "IN"));
124 ASSERT_TRUE(t->GetBytes(&ad, "AD"));
125 ASSERT_TRUE(t->GetBytes(&ct, "CT"));
126 ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700127 size_t tag_len = tag.size();
128 if (t->HasAttribute("TAG_LEN")) {
129 // Legacy AEADs are MAC-then-encrypt and may include padding in the TAG
130 // field. TAG_LEN contains the actual size of the digest in that case.
131 std::string tag_len_str;
132 ASSERT_TRUE(t->GetAttribute(&tag_len_str, "TAG_LEN"));
133 tag_len = strtoul(tag_len_str.c_str(), nullptr, 10);
134 ASSERT_TRUE(tag_len);
135 }
David Benjamin074e3d22015-05-10 01:51:26 -0400136
David Benjamin6757fbf2017-05-24 00:50:35 -0400137 bssl::ScopedEVP_AEAD_CTX ctx;
138 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700139 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_seal));
David Benjamin074e3d22015-05-10 01:51:26 -0400140
David Benjamin6757fbf2017-05-24 00:50:35 -0400141 std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead()));
142 if (!t->HasAttribute("NO_SEAL")) {
143 size_t out_len;
144 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
145 nonce.data(), nonce.size(), in.data(),
146 in.size(), ad.data(), ad.size()));
147 out.resize(out_len);
David Benjamin074e3d22015-05-10 01:51:26 -0400148
David Benjamin6757fbf2017-05-24 00:50:35 -0400149 ASSERT_EQ(out.size(), ct.size() + tag.size());
150 EXPECT_EQ(Bytes(ct), Bytes(out.data(), ct.size()));
151 EXPECT_EQ(Bytes(tag), Bytes(out.data() + ct.size(), tag.size()));
152 } else {
153 out.resize(ct.size() + tag.size());
154 OPENSSL_memcpy(out.data(), ct.data(), ct.size());
155 OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size());
David Benjamin074e3d22015-05-10 01:51:26 -0400156 }
David Benjamin074e3d22015-05-10 01:51:26 -0400157
David Benjamin6757fbf2017-05-24 00:50:35 -0400158 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
159 // reset after each operation.
160 ctx.Reset();
161 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700162 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
David Benjamin074e3d22015-05-10 01:51:26 -0400163
David Benjamin6757fbf2017-05-24 00:50:35 -0400164 std::vector<uint8_t> out2(out.size());
165 size_t out2_len;
166 int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
167 nonce.data(), nonce.size(), out.data(),
168 out.size(), ad.data(), ad.size());
169 if (t->HasAttribute("FAILS")) {
170 ASSERT_FALSE(ret) << "Decrypted bad data.";
171 ERR_clear_error();
172 return;
David Benjamin074e3d22015-05-10 01:51:26 -0400173 }
David Benjamin6757fbf2017-05-24 00:50:35 -0400174
175 ASSERT_TRUE(ret) << "Failed to decrypt.";
176 out2.resize(out2_len);
177 EXPECT_EQ(Bytes(in), Bytes(out2));
178
179 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
180 // reset after each operation.
181 ctx.Reset();
182 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700183 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
David Benjamin6757fbf2017-05-24 00:50:35 -0400184
185 // Garbage at the end isn't ignored.
186 out.push_back(0);
187 out2.resize(out.size());
188 EXPECT_FALSE(EVP_AEAD_CTX_open(
189 ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(),
190 nonce.size(), out.data(), out.size(), ad.data(), ad.size()))
191 << "Decrypted bad data with trailing garbage.";
David Benjamin074e3d22015-05-10 01:51:26 -0400192 ERR_clear_error();
David Benjamin074e3d22015-05-10 01:51:26 -0400193
David Benjamin6757fbf2017-05-24 00:50:35 -0400194 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
195 // reset after each operation.
196 ctx.Reset();
197 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700198 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
David Benjamin074e3d22015-05-10 01:51:26 -0400199
David Benjamin6757fbf2017-05-24 00:50:35 -0400200 // Verify integrity is checked.
201 out[0] ^= 0x80;
202 out.resize(out.size() - 1);
203 out2.resize(out.size());
204 EXPECT_FALSE(EVP_AEAD_CTX_open(
205 ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(),
206 nonce.size(), out.data(), out.size(), ad.data(), ad.size()))
207 << "Decrypted bad data with corrupted byte.";
208 ERR_clear_error();
209 });
David Benjamin074e3d22015-05-10 01:51:26 -0400210}
211
Martin Kreichgauerd977eaa2017-06-26 10:16:50 -0700212TEST_P(PerAEADTest, TestExtraInput) {
213 const KnownAEAD &aead_config = GetParam();
214 if (!aead()->seal_scatter_supports_extra_in) {
215 return;
216 }
217
218 const std::string test_vectors =
219 "crypto/cipher_extra/test/" + std::string(aead_config.test_vectors);
220 FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
221 if (t->HasAttribute("NO_SEAL") ||
222 t->HasAttribute("FAILS")) {
223 t->SkipCurrent();
224 return;
225 }
226
227 std::vector<uint8_t> key, nonce, in, ad, ct, tag;
228 ASSERT_TRUE(t->GetBytes(&key, "KEY"));
229 ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
230 ASSERT_TRUE(t->GetBytes(&in, "IN"));
231 ASSERT_TRUE(t->GetBytes(&ad, "AD"));
232 ASSERT_TRUE(t->GetBytes(&ct, "CT"));
233 ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
234
235 bssl::ScopedEVP_AEAD_CTX ctx;
236 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key.data(), key.size(),
237 tag.size(), nullptr));
238 std::vector<uint8_t> out_tag(EVP_AEAD_max_overhead(aead()) + in.size());
239 std::vector<uint8_t> out(in.size());
240
241 for (size_t extra_in_size = 0; extra_in_size < in.size(); extra_in_size++) {
242 size_t tag_bytes_written;
Adam Langleyc66e3972017-06-28 13:33:08 -0700243 SCOPED_TRACE(extra_in_size);
Martin Kreichgauerd977eaa2017-06-26 10:16:50 -0700244 ASSERT_TRUE(EVP_AEAD_CTX_seal_scatter(
245 ctx.get(), out.data(), out_tag.data(), &tag_bytes_written,
246 out_tag.size(), nonce.data(), nonce.size(), in.data(),
247 in.size() - extra_in_size, in.data() + in.size() - extra_in_size,
248 extra_in_size, ad.data(), ad.size()));
249
250 ASSERT_EQ(tag_bytes_written, extra_in_size + tag.size());
251
252 memcpy(out.data() + in.size() - extra_in_size, out_tag.data(),
253 extra_in_size);
254
255 EXPECT_EQ(Bytes(ct), Bytes(out.data(), in.size()));
256 EXPECT_EQ(Bytes(tag), Bytes(out_tag.data() + extra_in_size,
257 tag_bytes_written - extra_in_size));
258 }
259 });
260}
261
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700262TEST_P(PerAEADTest, TestVectorScatterGather) {
263 std::string test_vectors = "crypto/cipher_extra/test/";
264 const KnownAEAD &aead_config = GetParam();
265 test_vectors += aead_config.test_vectors;
266 FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
267 std::vector<uint8_t> key, nonce, in, ad, ct, tag;
268 ASSERT_TRUE(t->GetBytes(&key, "KEY"));
269 ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
270 ASSERT_TRUE(t->GetBytes(&in, "IN"));
271 ASSERT_TRUE(t->GetBytes(&ad, "AD"));
272 ASSERT_TRUE(t->GetBytes(&ct, "CT"));
273 ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
274 size_t tag_len = tag.size();
275 if (t->HasAttribute("TAG_LEN")) {
276 // Legacy AEADs are MAC-then-encrypt and may include padding in the TAG
277 // field. TAG_LEN contains the actual size of the digest in that case.
278 std::string tag_len_str;
279 ASSERT_TRUE(t->GetAttribute(&tag_len_str, "TAG_LEN"));
280 tag_len = strtoul(tag_len_str.c_str(), nullptr, 10);
281 ASSERT_TRUE(tag_len);
282 }
283
284 bssl::ScopedEVP_AEAD_CTX ctx;
285 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
286 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_seal));
287
288 std::vector<uint8_t> out(in.size());
289 std::vector<uint8_t> out_tag(EVP_AEAD_max_overhead(aead()));
290 if (!t->HasAttribute("NO_SEAL")) {
291 size_t out_tag_len;
292 ASSERT_TRUE(EVP_AEAD_CTX_seal_scatter(
293 ctx.get(), out.data(), out_tag.data(), &out_tag_len, out_tag.size(),
Martin Kreichgauer74bce292017-06-23 14:49:22 -0700294 nonce.data(), nonce.size(), in.data(), in.size(), nullptr, 0,
295 ad.data(), ad.size()));
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700296 out_tag.resize(out_tag_len);
297
298 ASSERT_EQ(out.size(), ct.size());
299 ASSERT_EQ(out_tag.size(), tag.size());
300 EXPECT_EQ(Bytes(ct), Bytes(out.data(), ct.size()));
301 EXPECT_EQ(Bytes(tag), Bytes(out_tag.data(), tag.size()));
302 } else {
303 out.resize(ct.size());
304 out_tag.resize(tag.size());
305 OPENSSL_memcpy(out.data(), ct.data(), ct.size());
306 OPENSSL_memcpy(out_tag.data(), tag.data(), tag.size());
307 }
308
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700309 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
310 // reset after each operation.
311 ctx.Reset();
312 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
313 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
314
315 std::vector<uint8_t> out2(out.size());
316 int ret = EVP_AEAD_CTX_open_gather(
317 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
318 out.size(), out_tag.data(), out_tag.size(), ad.data(), ad.size());
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -0700319
320 // Skip decryption for AEADs that don't implement open_gather().
321 if (!ret) {
322 int err = ERR_peek_error();
323 if (ERR_GET_LIB(err) == ERR_LIB_CIPHER &&
324 ERR_GET_REASON(err) == CIPHER_R_CTRL_NOT_IMPLEMENTED) {
Martin Kreichgauerd977eaa2017-06-26 10:16:50 -0700325 t->SkipCurrent();
Martin Kreichgauer6af3a3d2017-06-09 16:25:02 -0700326 return;
327 }
328 }
329
Martin Kreichgauer18d9f282017-06-06 12:29:48 -0700330 if (t->HasAttribute("FAILS")) {
331 ASSERT_FALSE(ret) << "Decrypted bad data";
332 ERR_clear_error();
333 return;
334 }
335
336 ASSERT_TRUE(ret) << "Failed to decrypt: "
337 << ERR_reason_error_string(ERR_get_error());
338 EXPECT_EQ(Bytes(in), Bytes(out2));
339
340 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
341 // reset after each operation.
342 ctx.Reset();
343 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
344 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
345
346 // Garbage at the end isn't ignored.
347 out_tag.push_back(0);
348 out2.resize(out.size());
349 EXPECT_FALSE(EVP_AEAD_CTX_open_gather(
350 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
351 out.size(), out_tag.data(), out_tag.size(), ad.data(), ad.size()))
352 << "Decrypted bad data with trailing garbage.";
353 ERR_clear_error();
354
355 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
356 // reset after each operation.
357 ctx.Reset();
358 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
359 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
360
361 // Verify integrity is checked.
362 out_tag[0] ^= 0x80;
363 out_tag.resize(out_tag.size() - 1);
364 out2.resize(out.size());
365 EXPECT_FALSE(EVP_AEAD_CTX_open_gather(
366 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
367 out.size(), out_tag.data(), out_tag.size(), ad.data(), ad.size()))
368 << "Decrypted bad data with corrupted byte.";
369 ERR_clear_error();
370
371 ctx.Reset();
372 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
373 ctx.get(), aead(), key.data(), key.size(), tag_len, evp_aead_open));
374
375 // Check edge case for tag length.
376 EXPECT_FALSE(EVP_AEAD_CTX_open_gather(
377 ctx.get(), out2.data(), nonce.data(), nonce.size(), out.data(),
378 out.size(), out_tag.data(), 0, ad.data(), ad.size()))
379 << "Decrypted bad data with corrupted byte.";
380 ERR_clear_error();
381 });
382}
383
David Benjamin6757fbf2017-05-24 00:50:35 -0400384TEST_P(PerAEADTest, CleanupAfterInitFailure) {
Adam Langley5c7a4b82017-01-20 11:40:50 -0800385 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
David Benjamin17cf2cb2016-12-13 01:07:13 -0500386 OPENSSL_memset(key, 0, sizeof(key));
David Benjamin6757fbf2017-05-24 00:50:35 -0400387 const size_t key_len = EVP_AEAD_key_length(aead());
388 ASSERT_GE(sizeof(key), key_len);
Adam Langley5aa8a862015-05-11 14:28:12 -0700389
Adam Langley5c7a4b82017-01-20 11:40:50 -0800390 EVP_AEAD_CTX ctx;
David Benjamin6757fbf2017-05-24 00:50:35 -0400391 ASSERT_FALSE(EVP_AEAD_CTX_init(
392 &ctx, aead(), key, key_len,
393 9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */));
David Benjaminfd560362015-06-30 16:32:48 -0400394 ERR_clear_error();
Adam Langley5aa8a862015-05-11 14:28:12 -0700395
David Benjamin808f8322017-08-18 14:06:02 -0400396 // Running a second, failed _init should not cause a memory leak.
David Benjamin6757fbf2017-05-24 00:50:35 -0400397 ASSERT_FALSE(EVP_AEAD_CTX_init(
398 &ctx, aead(), key, key_len,
399 9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */));
David Benjaminfd560362015-06-30 16:32:48 -0400400 ERR_clear_error();
Adam Langley5aa8a862015-05-11 14:28:12 -0700401
David Benjamin808f8322017-08-18 14:06:02 -0400402 // Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a
403 // no-op.
Adam Langley5aa8a862015-05-11 14:28:12 -0700404 EVP_AEAD_CTX_cleanup(&ctx);
Adam Langley5aa8a862015-05-11 14:28:12 -0700405}
406
David Benjamin6757fbf2017-05-24 00:50:35 -0400407TEST_P(PerAEADTest, TruncatedTags) {
408 if (!GetParam().truncated_tags) {
409 return;
410 }
411
Adam Langley5c7a4b82017-01-20 11:40:50 -0800412 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
413 OPENSSL_memset(key, 0, sizeof(key));
David Benjamin6757fbf2017-05-24 00:50:35 -0400414 const size_t key_len = EVP_AEAD_key_length(aead());
415 ASSERT_GE(sizeof(key), key_len);
Adam Langley5c7a4b82017-01-20 11:40:50 -0800416
417 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
418 OPENSSL_memset(nonce, 0, sizeof(nonce));
David Benjamin6757fbf2017-05-24 00:50:35 -0400419 const size_t nonce_len = EVP_AEAD_nonce_length(aead());
420 ASSERT_GE(sizeof(nonce), nonce_len);
Adam Langley5c7a4b82017-01-20 11:40:50 -0800421
422 bssl::ScopedEVP_AEAD_CTX ctx;
David Benjamin6757fbf2017-05-24 00:50:35 -0400423 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key, key_len,
424 1 /* one byte tag */, NULL /* ENGINE */));
Adam Langley5c7a4b82017-01-20 11:40:50 -0800425
426 const uint8_t plaintext[1] = {'A'};
427
428 uint8_t ciphertext[128];
429 size_t ciphertext_len;
430 constexpr uint8_t kSentinel = 42;
431 OPENSSL_memset(ciphertext, kSentinel, sizeof(ciphertext));
432
David Benjamin6757fbf2017-05-24 00:50:35 -0400433 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len,
434 sizeof(ciphertext), nonce, nonce_len, plaintext,
435 sizeof(plaintext), nullptr /* ad */, 0));
Adam Langley5c7a4b82017-01-20 11:40:50 -0800436
437 for (size_t i = ciphertext_len; i < sizeof(ciphertext); i++) {
438 // Sealing must not write past where it said it did.
David Benjamin6757fbf2017-05-24 00:50:35 -0400439 EXPECT_EQ(kSentinel, ciphertext[i])
440 << "Sealing wrote off the end of the buffer.";
Adam Langley5c7a4b82017-01-20 11:40:50 -0800441 }
442
443 const size_t overhead_used = ciphertext_len - sizeof(plaintext);
Steven Valdez1d134ee2017-04-19 16:45:09 -0400444 const size_t expected_overhead =
David Benjamin6757fbf2017-05-24 00:50:35 -0400445 1 + EVP_AEAD_max_overhead(aead()) - EVP_AEAD_max_tag_len(aead());
446 EXPECT_EQ(overhead_used, expected_overhead)
447 << "AEAD is probably ignoring request to truncate tags.";
Adam Langley5c7a4b82017-01-20 11:40:50 -0800448
449 uint8_t plaintext2[sizeof(plaintext) + 16];
450 OPENSSL_memset(plaintext2, kSentinel, sizeof(plaintext2));
451
452 size_t plaintext2_len;
David Benjamin6757fbf2017-05-24 00:50:35 -0400453 ASSERT_TRUE(EVP_AEAD_CTX_open(
454 ctx.get(), plaintext2, &plaintext2_len, sizeof(plaintext2), nonce,
455 nonce_len, ciphertext, ciphertext_len, nullptr /* ad */, 0))
456 << "Opening with truncated tag didn't work.";
Adam Langley5c7a4b82017-01-20 11:40:50 -0800457
458 for (size_t i = plaintext2_len; i < sizeof(plaintext2); i++) {
459 // Likewise, opening should also stay within bounds.
David Benjamin6757fbf2017-05-24 00:50:35 -0400460 EXPECT_EQ(kSentinel, plaintext2[i])
461 << "Opening wrote off the end of the buffer.";
Adam Langley5c7a4b82017-01-20 11:40:50 -0800462 }
463
David Benjamin6757fbf2017-05-24 00:50:35 -0400464 EXPECT_EQ(Bytes(plaintext), Bytes(plaintext2, plaintext2_len));
Adam Langley5c7a4b82017-01-20 11:40:50 -0800465}
466
David Benjamin6757fbf2017-05-24 00:50:35 -0400467TEST_P(PerAEADTest, AliasedBuffers) {
468 if (GetParam().limited_implementation) {
469 return;
470 }
471
472 const size_t key_len = EVP_AEAD_key_length(aead());
473 const size_t nonce_len = EVP_AEAD_nonce_length(aead());
474 const size_t max_overhead = EVP_AEAD_max_overhead(aead());
Adam Langleyf132d4e2016-02-25 17:07:19 -0800475
476 std::vector<uint8_t> key(key_len, 'a');
David Benjaminaac1e2d2016-12-06 22:35:41 -0500477 bssl::ScopedEVP_AEAD_CTX ctx;
David Benjamin6757fbf2017-05-24 00:50:35 -0400478 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key.data(), key_len,
479 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
Adam Langleyf132d4e2016-02-25 17:07:19 -0800480
481 static const uint8_t kPlaintext[260] =
482 "testing123456testing123456testing123456testing123456testing123456testing"
483 "123456testing123456testing123456testing123456testing123456testing123456t"
484 "esting123456testing123456testing123456testing123456testing123456testing1"
485 "23456testing123456testing123456testing12345";
486 const std::vector<size_t> offsets = {
487 0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63,
488 64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257,
489 };
490
491 std::vector<uint8_t> nonce(nonce_len, 'b');
492 std::vector<uint8_t> valid_encryption(sizeof(kPlaintext) + max_overhead);
493 size_t valid_encryption_len;
David Benjamin6757fbf2017-05-24 00:50:35 -0400494 ASSERT_TRUE(EVP_AEAD_CTX_seal(
495 ctx.get(), valid_encryption.data(), &valid_encryption_len,
496 sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, kPlaintext,
497 sizeof(kPlaintext), nullptr, 0))
498 << "EVP_AEAD_CTX_seal failed with disjoint buffers.";
Adam Langleyf132d4e2016-02-25 17:07:19 -0800499
David Benjamin2446db02016-06-08 18:31:42 -0400500 // Test with out != in which we expect to fail.
501 std::vector<uint8_t> buffer(2 + valid_encryption_len);
502 uint8_t *in = buffer.data() + 1;
503 uint8_t *out1 = buffer.data();
504 uint8_t *out2 = buffer.data() + 2;
Adam Langleyf132d4e2016-02-25 17:07:19 -0800505
David Benjamin17cf2cb2016-12-13 01:07:13 -0500506 OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext));
David Benjamin2446db02016-06-08 18:31:42 -0400507 size_t out_len;
David Benjamin6757fbf2017-05-24 00:50:35 -0400508 EXPECT_FALSE(EVP_AEAD_CTX_seal(
509 ctx.get(), out1 /* in - 1 */, &out_len, sizeof(kPlaintext) + max_overhead,
510 nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0));
511 EXPECT_FALSE(EVP_AEAD_CTX_seal(
512 ctx.get(), out2 /* in + 1 */, &out_len, sizeof(kPlaintext) + max_overhead,
513 nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0));
David Benjamin2446db02016-06-08 18:31:42 -0400514 ERR_clear_error();
Adam Langleyf132d4e2016-02-25 17:07:19 -0800515
David Benjamin17cf2cb2016-12-13 01:07:13 -0500516 OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len);
David Benjamin6757fbf2017-05-24 00:50:35 -0400517 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out1 /* in - 1 */, &out_len,
518 valid_encryption_len, nonce.data(), nonce_len,
519 in, valid_encryption_len, nullptr, 0));
520 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out2 /* in + 1 */, &out_len,
521 valid_encryption_len, nonce.data(), nonce_len,
522 in, valid_encryption_len, nullptr, 0));
David Benjamin2446db02016-06-08 18:31:42 -0400523 ERR_clear_error();
Adam Langleyf132d4e2016-02-25 17:07:19 -0800524
David Benjamin2446db02016-06-08 18:31:42 -0400525 // Test with out == in, which we expect to work.
David Benjamin17cf2cb2016-12-13 01:07:13 -0500526 OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext));
David Benjamin2446db02016-06-08 18:31:42 -0400527
David Benjamin6757fbf2017-05-24 00:50:35 -0400528 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
529 sizeof(kPlaintext) + max_overhead, nonce.data(),
530 nonce_len, in, sizeof(kPlaintext), nullptr, 0));
531 EXPECT_EQ(Bytes(valid_encryption.data(), valid_encryption_len),
532 Bytes(in, out_len));
Adam Langleyf132d4e2016-02-25 17:07:19 -0800533
David Benjamin17cf2cb2016-12-13 01:07:13 -0500534 OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len);
David Benjamin6757fbf2017-05-24 00:50:35 -0400535 ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
536 nonce.data(), nonce_len, in,
537 valid_encryption_len, nullptr, 0));
538 EXPECT_EQ(Bytes(kPlaintext), Bytes(in, out_len));
Adam Langleyf132d4e2016-02-25 17:07:19 -0800539}
540
David Benjamin733f46e2017-06-01 14:35:13 -0400541TEST_P(PerAEADTest, UnalignedInput) {
542 alignas(64) uint8_t key[EVP_AEAD_MAX_KEY_LENGTH + 1];
543 alignas(64) uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH + 1];
544 alignas(64) uint8_t plaintext[32 + 1];
545 alignas(64) uint8_t ad[32 + 1];
546 OPENSSL_memset(key, 'K', sizeof(key));
547 OPENSSL_memset(nonce, 'N', sizeof(nonce));
548 OPENSSL_memset(plaintext, 'P', sizeof(plaintext));
549 OPENSSL_memset(ad, 'A', sizeof(ad));
550 const size_t key_len = EVP_AEAD_key_length(aead());
551 ASSERT_GE(sizeof(key) - 1, key_len);
552 const size_t nonce_len = EVP_AEAD_nonce_length(aead());
553 ASSERT_GE(sizeof(nonce) - 1, nonce_len);
554 const size_t ad_len =
555 GetParam().ad_len != 0 ? GetParam().ad_len : sizeof(ad) - 1;
556 ASSERT_GE(sizeof(ad) - 1, ad_len);
557
558 // Encrypt some input.
559 bssl::ScopedEVP_AEAD_CTX ctx;
560 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
561 ctx.get(), aead(), key + 1, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH,
562 evp_aead_seal));
563 alignas(64) uint8_t ciphertext[sizeof(plaintext) + EVP_AEAD_MAX_OVERHEAD];
564 size_t ciphertext_len;
565 ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), ciphertext + 1, &ciphertext_len,
566 sizeof(ciphertext) - 1, nonce + 1, nonce_len,
567 plaintext + 1, sizeof(plaintext) - 1, ad + 1,
568 ad_len));
569
570 // It must successfully decrypt.
571 alignas(64) uint8_t out[sizeof(ciphertext)];
572 ctx.Reset();
573 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
574 ctx.get(), aead(), key + 1, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH,
575 evp_aead_open));
576 size_t out_len;
577 ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out + 1, &out_len, sizeof(out) - 1,
578 nonce + 1, nonce_len, ciphertext + 1,
579 ciphertext_len, ad + 1, ad_len));
580 EXPECT_EQ(Bytes(plaintext + 1, sizeof(plaintext) - 1),
581 Bytes(out + 1, out_len));
582}
583
Adam Langleyd2e872f2017-07-05 15:37:04 -0700584TEST_P(PerAEADTest, Overflow) {
585 alignas(64) uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
586 OPENSSL_memset(key, 'K', sizeof(key));
587
588 bssl::ScopedEVP_AEAD_CTX ctx;
589 const size_t max_tag_len = EVP_AEAD_max_tag_len(aead());
590 ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(ctx.get(), aead(), key,
591 EVP_AEAD_key_length(aead()),
592 max_tag_len, evp_aead_seal));
593
594 uint8_t plaintext[1] = {0};
595 uint8_t ciphertext[1024] = {0};
596 size_t ciphertext_len;
597 // The AEAD must not overflow when calculating the ciphertext length.
598 ASSERT_FALSE(EVP_AEAD_CTX_seal(
599 ctx.get(), ciphertext, &ciphertext_len, sizeof(ciphertext), nullptr, 0,
600 plaintext, std::numeric_limits<size_t>::max() - max_tag_len + 1, nullptr,
601 0));
602 ERR_clear_error();
603
604 // (Can't test the scatter interface because it'll attempt to zero the output
605 // buffer on error and the primary output buffer is implicitly the same size
606 // as the input.)
607}
608
David Benjamin6757fbf2017-05-24 00:50:35 -0400609// Test that EVP_aead_aes_128_gcm and EVP_aead_aes_256_gcm reject empty nonces.
610// AES-GCM is not defined for those.
611TEST(AEADTest, AESGCMEmptyNonce) {
612 static const uint8_t kZeros[32] = {0};
Adam Langley9624b402015-05-11 14:26:16 -0700613
David Benjamin6757fbf2017-05-24 00:50:35 -0400614 // Test AES-128-GCM.
615 uint8_t buf[16];
616 size_t len;
617 bssl::ScopedEVP_AEAD_CTX ctx;
618 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_gcm(), kZeros, 16,
619 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
Adam Langley9624b402015-05-11 14:26:16 -0700620
David Benjamin6757fbf2017-05-24 00:50:35 -0400621 EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
622 nullptr /* nonce */, 0, nullptr /* in */, 0,
623 nullptr /* ad */, 0));
624 uint32_t err = ERR_get_error();
625 EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
626 EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
David Benjamin074e3d22015-05-10 01:51:26 -0400627
David Benjamin6757fbf2017-05-24 00:50:35 -0400628 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
629 nullptr /* nonce */, 0, kZeros /* in */,
630 sizeof(kZeros), nullptr /* ad */, 0));
631 err = ERR_get_error();
632 EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
633 EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
David Benjamin074e3d22015-05-10 01:51:26 -0400634
David Benjamin6757fbf2017-05-24 00:50:35 -0400635 // Test AES-256-GCM.
636 ctx.Reset();
637 ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(), kZeros, 32,
638 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
David Benjamin074e3d22015-05-10 01:51:26 -0400639
David Benjamin6757fbf2017-05-24 00:50:35 -0400640 EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
641 nullptr /* nonce */, 0, nullptr /* in */, 0,
642 nullptr /* ad */, 0));
643 err = ERR_get_error();
644 EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
645 EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
Adam Langleyf132d4e2016-02-25 17:07:19 -0800646
David Benjamin6757fbf2017-05-24 00:50:35 -0400647 EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
648 nullptr /* nonce */, 0, kZeros /* in */,
649 sizeof(kZeros), nullptr /* ad */, 0));
650 err = ERR_get_error();
651 EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
652 EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
David Benjamin074e3d22015-05-10 01:51:26 -0400653}