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#include "../test/scoped_types.h" 26 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 195struct AEADName { 196 const char name[40]; 197 const EVP_AEAD *(*func)(void); 198}; 199 200static const struct AEADName kAEADs[] = { 201 { "aes-128-gcm", EVP_aead_aes_128_gcm }, 202 { "aes-256-gcm", EVP_aead_aes_256_gcm }, 203 { "chacha20-poly1305", EVP_aead_chacha20_poly1305 }, 204 { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old }, 205 { "rc4-md5-tls", EVP_aead_rc4_md5_tls }, 206 { "rc4-sha1-tls", EVP_aead_rc4_sha1_tls }, 207 { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls }, 208 { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv }, 209 { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls }, 210 { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls }, 211 { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv }, 212 { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls }, 213 { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls }, 214 { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls }, 215 { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv }, 216 { "rc4-md5-ssl3", EVP_aead_rc4_md5_ssl3 }, 217 { "rc4-sha1-ssl3", EVP_aead_rc4_sha1_ssl3 }, 218 { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3 }, 219 { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3 }, 220 { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3 }, 221 { "aes-128-key-wrap", EVP_aead_aes_128_key_wrap }, 222 { "aes-256-key-wrap", EVP_aead_aes_256_key_wrap }, 223 { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256 }, 224 { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256 }, 225 { "", NULL }, 226}; 227 228int main(int argc, char **argv) { 229 CRYPTO_library_init(); 230 231 if (argc != 3) { 232 fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]); 233 return 1; 234 } 235 236 const EVP_AEAD *aead; 237 for (unsigned i = 0;; i++) { 238 const struct AEADName &aead_name = kAEADs[i]; 239 if (aead_name.func == NULL) { 240 fprintf(stderr, "Unknown AEAD: %s\n", argv[1]); 241 return 2; 242 } 243 if (strcmp(aead_name.name, argv[1]) == 0) { 244 aead = aead_name.func(); 245 break; 246 } 247 } 248 249 if (!TestCleanupAfterInitFailure(aead)) { 250 return 1; 251 } 252 253 return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]); 254} 255