aead_test.cc revision e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5
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/stl_compat.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 38// EVP_AEAD_CTX lacks a zero state, so it doesn't fit easily into 39// ScopedOpenSSLContext. 40class EVP_AEAD_CTXScoper { 41 public: 42 EVP_AEAD_CTXScoper(EVP_AEAD_CTX *ctx) : ctx_(ctx) {} 43 ~EVP_AEAD_CTXScoper() { 44 EVP_AEAD_CTX_cleanup(ctx_); 45 } 46 private: 47 EVP_AEAD_CTX *ctx_; 48}; 49 50static bool TestAEAD(FileTest *t, void *arg) { 51 const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg); 52 53 std::vector<uint8_t> key, nonce, in, ad, ct, tag; 54 if (!t->GetBytes(&key, "KEY") || 55 !t->GetBytes(&nonce, "NONCE") || 56 !t->GetBytes(&in, "IN") || 57 !t->GetBytes(&ad, "AD") || 58 !t->GetBytes(&ct, "CT") || 59 !t->GetBytes(&tag, "TAG")) { 60 return false; 61 } 62 63 EVP_AEAD_CTX ctx; 64 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key), 65 key.size(), tag.size(), 66 evp_aead_seal)) { 67 t->PrintLine("Failed to init AEAD."); 68 return false; 69 } 70 EVP_AEAD_CTXScoper cleanup(&ctx); 71 72 std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead)); 73 if (!t->HasAttribute("NO_SEAL")) { 74 size_t out_len; 75 if (!EVP_AEAD_CTX_seal(&ctx, bssl::vector_data(&out), &out_len, out.size(), 76 bssl::vector_data(&nonce), nonce.size(), 77 bssl::vector_data(&in), in.size(), 78 bssl::vector_data(&ad), ad.size())) { 79 t->PrintLine("Failed to run AEAD."); 80 return false; 81 } 82 out.resize(out_len); 83 84 if (out.size() != ct.size() + tag.size()) { 85 t->PrintLine("Bad output length: %u vs %u.", (unsigned)out_len, 86 (unsigned)(ct.size() + tag.size())); 87 return false; 88 } 89 if (!t->ExpectBytesEqual(bssl::vector_data(&ct), ct.size(), 90 bssl::vector_data(&out), ct.size()) || 91 !t->ExpectBytesEqual(bssl::vector_data(&tag), tag.size(), 92 bssl::vector_data(&out) + ct.size(), tag.size())) { 93 return false; 94 } 95 } else { 96 out.resize(ct.size() + tag.size()); 97 memcpy(bssl::vector_data(&out), bssl::vector_data(&ct), ct.size()); 98 memcpy(bssl::vector_data(&out) + ct.size(), bssl::vector_data(&tag), 99 tag.size()); 100 } 101 102 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 103 // reset after each operation. 104 EVP_AEAD_CTX_cleanup(&ctx); 105 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key), 106 key.size(), tag.size(), 107 evp_aead_open)) { 108 t->PrintLine("Failed to init AEAD."); 109 return false; 110 } 111 112 std::vector<uint8_t> out2(out.size()); 113 size_t out2_len; 114 int ret = EVP_AEAD_CTX_open(&ctx, 115 bssl::vector_data(&out2), &out2_len, out2.size(), 116 bssl::vector_data(&nonce), nonce.size(), 117 bssl::vector_data(&out), out.size(), 118 bssl::vector_data(&ad), ad.size()); 119 if (t->HasAttribute("FAILS")) { 120 if (ret) { 121 t->PrintLine("Decrypted bad data."); 122 return false; 123 } 124 ERR_clear_error(); 125 return true; 126 } 127 128 if (!ret) { 129 t->PrintLine("Failed to decrypt."); 130 return false; 131 } 132 out2.resize(out2_len); 133 if (!t->ExpectBytesEqual(bssl::vector_data(&in), in.size(), 134 bssl::vector_data(&out2), out2.size())) { 135 return false; 136 } 137 138 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 139 // reset after each operation. 140 EVP_AEAD_CTX_cleanup(&ctx); 141 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key), 142 key.size(), tag.size(), 143 evp_aead_open)) { 144 t->PrintLine("Failed to init AEAD."); 145 return false; 146 } 147 148 // Garbage at the end isn't ignored. 149 out.push_back(0); 150 out2.resize(out.size()); 151 if (EVP_AEAD_CTX_open(&ctx, bssl::vector_data(&out2), &out2_len, out2.size(), 152 bssl::vector_data(&nonce), nonce.size(), 153 bssl::vector_data(&out), out.size(), 154 bssl::vector_data(&ad), ad.size())) { 155 t->PrintLine("Decrypted bad data with trailing garbage."); 156 return false; 157 } 158 ERR_clear_error(); 159 160 // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be 161 // reset after each operation. 162 EVP_AEAD_CTX_cleanup(&ctx); 163 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key), 164 key.size(), tag.size(), 165 evp_aead_open)) { 166 t->PrintLine("Failed to init AEAD."); 167 return false; 168 } 169 170 // Verify integrity is checked. 171 out[0] ^= 0x80; 172 out.resize(out.size() - 1); 173 out2.resize(out.size()); 174 if (EVP_AEAD_CTX_open(&ctx, bssl::vector_data(&out2), &out2_len, out2.size(), 175 bssl::vector_data(&nonce), nonce.size(), 176 bssl::vector_data(&out), out.size(), 177 bssl::vector_data(&ad), ad.size())) { 178 t->PrintLine("Decrypted bad data with corrupted byte."); 179 return false; 180 } 181 ERR_clear_error(); 182 183 return true; 184} 185 186static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) { 187 EVP_AEAD_CTX ctx; 188 uint8_t key[128]; 189 190 memset(key, 0, sizeof(key)); 191 const size_t key_len = EVP_AEAD_key_length(aead); 192 if (key_len > sizeof(key)) { 193 fprintf(stderr, "Key length of AEAD too long.\n"); 194 return 0; 195 } 196 197 if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, 198 9999 /* a silly tag length to trigger an error */, 199 NULL /* ENGINE */) != 0) { 200 fprintf(stderr, "A silly tag length didn't trigger an error!\n"); 201 return 0; 202 } 203 204 /* Running a second, failed _init should not cause a memory leak. */ 205 if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, 206 9999 /* a silly tag length to trigger an error */, 207 NULL /* ENGINE */) != 0) { 208 fprintf(stderr, "A silly tag length didn't trigger an error!\n"); 209 return 0; 210 } 211 212 /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a 213 * no-op. */ 214 EVP_AEAD_CTX_cleanup(&ctx); 215 return 1; 216} 217 218struct AEADName { 219 const char name[40]; 220 const EVP_AEAD *(*func)(void); 221}; 222 223static const struct AEADName kAEADs[] = { 224 { "aes-128-gcm", EVP_aead_aes_128_gcm }, 225 { "aes-256-gcm", EVP_aead_aes_256_gcm }, 226 { "chacha20-poly1305", EVP_aead_chacha20_poly1305 }, 227 { "rc4-md5-tls", EVP_aead_rc4_md5_tls }, 228 { "rc4-sha1-tls", EVP_aead_rc4_sha1_tls }, 229 { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls }, 230 { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv }, 231 { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls }, 232 { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls }, 233 { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv }, 234 { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls }, 235 { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls }, 236 { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls }, 237 { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv }, 238 { "rc4-md5-ssl3", EVP_aead_rc4_md5_ssl3 }, 239 { "rc4-sha1-ssl3", EVP_aead_rc4_sha1_ssl3 }, 240 { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3 }, 241 { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3 }, 242 { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3 }, 243 { "aes-128-key-wrap", EVP_aead_aes_128_key_wrap }, 244 { "aes-256-key-wrap", EVP_aead_aes_256_key_wrap }, 245 { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256 }, 246 { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256 }, 247 { "", NULL }, 248}; 249 250int main(int argc, char **argv) { 251 CRYPTO_library_init(); 252 253 if (argc != 3) { 254 fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]); 255 return 1; 256 } 257 258 const EVP_AEAD *aead; 259 for (unsigned i = 0;; i++) { 260 const struct AEADName &aead_name = kAEADs[i]; 261 if (aead_name.func == NULL) { 262 fprintf(stderr, "Unknown AEAD: %s\n", argv[1]); 263 return 2; 264 } 265 if (strcmp(aead_name.name, argv[1]) == 0) { 266 aead = aead_name.func(); 267 break; 268 } 269 } 270 271 if (!TestCleanupAfterInitFailure(aead)) { 272 return 1; 273 } 274 275 return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]); 276} 277