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 <assert.h> 16 #include <stdint.h> 17 #include <string.h> 18 19 #include <vector> 20 21 #include <openssl/aead.h> 22 #include <openssl/crypto.h> 23 #include <openssl/err.h> 24 25 #include "../internal.h" 26 #include "../test/file_test.h" 27 28 29 #if defined(OPENSSL_SMALL) 30 const EVP_AEAD* EVP_aead_aes_128_gcm_siv(void) { 31 return nullptr; 32 } 33 const EVP_AEAD* EVP_aead_aes_256_gcm_siv(void) { 34 return nullptr; 35 } 36 #endif 37 38 // This program tests an AEAD against a series of test vectors from a file, 39 // using the FileTest format. As an example, here's a valid test case: 40 // 41 // KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4 42 // NONCE: 978105dfce667bf4 43 // IN: 6a4583908d 44 // AD: b654574932 45 // CT: 5294265a60 46 // TAG: 1d45758621762e061368e68868e2f929 47 48 static bool TestAEAD(FileTest *t, void *arg) { 49 const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg); 50 51 std::vector<uint8_t> key, nonce, in, ad, ct, tag; 52 if (!t->GetBytes(&key, "KEY") || 53 !t->GetBytes(&nonce, "NONCE") || 54 !t->GetBytes(&in, "IN") || 55 !t->GetBytes(&ad, "AD") || 56 !t->GetBytes(&ct, "CT") || 57 !t->GetBytes(&tag, "TAG")) { 58 return false; 59 } 60 61 bssl::ScopedEVP_AEAD_CTX ctx; 62 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 63 tag.size(), evp_aead_seal)) { 64 t->PrintLine("Failed to init AEAD."); 65 return false; 66 } 67 68 std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead)); 69 if (!t->HasAttribute("NO_SEAL")) { 70 size_t out_len; 71 if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), 72 nonce.data(), nonce.size(), in.data(), in.size(), 73 ad.data(), ad.size())) { 74 t->PrintLine("Failed to run AEAD."); 75 return false; 76 } 77 out.resize(out_len); 78 79 if (out.size() != ct.size() + tag.size()) { 80 t->PrintLine("Bad output length: %u vs %u.", (unsigned)out_len, 81 (unsigned)(ct.size() + tag.size())); 82 return false; 83 } 84 if (!t->ExpectBytesEqual(ct.data(), ct.size(), out.data(), ct.size()) || 85 !t->ExpectBytesEqual(tag.data(), tag.size(), out.data() + ct.size(), 86 tag.size())) { 87 return false; 88 } 89 } else { 90 out.resize(ct.size() + tag.size()); 91 OPENSSL_memcpy(out.data(), ct.data(), ct.size()); 92 OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size()); 93 } 94 95 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 96 // reset after each operation. 97 ctx.Reset(); 98 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 99 tag.size(), evp_aead_open)) { 100 t->PrintLine("Failed to init AEAD."); 101 return false; 102 } 103 104 std::vector<uint8_t> out2(out.size()); 105 size_t out2_len; 106 int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), 107 nonce.data(), nonce.size(), out.data(), 108 out.size(), ad.data(), ad.size()); 109 if (t->HasAttribute("FAILS")) { 110 if (ret) { 111 t->PrintLine("Decrypted bad data."); 112 return false; 113 } 114 ERR_clear_error(); 115 return true; 116 } 117 118 if (!ret) { 119 t->PrintLine("Failed to decrypt."); 120 return false; 121 } 122 out2.resize(out2_len); 123 if (!t->ExpectBytesEqual(in.data(), in.size(), out2.data(), out2.size())) { 124 return false; 125 } 126 127 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 128 // reset after each operation. 129 ctx.Reset(); 130 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 131 tag.size(), evp_aead_open)) { 132 t->PrintLine("Failed to init AEAD."); 133 return false; 134 } 135 136 // Garbage at the end isn't ignored. 137 out.push_back(0); 138 out2.resize(out.size()); 139 if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), 140 nonce.data(), nonce.size(), out.data(), out.size(), 141 ad.data(), ad.size())) { 142 t->PrintLine("Decrypted bad data with trailing garbage."); 143 return false; 144 } 145 ERR_clear_error(); 146 147 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 148 // reset after each operation. 149 ctx.Reset(); 150 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), 151 tag.size(), evp_aead_open)) { 152 t->PrintLine("Failed to init AEAD."); 153 return false; 154 } 155 156 // Verify integrity is checked. 157 out[0] ^= 0x80; 158 out.resize(out.size() - 1); 159 out2.resize(out.size()); 160 if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), 161 nonce.data(), nonce.size(), out.data(), out.size(), 162 ad.data(), ad.size())) { 163 t->PrintLine("Decrypted bad data with corrupted byte."); 164 return false; 165 } 166 ERR_clear_error(); 167 168 return true; 169 } 170 171 static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) { 172 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; 173 OPENSSL_memset(key, 0, sizeof(key)); 174 const size_t key_len = EVP_AEAD_key_length(aead); 175 assert(sizeof(key) >= key_len); 176 177 EVP_AEAD_CTX ctx; 178 if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, 179 9999 /* a silly tag length to trigger an error */, 180 NULL /* ENGINE */) != 0) { 181 fprintf(stderr, "A silly tag length didn't trigger an error!\n"); 182 return 0; 183 } 184 ERR_clear_error(); 185 186 /* Running a second, failed _init should not cause a memory leak. */ 187 if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, 188 9999 /* a silly tag length to trigger an error */, 189 NULL /* ENGINE */) != 0) { 190 fprintf(stderr, "A silly tag length didn't trigger an error!\n"); 191 return 0; 192 } 193 ERR_clear_error(); 194 195 /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a 196 * no-op. */ 197 EVP_AEAD_CTX_cleanup(&ctx); 198 return 1; 199 } 200 201 static int TestTruncatedTags(const EVP_AEAD *aead) { 202 uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; 203 OPENSSL_memset(key, 0, sizeof(key)); 204 const size_t key_len = EVP_AEAD_key_length(aead); 205 assert(sizeof(key) >= key_len); 206 207 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; 208 OPENSSL_memset(nonce, 0, sizeof(nonce)); 209 const size_t nonce_len = EVP_AEAD_nonce_length(aead); 210 assert(sizeof(nonce) >= nonce_len); 211 212 bssl::ScopedEVP_AEAD_CTX ctx; 213 if (!EVP_AEAD_CTX_init(ctx.get(), aead, key, key_len, 1 /* one byte tag */, 214 NULL /* ENGINE */)) { 215 fprintf(stderr, "Couldn't initialise AEAD with truncated tag.\n"); 216 return 1; 217 } 218 219 const uint8_t plaintext[1] = {'A'}; 220 221 uint8_t ciphertext[128]; 222 size_t ciphertext_len; 223 constexpr uint8_t kSentinel = 42; 224 OPENSSL_memset(ciphertext, kSentinel, sizeof(ciphertext)); 225 226 if (!EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len, 227 sizeof(ciphertext), nonce, nonce_len, plaintext, 228 sizeof(plaintext), nullptr /* ad */, 0)) { 229 fprintf(stderr, "Sealing with truncated tag didn't work.\n"); 230 return 0; 231 } 232 233 for (size_t i = ciphertext_len; i < sizeof(ciphertext); i++) { 234 // Sealing must not write past where it said it did. 235 if (ciphertext[i] != kSentinel) { 236 fprintf(stderr, "Sealing wrote off the end of the buffer.\n"); 237 return 0; 238 } 239 } 240 241 const size_t overhead_used = ciphertext_len - sizeof(plaintext); 242 if (overhead_used != 1) { 243 fprintf(stderr, "AEAD is probably ignoring request to truncate tags.\n"); 244 return 0; 245 } 246 247 uint8_t plaintext2[sizeof(plaintext) + 16]; 248 OPENSSL_memset(plaintext2, kSentinel, sizeof(plaintext2)); 249 250 size_t plaintext2_len; 251 if (!EVP_AEAD_CTX_open(ctx.get(), plaintext2, &plaintext2_len, 252 sizeof(plaintext2), nonce, nonce_len, ciphertext, 253 ciphertext_len, nullptr /* ad */, 0)) { 254 fprintf(stderr, "Opening with truncated tag didn't work.\n"); 255 return 0; 256 } 257 258 for (size_t i = plaintext2_len; i < sizeof(plaintext2); i++) { 259 // Likewise, opening should also stay within bounds. 260 if (plaintext2[i] != kSentinel) { 261 fprintf(stderr, "Opening wrote off the end of the buffer.\n"); 262 return 0; 263 } 264 } 265 266 if (plaintext2_len != sizeof(plaintext) || 267 OPENSSL_memcmp(plaintext2, plaintext, sizeof(plaintext)) != 0) { 268 fprintf(stderr, "Opening with truncated tag gave wrong result.\n"); 269 return 0; 270 } 271 272 return 1; 273 } 274 275 static bool TestWithAliasedBuffers(const EVP_AEAD *aead) { 276 const size_t key_len = EVP_AEAD_key_length(aead); 277 const size_t nonce_len = EVP_AEAD_nonce_length(aead); 278 const size_t max_overhead = EVP_AEAD_max_overhead(aead); 279 280 std::vector<uint8_t> key(key_len, 'a'); 281 bssl::ScopedEVP_AEAD_CTX ctx; 282 if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key_len, 283 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { 284 return false; 285 } 286 287 static const uint8_t kPlaintext[260] = 288 "testing123456testing123456testing123456testing123456testing123456testing" 289 "123456testing123456testing123456testing123456testing123456testing123456t" 290 "esting123456testing123456testing123456testing123456testing123456testing1" 291 "23456testing123456testing123456testing12345"; 292 const std::vector<size_t> offsets = { 293 0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63, 294 64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257, 295 }; 296 297 std::vector<uint8_t> nonce(nonce_len, 'b'); 298 std::vector<uint8_t> valid_encryption(sizeof(kPlaintext) + max_overhead); 299 size_t valid_encryption_len; 300 if (!EVP_AEAD_CTX_seal( 301 ctx.get(), valid_encryption.data(), &valid_encryption_len, 302 sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, 303 kPlaintext, sizeof(kPlaintext), nullptr, 0)) { 304 fprintf(stderr, "EVP_AEAD_CTX_seal failed with disjoint buffers.\n"); 305 return false; 306 } 307 308 // Test with out != in which we expect to fail. 309 std::vector<uint8_t> buffer(2 + valid_encryption_len); 310 uint8_t *in = buffer.data() + 1; 311 uint8_t *out1 = buffer.data(); 312 uint8_t *out2 = buffer.data() + 2; 313 314 OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext)); 315 size_t out_len; 316 if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len, 317 sizeof(kPlaintext) + max_overhead, nonce.data(), 318 nonce_len, in, sizeof(kPlaintext), nullptr, 0) || 319 EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len, 320 sizeof(kPlaintext) + max_overhead, nonce.data(), 321 nonce_len, in, sizeof(kPlaintext), nullptr, 0)) { 322 fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n"); 323 return false; 324 } 325 ERR_clear_error(); 326 327 OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len); 328 if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len, 329 nonce.data(), nonce_len, in, valid_encryption_len, 330 nullptr, 0) || 331 EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len, 332 nonce.data(), nonce_len, in, valid_encryption_len, 333 nullptr, 0)) { 334 fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n"); 335 return false; 336 } 337 ERR_clear_error(); 338 339 // Test with out == in, which we expect to work. 340 OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext)); 341 342 if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len, 343 sizeof(kPlaintext) + max_overhead, nonce.data(), 344 nonce_len, in, sizeof(kPlaintext), nullptr, 0)) { 345 fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n"); 346 return false; 347 } 348 349 if (out_len != valid_encryption_len || 350 OPENSSL_memcmp(in, valid_encryption.data(), out_len) != 0) { 351 fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n"); 352 return false; 353 } 354 355 OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len); 356 if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len, 357 nonce.data(), nonce_len, in, valid_encryption_len, 358 nullptr, 0)) { 359 fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n"); 360 return false; 361 } 362 363 if (out_len != sizeof(kPlaintext) || 364 OPENSSL_memcmp(in, kPlaintext, out_len) != 0) { 365 fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n"); 366 return false; 367 } 368 369 return true; 370 } 371 372 struct KnownAEAD { 373 const char name[40]; 374 const EVP_AEAD *(*func)(void); 375 // limited_implementation indicates that tests that assume a generic AEAD 376 // interface should not be performed. For example, the key-wrap AEADs only 377 // handle inputs that are a multiple of eight bytes in length and the 378 // SSLv3/TLS AEADs have the concept of direction. 379 bool limited_implementation; 380 // truncated_tags is true if the AEAD supports truncating tags to arbitrary 381 // lengths. 382 bool truncated_tags; 383 }; 384 385 static const struct KnownAEAD kAEADs[] = { 386 { "aes-128-gcm", EVP_aead_aes_128_gcm, false, true }, 387 { "aes-256-gcm", EVP_aead_aes_256_gcm, false, true }, 388 { "aes-128-gcm-siv", EVP_aead_aes_128_gcm_siv, false, false }, 389 { "aes-256-gcm-siv", EVP_aead_aes_256_gcm_siv, false, false }, 390 { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false, true }, 391 { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true, false }, 392 { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, true, false }, 393 { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls, true, false }, 394 { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls, true, false }, 395 { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv, true, false }, 396 { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls, true, false }, 397 { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls, true, false }, 398 { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls, true, false }, 399 { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, true, false }, 400 { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true, false }, 401 { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true, false }, 402 { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true, false }, 403 { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false, true }, 404 { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false, true }, 405 { "", NULL, false, false }, 406 }; 407 408 int main(int argc, char **argv) { 409 CRYPTO_library_init(); 410 411 if (argc != 3) { 412 fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]); 413 return 1; 414 } 415 416 const struct KnownAEAD *known_aead; 417 for (unsigned i = 0;; i++) { 418 known_aead = &kAEADs[i]; 419 if (known_aead->func == NULL) { 420 fprintf(stderr, "Unknown AEAD: %s\n", argv[1]); 421 return 2; 422 } 423 if (strcmp(known_aead->name, argv[1]) == 0) { 424 break; 425 } 426 } 427 428 const EVP_AEAD *const aead = known_aead->func(); 429 if (aead == NULL) { 430 // AEAD is not compiled in this configuration. 431 printf("PASS\n"); 432 return 0; 433 } 434 435 if (!TestCleanupAfterInitFailure(aead)) { 436 return 1; 437 } 438 439 if (known_aead->truncated_tags && !TestTruncatedTags(aead)) { 440 fprintf(stderr, "Truncated tags test failed for %s.\n", known_aead->name); 441 return 1; 442 } 443 444 if (!known_aead->limited_implementation && !TestWithAliasedBuffers(aead)) { 445 fprintf(stderr, "Aliased buffers test failed for %s.\n", known_aead->name); 446 return 1; 447 } 448 449 return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]); 450 } 451