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 <stdio.h>
16 #include <string.h>
17 
18 #include <string>
19 #include <vector>
20 
21 #include <openssl/base64.h>
22 #include <openssl/crypto.h>
23 #include <openssl/err.h>
24 
25 #include "../internal.h"
26 
27 
28 enum encoding_relation {
29   // canonical indicates that the encoding is the expected encoding of the
30   // input.
31   canonical,
32   // valid indicates that the encoding is /a/ valid encoding of the input, but
33   // need not be the canonical one.
34   valid,
35   // invalid indicates that the encoded data is valid.
36   invalid,
37 };
38 
39 struct TestVector {
40   enum encoding_relation relation;
41   const char *decoded;
42   const char *encoded;
43 };
44 
45 // Test vectors from RFC 4648.
46 static const TestVector kTestVectors[] = {
47     {canonical, "", ""},
48     {canonical, "f", "Zg==\n"},
49     {canonical, "fo", "Zm8=\n"},
50     {canonical, "foo", "Zm9v\n"},
51     {canonical, "foob", "Zm9vYg==\n"},
52     {canonical, "fooba", "Zm9vYmE=\n"},
53     {canonical, "foobar", "Zm9vYmFy\n"},
54     {valid, "foobar", "Zm9vYmFy\n\n"},
55     {valid, "foobar", " Zm9vYmFy\n\n"},
56     {valid, "foobar", " Z m 9 v Y m F y\n\n"},
57     {invalid, "", "Zm9vYmFy=\n"},
58     {invalid, "", "Zm9vYmFy==\n"},
59     {invalid, "", "Zm9vYmFy===\n"},
60     {invalid, "", "Z"},
61     {invalid, "", "Z\n"},
62     {invalid, "", "ab!c"},
63     {invalid, "", "ab=c"},
64     {invalid, "", "abc"},
65 
66     {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
67      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"},
68     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
69      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"},
70     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
71      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"},
72     {invalid, "",
73      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"},
74     {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
75      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
76      "4eHh4eHh4\n"},
77     {canonical,
78      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
79      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
80      "4eHh4eHh4eHh4eA==\n"},
81     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
82      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh"
83      "4eHh4eHh4eHh4eA==\n"},
84     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
85      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e"
86      "Hh4eHh4eHh4eA==\n"},
87     {invalid, "",
88      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=="
89      "\neHh4eHh4eHh4eHh4eHh4eHh4\n"},
90 
91     // A '-' has traditionally been treated as the end of the data by OpenSSL
92     // and anything following would be ignored. BoringSSL does not accept this
93     // non-standard extension.
94     {invalid, "", "Zm9vYmFy-anythinggoes"},
95     {invalid, "", "Zm9vYmFy\n-anythinggoes"},
96 
97     // CVE-2015-0292
98     {invalid, "",
99      "ZW5jb2RlIG1lCg==========================================================="
100      "=======\n"},
101 };
102 
103 static const size_t kNumTests = OPENSSL_ARRAY_SIZE(kTestVectors);
104 
105 // RemoveNewlines returns a copy of |in| with all '\n' characters removed.
RemoveNewlines(const char * in)106 static std::string RemoveNewlines(const char *in) {
107   std::string ret;
108   const size_t in_len = strlen(in);
109 
110   for (size_t i = 0; i < in_len; i++) {
111     if (in[i] != '\n') {
112       ret.push_back(in[i]);
113     }
114   }
115 
116   return ret;
117 }
118 
TestEncodeBlock()119 static bool TestEncodeBlock() {
120   for (unsigned i = 0; i < kNumTests; i++) {
121     const TestVector *t = &kTestVectors[i];
122     if (t->relation != canonical) {
123       continue;
124     }
125 
126     const size_t decoded_len = strlen(t->decoded);
127     size_t max_encoded_len;
128     if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
129       fprintf(stderr, "#%u: EVP_EncodedLength failed\n", i);
130       return false;
131     }
132 
133     std::vector<uint8_t> out_vec(max_encoded_len);
134     uint8_t *out = out_vec.data();
135     size_t len = EVP_EncodeBlock(out, (const uint8_t *)t->decoded, decoded_len);
136 
137     std::string encoded(RemoveNewlines(t->encoded));
138     if (len != encoded.size() ||
139         OPENSSL_memcmp(out, encoded.data(), len) != 0) {
140       fprintf(stderr, "encode(\"%s\") = \"%.*s\", want \"%s\"\n",
141               t->decoded, (int)len, (const char*)out, encoded.c_str());
142       return false;
143     }
144   }
145 
146   return true;
147 }
148 
TestDecodeBase64()149 static bool TestDecodeBase64() {
150   size_t len;
151 
152   for (unsigned i = 0; i < kNumTests; i++) {
153     const TestVector *t = &kTestVectors[i];
154 
155     if (t->relation == valid) {
156       // The non-canonical encodings will generally have odd whitespace etc
157       // that |EVP_DecodeBase64| will reject.
158       continue;
159     }
160 
161     const std::string encoded(RemoveNewlines(t->encoded));
162     std::vector<uint8_t> out_vec(encoded.size());
163     uint8_t *out = out_vec.data();
164 
165     int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
166                               (const uint8_t *)encoded.data(), encoded.size());
167 
168     if (t->relation == invalid) {
169       if (ok) {
170         fprintf(stderr, "decode(\"%s\") didn't fail but should have\n",
171                 encoded.c_str());
172         return false;
173       }
174     } else if (t->relation == canonical) {
175       if (!ok) {
176         fprintf(stderr, "decode(\"%s\") failed\n", encoded.c_str());
177         return false;
178       }
179 
180       if (len != strlen(t->decoded) ||
181           OPENSSL_memcmp(out, t->decoded, len) != 0) {
182         fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
183                 encoded.c_str(), (int)len, (const char*)out, t->decoded);
184         return false;
185       }
186     }
187   }
188 
189   return true;
190 }
191 
TestDecodeBlock()192 static bool TestDecodeBlock() {
193   for (unsigned i = 0; i < kNumTests; i++) {
194     const TestVector *t = &kTestVectors[i];
195     if (t->relation != canonical) {
196       continue;
197     }
198 
199     std::string encoded(RemoveNewlines(t->encoded));
200 
201     std::vector<uint8_t> out_vec(encoded.size());
202     uint8_t *out = out_vec.data();
203 
204     // Test that the padding behavior of the deprecated API is preserved.
205     int ret =
206         EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size());
207     if (ret < 0) {
208       fprintf(stderr, "EVP_DecodeBlock(\"%s\") failed\n", t->encoded);
209       return false;
210     }
211     if (ret % 3 != 0) {
212       fprintf(stderr, "EVP_DecodeBlock did not ignore padding\n");
213       return false;
214     }
215     size_t expected_len = strlen(t->decoded);
216     if (expected_len % 3 != 0) {
217       ret -= 3 - (expected_len % 3);
218     }
219     if (static_cast<size_t>(ret) != strlen(t->decoded) ||
220         OPENSSL_memcmp(out, t->decoded, ret) != 0) {
221       fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
222               t->encoded, ret, (const char*)out, t->decoded);
223       return false;
224     }
225   }
226 
227   return true;
228 }
229 
TestEncodeDecode()230 static bool TestEncodeDecode() {
231   for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
232     const TestVector *t = &kTestVectors[test_num];
233 
234     EVP_ENCODE_CTX ctx;
235     const size_t decoded_len = strlen(t->decoded);
236 
237     if (t->relation == canonical) {
238       size_t max_encoded_len;
239       if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
240         fprintf(stderr, "#%u: EVP_EncodedLength failed\n", test_num);
241         return false;
242       }
243 
244       // EVP_EncodeUpdate will output new lines every 64 bytes of output so we
245       // need slightly more than |EVP_EncodedLength| returns. */
246       max_encoded_len += (max_encoded_len + 63) >> 6;
247       std::vector<uint8_t> out_vec(max_encoded_len);
248       uint8_t *out = out_vec.data();
249 
250       EVP_EncodeInit(&ctx);
251 
252       int out_len;
253       EVP_EncodeUpdate(&ctx, out, &out_len,
254                        reinterpret_cast<const uint8_t *>(t->decoded),
255                        decoded_len);
256       size_t total = out_len;
257 
258       EVP_EncodeFinal(&ctx, out + total, &out_len);
259       total += out_len;
260 
261       if (total != strlen(t->encoded) ||
262           OPENSSL_memcmp(out, t->encoded, total) != 0) {
263         fprintf(stderr, "#%u: EVP_EncodeUpdate produced different output: '%s' (%u)\n",
264                 test_num, out, static_cast<unsigned>(total));
265         return false;
266       }
267     }
268 
269     std::vector<uint8_t> out_vec(strlen(t->encoded));
270     uint8_t *out = out_vec.data();
271 
272     EVP_DecodeInit(&ctx);
273     int out_len;
274     size_t total = 0;
275     int ret = EVP_DecodeUpdate(&ctx, out, &out_len,
276                                reinterpret_cast<const uint8_t *>(t->encoded),
277                                strlen(t->encoded));
278     if (ret != -1) {
279       total = out_len;
280       ret = EVP_DecodeFinal(&ctx, out + total, &out_len);
281       total += out_len;
282     }
283 
284     switch (t->relation) {
285       case canonical:
286       case valid:
287         if (ret == -1) {
288           fprintf(stderr, "#%u: EVP_DecodeUpdate failed\n", test_num);
289           return false;
290         }
291         if (total != decoded_len ||
292             OPENSSL_memcmp(out, t->decoded, decoded_len)) {
293           fprintf(stderr, "#%u: EVP_DecodeUpdate produced incorrect output\n",
294                   test_num);
295           return false;
296         }
297         break;
298 
299       case invalid:
300         if (ret != -1) {
301           fprintf(stderr, "#%u: EVP_DecodeUpdate was successful but shouldn't have been\n", test_num);
302           return false;
303         }
304         break;
305     }
306   }
307 
308   return true;
309 }
310 
TestDecodeUpdateStreaming()311 static bool TestDecodeUpdateStreaming() {
312   for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
313     const TestVector *t = &kTestVectors[test_num];
314     if (t->relation == invalid) {
315       continue;
316     }
317 
318     const size_t encoded_len = strlen(t->encoded);
319 
320     std::vector<uint8_t> out(encoded_len);
321 
322     for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) {
323       size_t out_len = 0;
324       EVP_ENCODE_CTX ctx;
325       EVP_DecodeInit(&ctx);
326 
327       for (size_t i = 0; i < encoded_len;) {
328         size_t todo = encoded_len - i;
329         if (todo > chunk_size) {
330           todo = chunk_size;
331         }
332 
333         int bytes_written;
334         int ret = EVP_DecodeUpdate(
335             &ctx, out.data() + out_len, &bytes_written,
336             reinterpret_cast<const uint8_t *>(t->encoded + i), todo);
337         i += todo;
338 
339         switch (ret) {
340           case -1:
341             fprintf(stderr, "#%u: EVP_DecodeUpdate returned error\n", test_num);
342             return 0;
343           case 0:
344             out_len += bytes_written;
345             if (i == encoded_len ||
346                 (i + 1 == encoded_len && t->encoded[i] == '\n') ||
347                 /* If there was an '-' in the input (which means “EOF”) then
348                  * this loop will continue to test that |EVP_DecodeUpdate| will
349                  * ignore the remainder of the input. */
350                 strchr(t->encoded, '-') != nullptr) {
351               break;
352             }
353 
354             fprintf(stderr,
355                     "#%u: EVP_DecodeUpdate returned zero before end of "
356                     "encoded data\n",
357                     test_num);
358             return 0;
359           default:
360             out_len += bytes_written;
361         }
362       }
363 
364       int bytes_written;
365       int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
366       if (ret == -1) {
367         fprintf(stderr, "#%u: EVP_DecodeFinal returned error\n", test_num);
368         return 0;
369       }
370       out_len += bytes_written;
371 
372       if (out_len != strlen(t->decoded) ||
373           OPENSSL_memcmp(out.data(), t->decoded, out_len) != 0) {
374         fprintf(stderr, "#%u: incorrect output\n", test_num);
375         return 0;
376       }
377     }
378   }
379 
380   return true;
381 }
382 
main(void)383 int main(void) {
384   CRYPTO_library_init();
385 
386   if (!TestEncodeBlock() ||
387       !TestDecodeBase64() ||
388       !TestDecodeBlock() ||
389       !TestDecodeUpdateStreaming() ||
390       !TestEncodeDecode()) {
391     return 1;
392   }
393 
394   printf("PASS\n");
395   return 0;
396 }
397