1*e10c7425Sjsing /* $OpenBSD: rsa_padding_test.c,v 1.2 2024/03/30 02:20:39 jsing Exp $ */
26e3e576cSjsing /*
36e3e576cSjsing * Copyright (c) 2024 Joel Sing <jsing@openbsd.org>
46e3e576cSjsing *
56e3e576cSjsing * Permission to use, copy, modify, and distribute this software for any
66e3e576cSjsing * purpose with or without fee is hereby granted, provided that the above
76e3e576cSjsing * copyright notice and this permission notice appear in all copies.
86e3e576cSjsing *
96e3e576cSjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106e3e576cSjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116e3e576cSjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126e3e576cSjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136e3e576cSjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146e3e576cSjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156e3e576cSjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166e3e576cSjsing */
176e3e576cSjsing
186e3e576cSjsing #include <stdint.h>
196e3e576cSjsing #include <string.h>
206e3e576cSjsing
216e3e576cSjsing #include <openssl/err.h>
226e3e576cSjsing #include <openssl/rsa.h>
236e3e576cSjsing
246e3e576cSjsing #if 0
256e3e576cSjsing static void
266e3e576cSjsing hexdump(const unsigned char *buf, size_t len)
276e3e576cSjsing {
286e3e576cSjsing size_t i;
296e3e576cSjsing
306e3e576cSjsing for (i = 1; i <= len; i++)
316e3e576cSjsing fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
326e3e576cSjsing
336e3e576cSjsing fprintf(stderr, "\n");
346e3e576cSjsing }
356e3e576cSjsing #endif
366e3e576cSjsing
376e3e576cSjsing struct pkcs1_test {
386e3e576cSjsing uint8_t in[128];
396e3e576cSjsing size_t in_len;
406e3e576cSjsing int want;
416e3e576cSjsing int want_error;
426e3e576cSjsing };
436e3e576cSjsing
446e3e576cSjsing static const struct pkcs1_test pkcs1_type1_tests[] = {
456e3e576cSjsing {
466e3e576cSjsing .in = {
476e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
486e3e576cSjsing 0xff, 0xff, 0xff, 0xff, 0x00, 0x6f, 0x6f, 0x6f,
496e3e576cSjsing 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
506e3e576cSjsing 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
516e3e576cSjsing },
526e3e576cSjsing .in_len = 32,
536e3e576cSjsing .want = 19,
546e3e576cSjsing },
556e3e576cSjsing {
566e3e576cSjsing .in = {
576e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
586e3e576cSjsing 0xff, 0xff, 0x00,
596e3e576cSjsing },
606e3e576cSjsing .in_len = 11,
616e3e576cSjsing .want = 0,
626e3e576cSjsing },
636e3e576cSjsing {
646e3e576cSjsing .in = {
656e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
666e3e576cSjsing 0xff, 0xff, 0x00, 0xff,
676e3e576cSjsing },
686e3e576cSjsing .in_len = 12,
696e3e576cSjsing .want = 1,
706e3e576cSjsing },
716e3e576cSjsing {
726e3e576cSjsing /* Insufficient padding bytes (< 8). */
736e3e576cSjsing .in = {
746e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
756e3e576cSjsing 0xff, 0x00, 0xff, 0xff,
766e3e576cSjsing },
776e3e576cSjsing .in_len = 12,
786e3e576cSjsing .want = -1,
796e3e576cSjsing .want_error = RSA_R_BAD_PAD_BYTE_COUNT,
806e3e576cSjsing },
816e3e576cSjsing {
826e3e576cSjsing /* Incorrect padding type (0x00). */
836e3e576cSjsing .in = {
846e3e576cSjsing 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
856e3e576cSjsing 0xff, 0xff, 0x00, 0xff,
866e3e576cSjsing },
876e3e576cSjsing .in_len = 12,
886e3e576cSjsing .want = -1,
896e3e576cSjsing .want_error = RSA_R_BLOCK_TYPE_IS_NOT_01,
906e3e576cSjsing },
916e3e576cSjsing {
926e3e576cSjsing /* Incorrect padding type (0x02). */
936e3e576cSjsing .in = {
946e3e576cSjsing 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
956e3e576cSjsing 0xff, 0xff, 0x00, 0xff,
966e3e576cSjsing },
976e3e576cSjsing .in_len = 12,
986e3e576cSjsing .want = -1,
996e3e576cSjsing .want_error = RSA_R_BLOCK_TYPE_IS_NOT_01,
1006e3e576cSjsing },
1016e3e576cSjsing {
1026e3e576cSjsing /* Non-padding byte before end of padding marker. */
1036e3e576cSjsing .in = {
1046e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1056e3e576cSjsing 0xff, 0xfe, 0x00, 0xff,
1066e3e576cSjsing },
1076e3e576cSjsing .in_len = 12,
1086e3e576cSjsing .want = -1,
1096e3e576cSjsing .want_error = RSA_R_BAD_FIXED_HEADER_DECRYPT,
1106e3e576cSjsing },
1116e3e576cSjsing {
1126e3e576cSjsing /* No end of padding marker. */
1136e3e576cSjsing .in = {
1146e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1156e3e576cSjsing 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1166e3e576cSjsing 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1176e3e576cSjsing 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1186e3e576cSjsing },
1196e3e576cSjsing .in_len = 32,
1206e3e576cSjsing .want = -1,
1216e3e576cSjsing .want_error = RSA_R_NULL_BEFORE_BLOCK_MISSING,
1226e3e576cSjsing },
1236e3e576cSjsing };
1246e3e576cSjsing
1256e3e576cSjsing #define N_PKCS1_TYPE1_TESTS \
1266e3e576cSjsing (sizeof(pkcs1_type1_tests) / sizeof(pkcs1_type1_tests[0]))
1276e3e576cSjsing
1286e3e576cSjsing static int
test_pkcs1_type1(void)1296e3e576cSjsing test_pkcs1_type1(void)
1306e3e576cSjsing {
1316e3e576cSjsing const struct pkcs1_test *pt;
1326e3e576cSjsing uint8_t buf[32], in[19], out[512];
1336e3e576cSjsing int pad_len;
1346e3e576cSjsing long err;
1356e3e576cSjsing size_t i;
1366e3e576cSjsing int failed = 1;
1376e3e576cSjsing
138*e10c7425Sjsing for (i = 0; i < 1000; i++) {
139*e10c7425Sjsing arc4random_buf(in, sizeof(in));
1406e3e576cSjsing
141*e10c7425Sjsing if (!RSA_padding_add_PKCS1_type_1(buf, sizeof(buf), in,
142*e10c7425Sjsing sizeof(in))) {
143*e10c7425Sjsing fprintf(stderr, "FAIL: failed to add PKCS1 type 1 "
144*e10c7425Sjsing "padding\n");
1456e3e576cSjsing goto failed;
1466e3e576cSjsing }
1476e3e576cSjsing
1486e3e576cSjsing pad_len = RSA_padding_check_PKCS1_type_1(out, sizeof(out) - 1,
1496e3e576cSjsing buf + 1, sizeof(buf) - 1, sizeof(buf));
1506e3e576cSjsing if (pad_len != sizeof(in)) {
151*e10c7425Sjsing fprintf(stderr, "FAIL: failed to check PKCS1 type 1 "
152*e10c7425Sjsing "padding\n");
1536e3e576cSjsing ERR_print_errors_fp(stderr);
1546e3e576cSjsing goto failed;
1556e3e576cSjsing }
156*e10c7425Sjsing }
1576e3e576cSjsing
1586e3e576cSjsing for (i = 0; i < N_PKCS1_TYPE1_TESTS; i++) {
1596e3e576cSjsing pt = &pkcs1_type1_tests[i];
1606e3e576cSjsing
1616e3e576cSjsing ERR_clear_error();
1626e3e576cSjsing
1636e3e576cSjsing pad_len = RSA_padding_check_PKCS1_type_1(out, sizeof(out) - 1,
1646e3e576cSjsing pt->in + 1, pt->in_len - 1, pt->in_len);
1656e3e576cSjsing
1666e3e576cSjsing if (pad_len != pt->want) {
1676e3e576cSjsing fprintf(stderr, "FAIL: test %zu - failed to check "
1686e3e576cSjsing "PKCS1 type 1 padding (%d != %d)\n", i, pad_len,
1696e3e576cSjsing pt->want);
1706e3e576cSjsing ERR_print_errors_fp(stderr);
1716e3e576cSjsing goto failed;
1726e3e576cSjsing }
1736e3e576cSjsing
1746e3e576cSjsing err = ERR_peek_error();
1756e3e576cSjsing if (pt->want == -1 && ERR_GET_REASON(err) != pt->want_error) {
1766e3e576cSjsing fprintf(stderr, "FAIL: test %zu - PKCS1 type 1 padding "
1776e3e576cSjsing "check failed with error reason %i, want %i\n",
1786e3e576cSjsing i, ERR_GET_REASON(err), pt->want_error);
1796e3e576cSjsing ERR_print_errors_fp(stderr);
1806e3e576cSjsing goto failed;
1816e3e576cSjsing }
1826e3e576cSjsing }
1836e3e576cSjsing
1846e3e576cSjsing failed = 0;
1856e3e576cSjsing
1866e3e576cSjsing failed:
1876e3e576cSjsing return failed;
1886e3e576cSjsing }
1896e3e576cSjsing
1906e3e576cSjsing static const struct pkcs1_test pkcs1_type2_tests[] = {
1916e3e576cSjsing {
1926e3e576cSjsing .in = {
1936e3e576cSjsing 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1946e3e576cSjsing 0xff, 0xff, 0xff, 0xff, 0x00, 0x6f, 0x6f, 0x6f,
1956e3e576cSjsing 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1966e3e576cSjsing 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1976e3e576cSjsing },
1986e3e576cSjsing .in_len = 32,
1996e3e576cSjsing .want = 19,
2006e3e576cSjsing },
2016e3e576cSjsing {
2026e3e576cSjsing .in = {
2036e3e576cSjsing 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2046e3e576cSjsing 0xff, 0xff, 0x00,
2056e3e576cSjsing },
2066e3e576cSjsing .in_len = 11,
2076e3e576cSjsing .want = 0,
2086e3e576cSjsing },
2096e3e576cSjsing {
2106e3e576cSjsing .in = {
2116e3e576cSjsing 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2126e3e576cSjsing 0xff, 0xff, 0x00, 0xff,
2136e3e576cSjsing },
2146e3e576cSjsing .in_len = 12,
2156e3e576cSjsing .want = 1,
2166e3e576cSjsing },
2176e3e576cSjsing {
2186e3e576cSjsing /* Insufficient padding bytes (< 8). */
2196e3e576cSjsing .in = {
2206e3e576cSjsing 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2216e3e576cSjsing 0xff, 0x00, 0xff, 0xff,
2226e3e576cSjsing },
2236e3e576cSjsing .in_len = 12,
2246e3e576cSjsing .want = -1,
2256e3e576cSjsing .want_error = RSA_R_BAD_PAD_BYTE_COUNT,
2266e3e576cSjsing },
2276e3e576cSjsing {
2286e3e576cSjsing /* Incorrect padding type (0x00). */
2296e3e576cSjsing .in = {
2306e3e576cSjsing 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2316e3e576cSjsing 0xff, 0xff, 0x00, 0xff,
2326e3e576cSjsing },
2336e3e576cSjsing .in_len = 12,
2346e3e576cSjsing .want = -1,
2356e3e576cSjsing .want_error = RSA_R_BLOCK_TYPE_IS_NOT_02,
2366e3e576cSjsing },
2376e3e576cSjsing {
2386e3e576cSjsing /* Incorrect padding type (0x01). */
2396e3e576cSjsing .in = {
2406e3e576cSjsing 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2416e3e576cSjsing 0xff, 0xff, 0x00, 0xff,
2426e3e576cSjsing },
2436e3e576cSjsing .in_len = 12,
2446e3e576cSjsing .want = -1,
2456e3e576cSjsing .want_error = RSA_R_BLOCK_TYPE_IS_NOT_02,
2466e3e576cSjsing },
2476e3e576cSjsing {
2486e3e576cSjsing /* No end of padding marker. */
2496e3e576cSjsing .in = {
2506e3e576cSjsing 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2516e3e576cSjsing 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x6f, 0x6f,
2526e3e576cSjsing 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
2536e3e576cSjsing 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
2546e3e576cSjsing },
2556e3e576cSjsing .in_len = 32,
2566e3e576cSjsing .want = -1,
2576e3e576cSjsing .want_error = RSA_R_NULL_BEFORE_BLOCK_MISSING,
2586e3e576cSjsing },
2596e3e576cSjsing };
2606e3e576cSjsing
2616e3e576cSjsing #define N_PKCS1_TYPE2_TESTS \
2626e3e576cSjsing (sizeof(pkcs1_type2_tests) / sizeof(pkcs1_type2_tests[0]))
2636e3e576cSjsing
2646e3e576cSjsing static int
test_pkcs1_type2(void)2656e3e576cSjsing test_pkcs1_type2(void)
2666e3e576cSjsing {
2676e3e576cSjsing const struct pkcs1_test *pt;
268*e10c7425Sjsing uint8_t buf[32], in[19], out[512];
2696e3e576cSjsing int pad_len;
2706e3e576cSjsing long err;
2716e3e576cSjsing size_t i;
2726e3e576cSjsing int failed = 1;
2736e3e576cSjsing
274*e10c7425Sjsing for (i = 0; i < 1000; i++) {
275*e10c7425Sjsing arc4random_buf(in, sizeof(in));
2766e3e576cSjsing
277*e10c7425Sjsing if (!RSA_padding_add_PKCS1_type_2(buf, sizeof(buf), in,
278*e10c7425Sjsing sizeof(in))) {
279*e10c7425Sjsing fprintf(stderr, "FAIL: failed to add PKCS1 type 2 "
280*e10c7425Sjsing "padding\n");
2816e3e576cSjsing goto failed;
2826e3e576cSjsing }
2836e3e576cSjsing
2846e3e576cSjsing pad_len = RSA_padding_check_PKCS1_type_2(out, sizeof(out) - 1,
285*e10c7425Sjsing buf + 1, sizeof(buf) - 1, sizeof(buf));
2866e3e576cSjsing if (pad_len != sizeof(in)) {
287*e10c7425Sjsing fprintf(stderr, "FAIL: failed to check PKCS1 type 2 "
288*e10c7425Sjsing "padding\n");
2896e3e576cSjsing ERR_print_errors_fp(stderr);
2906e3e576cSjsing goto failed;
2916e3e576cSjsing }
292*e10c7425Sjsing }
2936e3e576cSjsing
2946e3e576cSjsing for (i = 0; i < N_PKCS1_TYPE2_TESTS; i++) {
2956e3e576cSjsing pt = &pkcs1_type2_tests[i];
2966e3e576cSjsing
2976e3e576cSjsing ERR_clear_error();
2986e3e576cSjsing
2996e3e576cSjsing pad_len = RSA_padding_check_PKCS1_type_2(out, sizeof(out) - 1,
3006e3e576cSjsing pt->in + 1, pt->in_len - 1, pt->in_len);
3016e3e576cSjsing
3026e3e576cSjsing if (pad_len != pt->want) {
3036e3e576cSjsing fprintf(stderr, "FAIL: test %zu - failed to check "
3046e3e576cSjsing "PKCS1 type 2 padding (%d != %d)\n", i, pad_len,
3056e3e576cSjsing pt->want);
3066e3e576cSjsing ERR_print_errors_fp(stderr);
3076e3e576cSjsing goto failed;
3086e3e576cSjsing }
3096e3e576cSjsing
3106e3e576cSjsing err = ERR_peek_error();
3116e3e576cSjsing if (pt->want == -1 && ERR_GET_REASON(err) != pt->want_error) {
3126e3e576cSjsing fprintf(stderr, "FAIL: test %zu - PKCS1 type 2 padding "
3136e3e576cSjsing "check failed with error reason %i, want %i\n",
3146e3e576cSjsing i, ERR_GET_REASON(err), pt->want_error);
3156e3e576cSjsing ERR_print_errors_fp(stderr);
3166e3e576cSjsing goto failed;
3176e3e576cSjsing }
3186e3e576cSjsing }
3196e3e576cSjsing
3206e3e576cSjsing failed = 0;
3216e3e576cSjsing
3226e3e576cSjsing failed:
3236e3e576cSjsing return failed;
3246e3e576cSjsing }
3256e3e576cSjsing
3266e3e576cSjsing int
main(int argc,char ** argv)3276e3e576cSjsing main(int argc, char **argv)
3286e3e576cSjsing {
3296e3e576cSjsing int failed = 0;
3306e3e576cSjsing
3316e3e576cSjsing failed |= test_pkcs1_type1();
3326e3e576cSjsing failed |= test_pkcs1_type2();
3336e3e576cSjsing
3346e3e576cSjsing return failed;
3356e3e576cSjsing }
336