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 
TestAEAD(FileTest * t,void * arg)38 static 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 
TestCleanupAfterInitFailure(const EVP_AEAD * aead)161 static 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 
195 struct AEADName {
196   const char name[40];
197   const EVP_AEAD *(*func)(void);
198 };
199 
200 static 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 
main(int argc,char ** argv)228 int 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