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