/* $OpenBSD: rsa_padding_test.c,v 1.2 2024/03/30 02:20:39 jsing Exp $ */ /* * Copyright (c) 2024 Joel Sing * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #if 0 static void hexdump(const unsigned char *buf, size_t len) { size_t i; for (i = 1; i <= len; i++) fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); fprintf(stderr, "\n"); } #endif struct pkcs1_test { uint8_t in[128]; size_t in_len; int want; int want_error; }; static const struct pkcs1_test pkcs1_type1_tests[] = { { .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, }, .in_len = 32, .want = 19, }, { .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, }, .in_len = 11, .want = 0, }, { .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, }, .in_len = 12, .want = 1, }, { /* Insufficient padding bytes (< 8). */ .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BAD_PAD_BYTE_COUNT, }, { /* Incorrect padding type (0x00). */ .in = { 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BLOCK_TYPE_IS_NOT_01, }, { /* Incorrect padding type (0x02). */ .in = { 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BLOCK_TYPE_IS_NOT_01, }, { /* Non-padding byte before end of padding marker. */ .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BAD_FIXED_HEADER_DECRYPT, }, { /* No end of padding marker. */ .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .in_len = 32, .want = -1, .want_error = RSA_R_NULL_BEFORE_BLOCK_MISSING, }, }; #define N_PKCS1_TYPE1_TESTS \ (sizeof(pkcs1_type1_tests) / sizeof(pkcs1_type1_tests[0])) static int test_pkcs1_type1(void) { const struct pkcs1_test *pt; uint8_t buf[32], in[19], out[512]; int pad_len; long err; size_t i; int failed = 1; for (i = 0; i < 1000; i++) { arc4random_buf(in, sizeof(in)); if (!RSA_padding_add_PKCS1_type_1(buf, sizeof(buf), in, sizeof(in))) { fprintf(stderr, "FAIL: failed to add PKCS1 type 1 " "padding\n"); goto failed; } pad_len = RSA_padding_check_PKCS1_type_1(out, sizeof(out) - 1, buf + 1, sizeof(buf) - 1, sizeof(buf)); if (pad_len != sizeof(in)) { fprintf(stderr, "FAIL: failed to check PKCS1 type 1 " "padding\n"); ERR_print_errors_fp(stderr); goto failed; } } for (i = 0; i < N_PKCS1_TYPE1_TESTS; i++) { pt = &pkcs1_type1_tests[i]; ERR_clear_error(); pad_len = RSA_padding_check_PKCS1_type_1(out, sizeof(out) - 1, pt->in + 1, pt->in_len - 1, pt->in_len); if (pad_len != pt->want) { fprintf(stderr, "FAIL: test %zu - failed to check " "PKCS1 type 1 padding (%d != %d)\n", i, pad_len, pt->want); ERR_print_errors_fp(stderr); goto failed; } err = ERR_peek_error(); if (pt->want == -1 && ERR_GET_REASON(err) != pt->want_error) { fprintf(stderr, "FAIL: test %zu - PKCS1 type 1 padding " "check failed with error reason %i, want %i\n", i, ERR_GET_REASON(err), pt->want_error); ERR_print_errors_fp(stderr); goto failed; } } failed = 0; failed: return failed; } static const struct pkcs1_test pkcs1_type2_tests[] = { { .in = { 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, }, .in_len = 32, .want = 19, }, { .in = { 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, }, .in_len = 11, .want = 0, }, { .in = { 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, }, .in_len = 12, .want = 1, }, { /* Insufficient padding bytes (< 8). */ .in = { 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BAD_PAD_BYTE_COUNT, }, { /* Incorrect padding type (0x00). */ .in = { 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BLOCK_TYPE_IS_NOT_02, }, { /* Incorrect padding type (0x01). */ .in = { 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, }, .in_len = 12, .want = -1, .want_error = RSA_R_BLOCK_TYPE_IS_NOT_02, }, { /* No end of padding marker. */ .in = { 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, }, .in_len = 32, .want = -1, .want_error = RSA_R_NULL_BEFORE_BLOCK_MISSING, }, }; #define N_PKCS1_TYPE2_TESTS \ (sizeof(pkcs1_type2_tests) / sizeof(pkcs1_type2_tests[0])) static int test_pkcs1_type2(void) { const struct pkcs1_test *pt; uint8_t buf[32], in[19], out[512]; int pad_len; long err; size_t i; int failed = 1; for (i = 0; i < 1000; i++) { arc4random_buf(in, sizeof(in)); if (!RSA_padding_add_PKCS1_type_2(buf, sizeof(buf), in, sizeof(in))) { fprintf(stderr, "FAIL: failed to add PKCS1 type 2 " "padding\n"); goto failed; } pad_len = RSA_padding_check_PKCS1_type_2(out, sizeof(out) - 1, buf + 1, sizeof(buf) - 1, sizeof(buf)); if (pad_len != sizeof(in)) { fprintf(stderr, "FAIL: failed to check PKCS1 type 2 " "padding\n"); ERR_print_errors_fp(stderr); goto failed; } } for (i = 0; i < N_PKCS1_TYPE2_TESTS; i++) { pt = &pkcs1_type2_tests[i]; ERR_clear_error(); pad_len = RSA_padding_check_PKCS1_type_2(out, sizeof(out) - 1, pt->in + 1, pt->in_len - 1, pt->in_len); if (pad_len != pt->want) { fprintf(stderr, "FAIL: test %zu - failed to check " "PKCS1 type 2 padding (%d != %d)\n", i, pad_len, pt->want); ERR_print_errors_fp(stderr); goto failed; } err = ERR_peek_error(); if (pt->want == -1 && ERR_GET_REASON(err) != pt->want_error) { fprintf(stderr, "FAIL: test %zu - PKCS1 type 2 padding " "check failed with error reason %i, want %i\n", i, ERR_GET_REASON(err), pt->want_error); ERR_print_errors_fp(stderr); goto failed; } } failed = 0; failed: return failed; } int main(int argc, char **argv) { int failed = 0; failed |= test_pkcs1_type1(); failed |= test_pkcs1_type2(); return failed; }