aead_test.cc revision bb1ceac29bc7a18b94e3da78057dc41aa7071784
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 <openssl/aead.h> 21#include <openssl/crypto.h> 22#include <openssl/err.h> 23 24#include "../test/file_test.h" 25 26namespace bssl { 27 28// This program tests an AEAD against a series of test vectors from a file, 29// using the FileTest format. As an example, here's a valid test case: 30// 31// KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4 32// NONCE: 978105dfce667bf4 33// IN: 6a4583908d 34// AD: b654574932 35// CT: 5294265a60 36// TAG: 1d45758621762e061368e68868e2f929 37 38static bool TestAEAD(FileTest *t, void *arg) { 39 const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg); 40 41 std::vector<uint8_t> key, nonce, in, ad, ct, tag; 42 if (!t->GetBytes(&key, "KEY") || 43 !t->GetBytes(&nonce, "NONCE") || 44 !t->GetBytes(&in, "IN") || 45 !t->GetBytes(&ad, "AD") || 46 !t->GetBytes(&ct, "CT") || 47 !t->GetBytes(&tag, "TAG")) { 48 return false; 49 } 50 51 ScopedEVP_AEAD_CTX ctx; 52 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 53 tag.size(), evp_aead_seal)) { 54 t->PrintLine("Failed to init AEAD."); 55 return false; 56 } 57 58 std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead)); 59 if (!t->HasAttribute("NO_SEAL")) { 60 size_t out_len; 61 if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), 62 nonce.data(), nonce.size(), in.data(), in.size(), 63 ad.data(), ad.size())) { 64 t->PrintLine("Failed to run AEAD."); 65 return false; 66 } 67 out.resize(out_len); 68 69 if (out.size() != ct.size() + tag.size()) { 70 t->PrintLine("Bad output length: %u vs %u.", (unsigned)out_len, 71 (unsigned)(ct.size() + tag.size())); 72 return false; 73 } 74 if (!t->ExpectBytesEqual(ct.data(), ct.size(), out.data(), ct.size()) || 75 !t->ExpectBytesEqual(tag.data(), tag.size(), out.data() + ct.size(), 76 tag.size())) { 77 return false; 78 } 79 } else { 80 out.resize(ct.size() + tag.size()); 81 memcpy(out.data(), ct.data(), ct.size()); 82 memcpy(out.data() + ct.size(), tag.data(), tag.size()); 83 } 84 85 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 86 // reset after each operation. 87 ctx.Reset(); 88 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 89 tag.size(), evp_aead_open)) { 90 t->PrintLine("Failed to init AEAD."); 91 return false; 92 } 93 94 std::vector<uint8_t> out2(out.size()); 95 size_t out2_len; 96 int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), 97 nonce.data(), nonce.size(), out.data(), 98 out.size(), ad.data(), ad.size()); 99 if (t->HasAttribute("FAILS")) { 100 if (ret) { 101 t->PrintLine("Decrypted bad data."); 102 return false; 103 } 104 ERR_clear_error(); 105 return true; 106 } 107 108 if (!ret) { 109 t->PrintLine("Failed to decrypt."); 110 return false; 111 } 112 out2.resize(out2_len); 113 if (!t->ExpectBytesEqual(in.data(), in.size(), out2.data(), out2.size())) { 114 return false; 115 } 116 117 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 118 // reset after each operation. 119 ctx.Reset(); 120 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 121 tag.size(), evp_aead_open)) { 122 t->PrintLine("Failed to init AEAD."); 123 return false; 124 } 125 126 // Garbage at the end isn't ignored. 127 out.push_back(0); 128 out2.resize(out.size()); 129 if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), 130 nonce.data(), nonce.size(), out.data(), out.size(), 131 ad.data(), ad.size())) { 132 t->PrintLine("Decrypted bad data with trailing garbage."); 133 return false; 134 } 135 ERR_clear_error(); 136 137 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 138 // reset after each operation. 139 ctx.Reset(); 140 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 141 tag.size(), evp_aead_open)) { 142 t->PrintLine("Failed to init AEAD."); 143 return false; 144 } 145 146 // Verify integrity is checked. 147 out[0] ^= 0x80; 148 out.resize(out.size() - 1); 149 out2.resize(out.size()); 150 if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), 151 nonce.data(), nonce.size(), out.data(), out.size(), 152 ad.data(), ad.size())) { 153 t->PrintLine("Decrypted bad data with corrupted byte."); 154 return false; 155 } 156 ERR_clear_error(); 157 158 return true; 159} 160 161static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) { 162 EVP_AEAD_CTX ctx; 163 uint8_t key[128]; 164 165 memset(key, 0, sizeof(key)); 166 const size_t key_len = EVP_AEAD_key_length(aead); 167 if (key_len > sizeof(key)) { 168 fprintf(stderr, "Key length of AEAD too long.\n"); 169 return 0; 170 } 171 172 if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, 173 9999 /* a silly tag length to trigger an error */, 174 NULL /* ENGINE */) != 0) { 175 fprintf(stderr, "A silly tag length didn't trigger an error!\n"); 176 return 0; 177 } 178 ERR_clear_error(); 179 180 /* Running a second, failed _init should not cause a memory leak. */ 181 if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, 182 9999 /* a silly tag length to trigger an error */, 183 NULL /* ENGINE */) != 0) { 184 fprintf(stderr, "A silly tag length didn't trigger an error!\n"); 185 return 0; 186 } 187 ERR_clear_error(); 188 189 /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a 190 * no-op. */ 191 EVP_AEAD_CTX_cleanup(&ctx); 192 return 1; 193} 194 195static bool TestWithAliasedBuffers(const EVP_AEAD *aead) { 196 const size_t key_len = EVP_AEAD_key_length(aead); 197 const size_t nonce_len = EVP_AEAD_nonce_length(aead); 198 const size_t max_overhead = EVP_AEAD_max_overhead(aead); 199 200 std::vector<uint8_t> key(key_len, 'a'); 201 ScopedEVP_AEAD_CTX ctx; 202 if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key_len, 203 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { 204 return false; 205 } 206 207 static const uint8_t kPlaintext[260] = 208 "testing123456testing123456testing123456testing123456testing123456testing" 209 "123456testing123456testing123456testing123456testing123456testing123456t" 210 "esting123456testing123456testing123456testing123456testing123456testing1" 211 "23456testing123456testing123456testing12345"; 212 const std::vector<size_t> offsets = { 213 0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63, 214 64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257, 215 }; 216 217 std::vector<uint8_t> nonce(nonce_len, 'b'); 218 std::vector<uint8_t> valid_encryption(sizeof(kPlaintext) + max_overhead); 219 size_t valid_encryption_len; 220 if (!EVP_AEAD_CTX_seal( 221 ctx.get(), valid_encryption.data(), &valid_encryption_len, 222 sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, 223 kPlaintext, sizeof(kPlaintext), nullptr, 0)) { 224 fprintf(stderr, "EVP_AEAD_CTX_seal failed with disjoint buffers.\n"); 225 return false; 226 } 227 228 // Test with out != in which we expect to fail. 229 std::vector<uint8_t> buffer(2 + valid_encryption_len); 230 uint8_t *in = buffer.data() + 1; 231 uint8_t *out1 = buffer.data(); 232 uint8_t *out2 = buffer.data() + 2; 233 234 memcpy(in, kPlaintext, sizeof(kPlaintext)); 235 size_t out_len; 236 if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len, 237 sizeof(kPlaintext) + max_overhead, nonce.data(), 238 nonce_len, in, sizeof(kPlaintext), nullptr, 0) || 239 EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len, 240 sizeof(kPlaintext) + max_overhead, nonce.data(), 241 nonce_len, in, sizeof(kPlaintext), nullptr, 0)) { 242 fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n"); 243 return false; 244 } 245 ERR_clear_error(); 246 247 memcpy(in, valid_encryption.data(), valid_encryption_len); 248 if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len, 249 nonce.data(), nonce_len, in, valid_encryption_len, 250 nullptr, 0) || 251 EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len, 252 nonce.data(), nonce_len, in, valid_encryption_len, 253 nullptr, 0)) { 254 fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n"); 255 return false; 256 } 257 ERR_clear_error(); 258 259 // Test with out == in, which we expect to work. 260 memcpy(in, kPlaintext, sizeof(kPlaintext)); 261 262 if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len, 263 sizeof(kPlaintext) + max_overhead, nonce.data(), 264 nonce_len, in, sizeof(kPlaintext), nullptr, 0)) { 265 fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n"); 266 return false; 267 } 268 269 if (out_len != valid_encryption_len || 270 memcmp(in, valid_encryption.data(), out_len) != 0) { 271 fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n"); 272 return false; 273 } 274 275 memcpy(in, valid_encryption.data(), valid_encryption_len); 276 if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len, 277 nonce.data(), nonce_len, in, valid_encryption_len, 278 nullptr, 0)) { 279 fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n"); 280 return false; 281 } 282 283 if (out_len != sizeof(kPlaintext) || 284 memcmp(in, kPlaintext, out_len) != 0) { 285 fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n"); 286 return false; 287 } 288 289 return true; 290} 291 292struct KnownAEAD { 293 const char name[40]; 294 const EVP_AEAD *(*func)(void); 295 // limited_implementation indicates that tests that assume a generic AEAD 296 // interface should not be performed. For example, the key-wrap AEADs only 297 // handle inputs that are a multiple of eight bytes in length and the 298 // SSLv3/TLS AEADs have the concept of “direction”. 299 bool limited_implementation; 300}; 301 302static const struct KnownAEAD kAEADs[] = { 303 { "aes-128-gcm", EVP_aead_aes_128_gcm, false }, 304 { "aes-256-gcm", EVP_aead_aes_256_gcm, false }, 305 { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false }, 306 { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old, false }, 307 { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true }, 308 { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, true }, 309 { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls, true }, 310 { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls, true }, 311 { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv, true }, 312 { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls, true }, 313 { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls, true }, 314 { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls, true }, 315 { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, true }, 316 { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true }, 317 { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true }, 318 { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true }, 319 { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false }, 320 { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false }, 321 { "", NULL, false }, 322}; 323 324static int Main(int argc, char **argv) { 325 CRYPTO_library_init(); 326 327 if (argc != 3) { 328 fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]); 329 return 1; 330 } 331 332 const struct KnownAEAD *known_aead; 333 for (unsigned i = 0;; i++) { 334 known_aead = &kAEADs[i]; 335 if (known_aead->func == NULL) { 336 fprintf(stderr, "Unknown AEAD: %s\n", argv[1]); 337 return 2; 338 } 339 if (strcmp(known_aead->name, argv[1]) == 0) { 340 break; 341 } 342 } 343 344 const EVP_AEAD *const aead = known_aead->func(); 345 346 if (!TestCleanupAfterInitFailure(aead)) { 347 return 1; 348 } 349 350 if (!known_aead->limited_implementation && !TestWithAliasedBuffers(aead)) { 351 fprintf(stderr, "Aliased buffers test failed for %s.\n", known_aead->name); 352 return 1; 353 } 354 355 return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]); 356} 357 358} // namespace bssl 359 360int main(int argc, char **argv) { 361 return bssl::Main(argc, argv); 362} 363