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