xref: /openbsd-src/regress/lib/libcrypto/base64/base64test.c (revision 7bb1a6cf33c70622e249876e749b4a7ea7b98384)
1*7bb1a6cfStb /*	$OpenBSD: base64test.c,v 1.10 2022/09/05 21:06:31 tb Exp $	*/
297f8c275Sjsing /*
397f8c275Sjsing  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
497f8c275Sjsing  *
597f8c275Sjsing  * Permission to use, copy, modify, and distribute this software for any
697f8c275Sjsing  * purpose with or without fee is hereby granted, provided that the above
797f8c275Sjsing  * copyright notice and this permission notice appear in all copies.
897f8c275Sjsing  *
997f8c275Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1097f8c275Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1197f8c275Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1297f8c275Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1397f8c275Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1497f8c275Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1597f8c275Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1697f8c275Sjsing  */
1797f8c275Sjsing 
1897f8c275Sjsing #include <openssl/bio.h>
1997f8c275Sjsing #include <openssl/evp.h>
2097f8c275Sjsing 
2197f8c275Sjsing #include <err.h>
2297f8c275Sjsing #include <stdio.h>
2359536ef3Sjsing #include <string.h>
247df9a849Smiod #include <sys/types.h>
2597f8c275Sjsing 
2697f8c275Sjsing #define BUF_SIZE 128
2797f8c275Sjsing 
2897f8c275Sjsing struct base64_test {
2997f8c275Sjsing 	const unsigned char in[BUF_SIZE];
3059536ef3Sjsing 	const ssize_t in_len;
3197f8c275Sjsing 	const unsigned char out[BUF_SIZE];
3259536ef3Sjsing 	const ssize_t out_len;
3359536ef3Sjsing 	const ssize_t valid_len;
3497f8c275Sjsing };
3597f8c275Sjsing 
3697f8c275Sjsing /*
3797f8c275Sjsing  * Many of these tests are based on those found in Go's encoding/base64 tests.
3897f8c275Sjsing  */
3997f8c275Sjsing struct base64_test base64_tests[] = {
4097f8c275Sjsing 
4197f8c275Sjsing 	/* RFC3548 examples. */
4297f8c275Sjsing 	{ "\x14\xfb\x9c\x03\xd9\x7e", 6, "FPucA9l+", 8, 6, },
4397f8c275Sjsing 	{ "\x14\xfb\x9c\x03\xd9", 5, "FPucA9k=", 8, 5, },
4497f8c275Sjsing 	{ "\x14\xfb\x9c\x03", 4, "FPucAw==", 8, 4, },
4597f8c275Sjsing 
4697f8c275Sjsing 	/* RFC4648 examples. */
4797f8c275Sjsing 	{ "", 0, "", 0, 0, },
4897f8c275Sjsing 	{ "f", 1, "Zg==", 4, 1, },
4997f8c275Sjsing 	{ "fo", 2, "Zm8=", 4, 2, },
5097f8c275Sjsing 	{ "foo", 3, "Zm9v", 4, 3, },
5197f8c275Sjsing 	{ "foob", 4, "Zm9vYg==", 8, 4, },
5297f8c275Sjsing 	{ "fooba", 5, "Zm9vYmE=", 8, 5, },
5397f8c275Sjsing 	{ "foobar", 6, "Zm9vYmFy", 8, 6, },
5497f8c275Sjsing 
5597f8c275Sjsing 	/* Wikipedia examples. */
5697f8c275Sjsing 	{ "sure.", 5, "c3VyZS4=", 8, 5, },
5797f8c275Sjsing 	{ "sure", 4, "c3VyZQ==", 8, 4, },
5897f8c275Sjsing 	{ "sur", 3, "c3Vy", 4, 3, },
5997f8c275Sjsing 	{ "su", 2, "c3U=", 4, 2, },
6097f8c275Sjsing 	{ "leasure.", 8, "bGVhc3VyZS4=", 12, 8, },
6197f8c275Sjsing 	{ "easure.", 7, "ZWFzdXJlLg==", 12, 7, },
6297f8c275Sjsing 	{ "asure.", 6, "YXN1cmUu", 8, 6, },
6397f8c275Sjsing 
6497f8c275Sjsing 	{ "abcd", 4, "YWJjZA==", 8, 4, },
6597f8c275Sjsing 
6697f8c275Sjsing 	{
6797f8c275Sjsing 		"Twas brillig, and the slithy toves",
6897f8c275Sjsing 		34,
6997f8c275Sjsing 		"VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
7097f8c275Sjsing 		48,
7197f8c275Sjsing 		34,
7297f8c275Sjsing 	},
7397f8c275Sjsing };
7497f8c275Sjsing 
7597f8c275Sjsing #define N_TESTS (sizeof(base64_tests) / sizeof(*base64_tests))
7697f8c275Sjsing 
7797f8c275Sjsing struct base64_test base64_nl_tests[] = {
7897f8c275Sjsing 
7997f8c275Sjsing 	/* Corrupt/invalid encodings. */
8097f8c275Sjsing 	{ "", -1, "", 0, 0, },
811363119fSjsing 	{ "", -1, "!!!!", 4, 0, },
821363119fSjsing 	{ "", -1, "====", 4, 0, },
831363119fSjsing 	{ "", -1, "x===", 4, 0, },
841363119fSjsing 	{ "", -1, "=AAA", 4, 0, },
851363119fSjsing 	{ "", -1, "A=AA", 4, 0, },
861363119fSjsing 	{ "", -1, "AA=A", 4, 0, },
8797f8c275Sjsing 	{ "", -1, "AA==A", 5, 0, },
881363119fSjsing 	{ "", -1, "AAA=AAAA", 8, 0, },
8997f8c275Sjsing 	{ "", -1, "AAAAA", 5, 0, },
9097f8c275Sjsing 	{ "", -1, "AAAAAA", 6, 0, },
9197f8c275Sjsing 	{ "", -1, "A=", 2, 0, },
9297f8c275Sjsing 	{ "", -1, "A==", 3, 0, },
9397f8c275Sjsing 	{ "", -1, "AA=", 3, 0, },
9497f8c275Sjsing 	{ "", -1, "AA==", 4, 1, },		/* XXX - output ix 0x0. */
9597f8c275Sjsing 	{ "", -1, "AAA=", 4, 2, },		/* XXX - output ix 2x 0x0. */
9697f8c275Sjsing 	{ "", -1, "AAAA", 4, 3, },		/* XXX - output ix 3x 0x0. */
9797f8c275Sjsing 	{ "", -1, "AAAAAA=", 7, 0, },
9897f8c275Sjsing 	{ "", -1, "YWJjZA=====", 11, 0, },
9997f8c275Sjsing 
10097f8c275Sjsing 
10197f8c275Sjsing 	/* Encodings with embedded CR/LF. */
10297f8c275Sjsing 	{ "sure", 4, "c3VyZQ==", 8, 4, },
10397f8c275Sjsing 	{ "sure", 4, "c3VyZQ==\r", 9, 4, },
10497f8c275Sjsing 	{ "sure", 4, "c3VyZQ==\n", 9, 4, },
10597f8c275Sjsing 	{ "sure", 4, "c3VyZQ==\r\n", 10, 4, },
10697f8c275Sjsing 	{ "sure", 4, "c3VyZ\r\nQ==", 10, 4, },
10797f8c275Sjsing 	{ "sure", 4, "c3V\ryZ\nQ==", 10, 4, },
10897f8c275Sjsing 	{ "sure", 4, "c3V\nyZ\rQ==", 10, 4, },
10997f8c275Sjsing 	{ "sure", 4, "c3VyZ\nQ==", 9, 4, },
11097f8c275Sjsing 	{ "sure", 4, "c3VyZQ\n==", 9, 4, },
11197f8c275Sjsing 	{ "sure", 4, "c3VyZQ=\n=", 9, 4, },
11297f8c275Sjsing 	{ "sure", 4, "c3VyZQ=\r\n\r\n=", 12, 4, },
11397f8c275Sjsing 
1141363119fSjsing 	{
1151363119fSjsing 		"",
1161363119fSjsing 		-1,
1171363119fSjsing 		"YWJjZA======================================================"
1181363119fSjsing 		"============",
1191363119fSjsing 		74,
1201363119fSjsing 		0,
1211363119fSjsing 	},
1224b98474bSinoguchi 
1234b98474bSinoguchi 	/* OpenSSL-1.1.1d test */
1244b98474bSinoguchi 	/* canonical */
1254b98474bSinoguchi 	{ "", 0, "", 0, 0, },
1264b98474bSinoguchi 	/* canonical */
1274b98474bSinoguchi 	{ "h", 1, "aA==\n", 5, 1, },
1284b98474bSinoguchi 	/* canonical */
1294b98474bSinoguchi 	{ "hello", 5, "aGVsbG8=\n", 9, 5, },
1304b98474bSinoguchi 	/* canonical */
1314b98474bSinoguchi 	{ "hello world!", 12, "aGVsbG8gd29ybGQh\n", 17, 12, },
1324b98474bSinoguchi 	/* canonical */
1334b98474bSinoguchi 	{ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xa0\xb0\xc0\xd0\xe0\xf0\x00", 17, "AAECAwQFBgcICaCwwNDg8AA=\n", 25, 17, },
1344b98474bSinoguchi 	/* invalid # Missing padding */
1354b98474bSinoguchi 	{ "", -1, "aGVsbG8", 7, 0, },
1364b98474bSinoguchi 	/* invalid */
1374b98474bSinoguchi 	{ "", -1, "aGVsbG8\n", 8, 0, },
1384b98474bSinoguchi 	/* valid # Tolerate missing newline */
1394b98474bSinoguchi 	{ "hello", -1, "aGVsbG8=", 8, 5, },
1404b98474bSinoguchi 	/* invalid # Don't tolerate extra trailing '=' */
1414b98474bSinoguchi 	{ "", -1, "aGVsbG8==\n", 10, 0, },
1424b98474bSinoguchi 	/* invalid */
1434b98474bSinoguchi 	{ "", -1, "aGVsbG8===\n", 11, 0, },
1444b98474bSinoguchi 	/* invalid # Don't tolerate data after '=' */
1454b98474bSinoguchi 	{ "", -1, "aGV=sbG8=\n", 10, 0, },
1464b98474bSinoguchi 	/* valid # Newlines are ignored */
1474b98474bSinoguchi 	{ "hello", -1, "aGV\nsbG8=\n", 10, 5, },
1484b98474bSinoguchi 	/* canonical */
1494b98474bSinoguchi 	{ "hello", 5, "\x61\x47\x56\x73\x62\x47\x38\x3d\x0a", 9, 5, },
1504b98474bSinoguchi 	/* invalid # Invalid characters */
1514b98474bSinoguchi 	{ "", -1, "\x61\x47\x56\x73\x62\x47\x38\x3d\x0a\x00", 10, 0, },
1524b98474bSinoguchi 	/* invalid */
1534b98474bSinoguchi 	{ "", -1, "\x61\x47\x56\x00\x73\x62\x47\x38\x3d\x0a", 10, 0, },
1544b98474bSinoguchi 	/* invalid */
1554b98474bSinoguchi 	{ "", -1, "\x61\x47\x56\x01\x73\x62\x47\x38\x3d\x0a", 10, 0, },
1564b98474bSinoguchi 	/* invalid */
1574b98474bSinoguchi 	{ "", -1, "\x61\x47\x56\x80\x73\x62\x47\x38\x3d\x0a", 10, 0, },
1584b98474bSinoguchi 	/* invalid */
1594b98474bSinoguchi 	{ "", -1, "\xe1\x47\x56\x73\x62\x47\x38\x3d\x0a", 9, 0, },
1604b98474bSinoguchi 	/* canonical */
1614b98474bSinoguchi 	{ "OpenSSLOpenSSL\n", 15, "T3BlblNTTE9wZW5TU0wK\n", 21, 15, },
1624b98474bSinoguchi 	/* valid */
1634b98474bSinoguchi 	{ "OpenSSLOpenSSL\n", -1, "T3BlblNTTE9wZW5TU0wK", 20, 15, },
1644b98474bSinoguchi 	/* invalid # Truncate 1-3 chars */
1654b98474bSinoguchi 	{ "", -1, "T3BlblNTTE9wZW5TU0w", 19, 0, },
1664b98474bSinoguchi 	/* invalid */
1674b98474bSinoguchi 	{ "", -1, "T3BlblNTTE9wZW5TU0", 18, 0, },
1684b98474bSinoguchi 	/* invalid */
1694b98474bSinoguchi 	{ "", -1, "T3BlblNTTE9wZW5TU", 17, 0, },
1704b98474bSinoguchi 	/* invalid */
1714b98474bSinoguchi 	{ "", -1, "T3BlblNTTE9wZW5TU0wK====", 24, 0, },
1724b98474bSinoguchi 	/* invalid */
1734b98474bSinoguchi 	{ "", -1, "T3BlblNTTE9wZW5TU0wK============================================\n", 65, 0, },
1744b98474bSinoguchi 	/* invalid */
1754b98474bSinoguchi 	{ "", -1, "YQ==YQ==YQ==\n", 13, 0, },
1764b98474bSinoguchi 	/* invalid */
1774b98474bSinoguchi 	{ "", -1, "A", 1, 0, },
1784b98474bSinoguchi 	/* invalid */
1794b98474bSinoguchi 	{ "", -1, "A\n", 2, 0, },
1804b98474bSinoguchi 	/* invalid */
1814b98474bSinoguchi 	{ "", -1, "A=", 2, 0, },
1824b98474bSinoguchi 	/* invalid */
1834b98474bSinoguchi 	{ "", -1, "A==\n", 4, 0, },
1844b98474bSinoguchi 	/* invalid */
1854b98474bSinoguchi 	{ "", -1, "A===\n", 5, 0, },
1864b98474bSinoguchi 	/* invalid */
1874b98474bSinoguchi 	{ "", -1, "A====\n", 6, 0, },
1884b98474bSinoguchi 	/* valid */
1894b98474bSinoguchi 	{ "OpenSSLOpenSSL\n", -1, "T3BlblNTTE9wZW5TU0wK\n\n", 22, 15, },
1904b98474bSinoguchi 	/* valid */
1914b98474bSinoguchi 	{ "OpenSSLOpenSSL\n", -1, "T3BlblNTTE\n9wZW5TU0wK", 21, 15, },
1924b98474bSinoguchi 	/* invalid # CVE 2015-0292 */
1934b98474bSinoguchi 	{ "", -1, "ZW5jb2RlIG1lCg==================================================================\n", 81, 0, },
1944b98474bSinoguchi 	/* canonical */
1954b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 46, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n", 65, 46, },
1964b98474bSinoguchi 	/* valid */
1974b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n", 66, 46, },
1984b98474bSinoguchi 	/* valid */
1994b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n", 66, 46, },
2004b98474bSinoguchi 	/* invalid */
2014b98474bSinoguchi 	{ "", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA====\n", 67, 0, },
2024b98474bSinoguchi 	/* canonical # Multiline output without padding */
2034b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 60, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh4eHh4eHh4\n", 82, 60, },
2044b98474bSinoguchi 	/* canonical # Multiline output with padding */
2054b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 64, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh4eHh4eHh4eHh4eA==\n", 90, 64, },
2064b98474bSinoguchi 	/* valid # Multiline output with line break in the middle of a b64 block is accepted */
2074b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh4eHh4eHh4eHh4eA==\n", 90, 64, },
2084b98474bSinoguchi 	/* valid # Long lines are accepted */
2094b98474bSinoguchi 	{ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n", 89, 64, },
2104b98474bSinoguchi 	/* invalid # Multiline input with data after '='. */
2114b98474bSinoguchi 	{ "", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\neHh4eHh4eHh4eHh4eHh4eHh4\n", 90, 0, },
2124b98474bSinoguchi 	/* invalid */
2134b98474bSinoguchi 	{ "", -1, "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neA==eHh4eHh4eHh4eHh4eHh4\n", 90, 0, },
2144b98474bSinoguchi 	/* valid # B64_EOF ('-') terminates input and trailing bytes are ignored */
2154b98474bSinoguchi 	{ "OpenSSLOpenSSL\n", -1, "T3BlblNTTE9wZW5TU0wK\n-abcd", 26, 15, },
2164b98474bSinoguchi 	/* valid */
2174b98474bSinoguchi 	{ "OpenSSLOpenSSL\n", -1, "T3BlblNTTE9wZW5TU0wK-abcd", 25, 15, },
21897f8c275Sjsing };
21997f8c275Sjsing 
22097f8c275Sjsing #define N_NL_TESTS (sizeof(base64_nl_tests) / sizeof(*base64_nl_tests))
22197f8c275Sjsing 
22297f8c275Sjsing struct base64_test base64_no_nl_tests[] = {
22397f8c275Sjsing 
22497f8c275Sjsing 	/*
22597f8c275Sjsing 	 * In non-newline mode, the output resulting from corrupt/invalid
22697f8c275Sjsing 	 * encodings is completely crazy. A number of zero bytes is returned
22797f8c275Sjsing 	 * rather than nothing.
22897f8c275Sjsing 	 */
22997f8c275Sjsing 
23097f8c275Sjsing 	/* Corrupt/invalid encodings. */
23197f8c275Sjsing 	{ "", -1, "", 0, 0, },
2321363119fSjsing 	{ "", -1, "!!!!", 4, 0, },
23397f8c275Sjsing 	{ "", -1, "====", 4, 1, },
23497f8c275Sjsing 	{ "", -1, "x===", 4, 1, },
23597f8c275Sjsing 	{ "", -1, "=AAA", 4, 3, },
23697f8c275Sjsing 	{ "", -1, "A=AA", 4, 3, },
23797f8c275Sjsing 	{ "", -1, "AA=A", 4, 3, },
23897f8c275Sjsing 	{ "", -1, "AA==A", 5, 1, },
23997f8c275Sjsing 	{ "", -1, "AAA=AAAA", 8, 6, },
24097f8c275Sjsing 	{ "", -1, "AAAAA", 5, 3, },
24197f8c275Sjsing 	{ "", -1, "AAAAAA", 6, 3, },
24297f8c275Sjsing 	{ "", -1, "A=", 2, 0, },
24397f8c275Sjsing 	{ "", -1, "A==", 3, 0, },
24497f8c275Sjsing 	{ "", -1, "AA=", 3, 0, },
24597f8c275Sjsing 	{ "", -1, "AA==", 4, 1, },
24697f8c275Sjsing 	{ "", -1, "AAA=", 4, 2, },
24797f8c275Sjsing 	{ "", -1, "AAAA", 4, 3, },
24897f8c275Sjsing 	{ "", -1, "AAAAAA=", 7, 3, },
24997f8c275Sjsing 	{ "", -1, "YWJjZA=====", 11, 4, },
25097f8c275Sjsing 
25197f8c275Sjsing 	/* Encodings with embedded CR/LF. */
25297f8c275Sjsing 	{ "sure", 4, "c3VyZQ==", 8, 4, },
25397f8c275Sjsing 	{ "sure", 4, "c3VyZQ==\r", 9, 4, },
25497f8c275Sjsing 	{ "sure", 4, "c3VyZQ==\n", 9, 4, },
25597f8c275Sjsing 	{ "sure", 4, "c3VyZQ==\r\n", 10, 4, },
25697f8c275Sjsing 	{ "sure", -1, "c3VyZ\r\nQ==", 10, 0, },
25797f8c275Sjsing 	{ "sure", -1, "c3V\ryZ\nQ==", 10, 0, },
25897f8c275Sjsing 	{ "sure", -1, "c3V\nyZ\rQ==", 10, 0, },
25997f8c275Sjsing 	{ "sure", -1, "c3VyZ\nQ==", 9, 0, },
26097f8c275Sjsing 	{ "sure", -1, "c3VyZQ\n==", 9, 0, },
26197f8c275Sjsing 	{ "sure", -1, "c3VyZQ=\n=", 9, 0, },
26297f8c275Sjsing 	{ "sure", -1, "c3VyZQ=\r\n\r\n=", 12, 0, },
26397f8c275Sjsing 
2641363119fSjsing 	/*
2651363119fSjsing 	 * This is invalid, yet results in 'abcd' followed by a stream of
2661363119fSjsing 	 * zero value bytes.
2671363119fSjsing 	 */
2681363119fSjsing 	{
2691363119fSjsing 		"",
2701363119fSjsing 		-1,
2711363119fSjsing 		"YWJjZA======================================================"
2721363119fSjsing 		"============",
2731363119fSjsing 		74,
2741363119fSjsing 		52,
2751363119fSjsing 	},
27697f8c275Sjsing };
27797f8c275Sjsing 
27897f8c275Sjsing #define N_NO_NL_TESTS (sizeof(base64_no_nl_tests) / sizeof(*base64_no_nl_tests))
27997f8c275Sjsing 
28059536ef3Sjsing static int
base64_encoding_test(int test_no,struct base64_test * bt,int test_nl)28197f8c275Sjsing base64_encoding_test(int test_no, struct base64_test *bt, int test_nl)
28297f8c275Sjsing {
28397f8c275Sjsing 	BIO *bio_b64, *bio_mem;
28497f8c275Sjsing 	unsigned char *buf, *out;
28559536ef3Sjsing 	ssize_t i, len, b64len;
28697f8c275Sjsing 	int failure = 0;
28797f8c275Sjsing 
28897f8c275Sjsing 	buf = malloc(BUF_SIZE);
28997f8c275Sjsing 	if (buf == NULL)
29097f8c275Sjsing 		errx(1, "malloc");
29197f8c275Sjsing 
29297f8c275Sjsing 	bio_b64 = BIO_new(BIO_f_base64());
29397f8c275Sjsing 	if (bio_b64 == NULL)
29497f8c275Sjsing 		errx(1, "BIO_new failed for BIO_f_base64");
29597f8c275Sjsing 
29697f8c275Sjsing 	bio_mem = BIO_new(BIO_s_mem());
29797f8c275Sjsing 	if (bio_mem == NULL)
29897f8c275Sjsing 		errx(1, "BIO_new failed for BIO_s_mem");
29997f8c275Sjsing 
30097f8c275Sjsing 	bio_mem = BIO_push(bio_b64, bio_mem);
30197f8c275Sjsing 
30297f8c275Sjsing 	if (!test_nl)
30397f8c275Sjsing 		BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
30497f8c275Sjsing 
30597f8c275Sjsing 	len = BIO_write(bio_mem, bt->in, bt->in_len);
30697f8c275Sjsing 	if (len != bt->in_len) {
307*7bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - only wrote %zd out of %zd "
30897f8c275Sjsing 		    "characters\n", test_no, len, bt->in_len);
30997f8c275Sjsing 		failure = 1;
31097f8c275Sjsing 		goto done;
31197f8c275Sjsing 	}
31297f8c275Sjsing 	if (BIO_flush(bio_mem) < 0) {
313*7bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - flush failed\n", test_no);
31497f8c275Sjsing 		failure = 1;
31597f8c275Sjsing 		goto done;
31697f8c275Sjsing 	}
31797f8c275Sjsing 
31897f8c275Sjsing 	b64len = 0;
31997f8c275Sjsing 	for (i = 0; i < bt->out_len; i++) {
3209d21d53cSinoguchi 		if ((!test_nl ||
3219d21d53cSinoguchi 		    (test_nl && (i % 64 != 0 || i == bt->out_len - 1))) &&
3229d21d53cSinoguchi 		    (bt->out[i] == '\r' || bt->out[i] == '\n'))
32397f8c275Sjsing 			continue;
32497f8c275Sjsing 		buf[b64len++] = bt->out[i];
32597f8c275Sjsing 	}
32697f8c275Sjsing 	if (test_nl)
32797f8c275Sjsing 		buf[b64len++] = '\n';
32897f8c275Sjsing 
32997f8c275Sjsing 	len = BIO_get_mem_data(bio_mem, &out);
33097f8c275Sjsing 
33197f8c275Sjsing 	/* An empty string with NL results in no output, rather than '\n'. */
33297f8c275Sjsing 	if (test_nl && b64len == 1 && len == 0)
33397f8c275Sjsing 		goto done;
33497f8c275Sjsing 
33597f8c275Sjsing 	if (len != b64len) {
336*7bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - encoding resulted in %zd "
337*7bb1a6cfStb 		    "characters instead of %zd\n", test_no, len, b64len);
33897f8c275Sjsing 		failure = 1;
33997f8c275Sjsing 		goto done;
34097f8c275Sjsing 	}
34197f8c275Sjsing 
34297f8c275Sjsing 	if (memcmp(buf, out, b64len) != 0) {
343*7bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - encoding differs:\n", test_no);
34497f8c275Sjsing 		fprintf(stderr, "  encoding: ");
34597f8c275Sjsing 		for (i = 0; i < len; i++)
34697f8c275Sjsing 			fprintf(stderr, "%c", out[i]);
34797f8c275Sjsing 		fprintf(stderr, "\n");
34897f8c275Sjsing 		fprintf(stderr, " test data: ");
34997f8c275Sjsing 		for (i = 0; i < bt->out_len; i++)
35097f8c275Sjsing 			fprintf(stderr, "%c", buf[i]);
35197f8c275Sjsing 		fprintf(stderr, "\n");
35297f8c275Sjsing 		failure = 1;
35397f8c275Sjsing 	}
35497f8c275Sjsing 
35597f8c275Sjsing done:
35697f8c275Sjsing 	BIO_free_all(bio_mem);
35797f8c275Sjsing 	free(buf);
35897f8c275Sjsing 
35997f8c275Sjsing 	return failure;
36097f8c275Sjsing }
36197f8c275Sjsing 
36259536ef3Sjsing static int
base64_decoding_test(int test_no,struct base64_test * bt,int test_nl)36397f8c275Sjsing base64_decoding_test(int test_no, struct base64_test *bt, int test_nl)
36497f8c275Sjsing {
36597f8c275Sjsing 	BIO *bio_b64, *bio_mem;
36697f8c275Sjsing 	char *buf, *input;
36759536ef3Sjsing 	ssize_t i, inlen, len;
36897f8c275Sjsing 	int failure = 0;
36997f8c275Sjsing 
37097f8c275Sjsing 	buf = malloc(BUF_SIZE);
37197f8c275Sjsing 	if (buf == NULL)
37297f8c275Sjsing 		errx(1, "malloc");
37397f8c275Sjsing 
3749d21d53cSinoguchi 	if ((input = malloc(BUF_SIZE)) == NULL)
3759d21d53cSinoguchi 		errx(1, "malloc");
3769d21d53cSinoguchi 
3779d21d53cSinoguchi 	memcpy(input, bt->out, bt->out_len);
37897f8c275Sjsing 	inlen = bt->out_len;
3799d21d53cSinoguchi 	if (test_nl) {
3809d21d53cSinoguchi 		memcpy(&input[bt->out_len], "\r\n", 2);
3819d21d53cSinoguchi 		inlen += 2;
3829d21d53cSinoguchi 	}
383fe8a344bSderaadt 
38497f8c275Sjsing 	bio_mem = BIO_new_mem_buf(input, inlen);
38597f8c275Sjsing 	if (bio_mem == NULL)
38697f8c275Sjsing 		errx(1, "BIO_new_mem_buf failed");
38797f8c275Sjsing 
38897f8c275Sjsing 	bio_b64 = BIO_new(BIO_f_base64());
38997f8c275Sjsing 	if (bio_b64 == NULL)
39097f8c275Sjsing 		errx(1, "BIO_new failed for BIO_f_base64");
39197f8c275Sjsing 
39297f8c275Sjsing 	if (!test_nl)
39397f8c275Sjsing 		BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
39497f8c275Sjsing 
39597f8c275Sjsing 	bio_mem = BIO_push(bio_b64, bio_mem);
39697f8c275Sjsing 
39797f8c275Sjsing 	/*
39897f8c275Sjsing 	 * If we wrote zero characters then a BIO_read will result in a return
39997f8c275Sjsing 	 * value of -1, hence we need to handle this case.
40097f8c275Sjsing 	 */
40197f8c275Sjsing 	len = BIO_read(bio_mem, buf, BUF_SIZE);
40297f8c275Sjsing 	if (len != bt->valid_len && (bt->in_len != 0 || len != -1)) {
403*7bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - decoding resulted in %zd "
404*7bb1a6cfStb 		    "characters instead of %zd\n", test_no, len, bt->valid_len);
40597f8c275Sjsing 		fprintf(stderr, "  input: ");
40697f8c275Sjsing 		for (i = 0; i < inlen; i++)
40797f8c275Sjsing 			fprintf(stderr, "%c", input[i]);
40897f8c275Sjsing 		fprintf(stderr, "\n");
40997f8c275Sjsing 		fprintf(stderr, "  decoding: ");
41097f8c275Sjsing 		for (i = 0; i < len; i++)
41197f8c275Sjsing 			fprintf(stderr, "0x%x ", buf[i]);
41297f8c275Sjsing 		fprintf(stderr, "\n");
41397f8c275Sjsing 		failure = 1;
41497f8c275Sjsing 		goto done;
41597f8c275Sjsing 	}
41697f8c275Sjsing 
41797f8c275Sjsing 	/* See if we expect this to fail decoding. */
41897f8c275Sjsing 	if (bt->in_len == -1)
41997f8c275Sjsing 		goto done;
42097f8c275Sjsing 
42197f8c275Sjsing 	if (memcmp(bt->in, buf, bt->in_len) != 0) {
422*7bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - decoding differs:\n", test_no);
42397f8c275Sjsing 		fprintf(stderr, "  decoding: ");
42497f8c275Sjsing 		for (i = 0; i < len; i++)
42597f8c275Sjsing 			fprintf(stderr, "0x%x ", buf[i]);
42697f8c275Sjsing 		fprintf(stderr, "\n");
42797f8c275Sjsing 		fprintf(stderr, " test data: ");
4289d21d53cSinoguchi 		for (i = 0; i < bt->in_len; i++)
4299d21d53cSinoguchi 			fprintf(stderr, "0x%x ", bt->in[i]);
43097f8c275Sjsing 		fprintf(stderr, "\n");
43197f8c275Sjsing 		failure = 1;
43297f8c275Sjsing 	}
43397f8c275Sjsing 
43497f8c275Sjsing done:
43597f8c275Sjsing 	BIO_free_all(bio_mem);
43697f8c275Sjsing 	free(buf);
43797f8c275Sjsing 	free(input);
43897f8c275Sjsing 
43997f8c275Sjsing 	return failure;
44097f8c275Sjsing }
44197f8c275Sjsing 
44297f8c275Sjsing int
main(int argc,char ** argv)44397f8c275Sjsing main(int argc, char **argv)
44497f8c275Sjsing {
44597f8c275Sjsing 	struct base64_test *bt;
44697f8c275Sjsing 	int failed = 0;
44759536ef3Sjsing 	size_t i;
44897f8c275Sjsing 
44997f8c275Sjsing 	fprintf(stderr, "Starting combined tests...\n");
45097f8c275Sjsing 
45197f8c275Sjsing 	for (i = 0; i < N_TESTS; i++) {
45297f8c275Sjsing 		bt = &base64_tests[i];
45397f8c275Sjsing 		if (bt->in_len != -1)
45497f8c275Sjsing 			failed += base64_encoding_test(i, bt, 0);
45597f8c275Sjsing 		if (bt->out_len != -1)
45697f8c275Sjsing 			failed += base64_decoding_test(i, bt, 0);
45797f8c275Sjsing 		if (bt->in_len != -1)
45897f8c275Sjsing 			failed += base64_encoding_test(i, bt, 1);
45997f8c275Sjsing 		if (bt->out_len != -1)
46097f8c275Sjsing 			failed += base64_decoding_test(i, bt, 1);
46197f8c275Sjsing 	}
46297f8c275Sjsing 
46397f8c275Sjsing 	fprintf(stderr, "Starting NL tests...\n");
46497f8c275Sjsing 
46597f8c275Sjsing 	for (i = 0; i < N_NL_TESTS; i++) {
46697f8c275Sjsing 		bt = &base64_nl_tests[i];
46797f8c275Sjsing 
46897f8c275Sjsing 		if (bt->in_len != -1)
46997f8c275Sjsing 			failed += base64_encoding_test(i, bt, 1);
47097f8c275Sjsing 		if (bt->out_len != -1)
47197f8c275Sjsing 			failed += base64_decoding_test(i, bt, 1);
47297f8c275Sjsing 	}
47397f8c275Sjsing 
47497f8c275Sjsing 	fprintf(stderr, "Starting NO NL tests...\n");
47597f8c275Sjsing 
47697f8c275Sjsing 	for (i = 0; i < N_NO_NL_TESTS; i++) {
47797f8c275Sjsing 		bt = &base64_no_nl_tests[i];
47897f8c275Sjsing 
47997f8c275Sjsing 		if (bt->in_len != -1)
48097f8c275Sjsing 			failed += base64_encoding_test(i, bt, 0);
48197f8c275Sjsing 		if (bt->out_len != -1)
48297f8c275Sjsing 			failed += base64_decoding_test(i, bt, 0);
48397f8c275Sjsing 	}
48497f8c275Sjsing 
48597f8c275Sjsing 	return failed;
48697f8c275Sjsing }
487