1
0
mirror of https://github.com/opencryptoki/opencryptoki.git synced 2026-10-24 05:39:17 +03:00
Files
opencryptoki/testcases/unit/padtest.c
Ingo Franzki 3f6fb6d30b TESTCASES: Add unit tests for PKCS#7 padding and unpadding
Test the PKCS#7 padding and unpadding functions to behave correctly
on various valid and invalid inputs.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
2026-10-22 12:53:13 +02:00

210 lines
6.9 KiB
C

/*
* COPYRIGHT (c) International Business Machines Corp. 2026
*
* This program is provided under the terms of the Common Public License,
* version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
* software constitutes recipient's acceptance of CPL-1.0 terms which can be
* found in the file LICENSE file or at
* https://opensource.org/licenses/cpl1.0.php
*/
/*
* Unit test for add_pkcs_padding() and strip_pkcs_padding() in utility.c
*/
#include <stdio.h>
#include <string.h>
#include "pkcs11types.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "unittest.h"
#define MAX_BUF 256
#define FILL_BYTE 0xAA
#define LEN_UNTOUCHED ((CK_ULONG)0xDEADBEEF)
/*
* The buffer is built as follows: it is first filled with FILL_BYTE, then the
* last 'pad_count' bytes are set to 'pad_value'. Finally, if 'corrupt_idx' is
* not 0, the byte 'corrupt_idx' bytes from the end (1 = last byte) is set to
* 'corrupt_val'.
*/
struct strip_test {
const char *name;
CK_ULONG block_size;
CK_ULONG total_len;
CK_BYTE pad_value;
CK_ULONG pad_count;
CK_ULONG corrupt_idx;
CK_BYTE corrupt_val;
CK_RV exp_rc;
CK_ULONG exp_data_len;
};
static const struct strip_test strip_tests[] = {
/* valid padding */
{ "AES: 1 pad byte", 16, 16, 1, 1, 0, 0, CKR_OK, 15 },
{ "AES: 3 pad bytes", 16, 16, 3, 3, 0, 0, CKR_OK, 13 },
{ "AES: full padding block", 16, 16, 16, 16, 0, 0, CKR_OK, 0 },
{ "AES: full padding block, 2 blocks", 16, 32, 16, 16, 0, 0, CKR_OK, 16 },
{ "AES: 15 pad bytes, 2 blocks", 16, 32, 15, 15, 0, 0, CKR_OK, 17 },
{ "AES: byte before padding equals pad value", 16, 32, 15, 16, 0, 0,
CKR_OK, 17 },
{ "DES: full padding block", 8, 8, 8, 8, 0, 0, CKR_OK, 0 },
{ "DES: 1 pad byte, 3 blocks", 8, 24, 1, 1, 0, 0, CKR_OK, 23 },
/* invalid pad value */
{ "pad value 0", 16, 16, 0, 1, 0, 0, CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "pad value 0, all bytes 0", 16, 16, 0, 16, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "AES: pad value 17 > block size", 16, 16, 17, 16, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "AES: pad value 32 > block size, 2 blocks", 16, 32, 32, 32, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "DES: pad value 9 > block size", 8, 16, 9, 9, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "pad value 255", 16, 32, 255, 32, 0, 0, CKR_ENCRYPTED_DATA_INVALID, 0 },
/* invalid pad bytes */
{ "only last byte is the pad value", 16, 16, 3, 1, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "middle pad byte differs", 16, 16, 3, 3, 2, 2,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "first pad byte differs", 16, 16, 4, 4, 4, FILL_BYTE,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "first pad byte of full block differs", 16, 16, 16, 16, 16, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "DES: first pad byte of full block differs", 8, 8, 8, 8, 8, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
/* invalid lengths */
{ "total length 0", 16, 0, 1, 0, 0, 0, CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "total length not a multiple of block size", 16, 20, 1, 1, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "total length smaller than block size", 16, 8, 1, 1, 0, 0,
CKR_ENCRYPTED_DATA_INVALID, 0 },
/* invalid block size */
{ "block size 0", 0, 16, 1, 1, 0, 0, CKR_ENCRYPTED_DATA_INVALID, 0 },
{ "block size 256", 256, 256, 1, 1, 0, 0, CKR_ENCRYPTED_DATA_INVALID, 0 },
};
static int test_strip_pkcs_padding(void)
{
const struct strip_test *t;
CK_BYTE buf[MAX_BUF];
CK_ULONG data_len;
CK_RV rc;
size_t i;
int result = 0, failed;
for (i = 0; i < ARRAYSIZE(strip_tests); i++) {
t = &strip_tests[i];
failed = 0;
memset(buf, FILL_BYTE, sizeof(buf));
if (t->pad_count > 0)
memset(buf + t->total_len - t->pad_count, t->pad_value,
t->pad_count);
if (t->corrupt_idx > 0)
buf[t->total_len - t->corrupt_idx] = t->corrupt_val;
data_len = LEN_UNTOUCHED;
rc = strip_pkcs_padding(buf, t->block_size, t->total_len, &data_len);
if (rc != t->exp_rc) {
fprintf(stderr, "FAIL: strip [%zu] %s: unexpected rc 0x%lx "
"(expected 0x%lx)\n", i, t->name, rc, t->exp_rc);
failed = 1;
} else if (t->exp_rc == CKR_OK) {
if (data_len != t->exp_data_len) {
fprintf(stderr, "FAIL: strip [%zu] %s: unexpected data_len "
"%lu (expected %lu)\n", i, t->name, data_len,
t->exp_data_len);
failed = 1;
}
} else if (data_len != LEN_UNTOUCHED) {
fprintf(stderr, "FAIL: strip [%zu] %s: data_len modified on "
"failure\n", i, t->name);
failed = 1;
}
if (failed)
result++;
else
printf("PASS: strip [%zu] %s\n", i, t->name);
}
return result;
}
/*
* Round trip: add_pkcs_padding() followed by strip_pkcs_padding() must return
* the original data length for all data lengths and both block sizes.
*/
static int test_round_trip(void)
{
static const CK_ULONG block_sizes[] = { 8, 16 };
CK_BYTE buf[MAX_BUF];
CK_ULONG bs, data_len, total_len, out_len;
CK_RV rc;
size_t i;
int result = 0, failed;
for (i = 0; i < ARRAYSIZE(block_sizes); i++) {
bs = block_sizes[i];
failed = 0;
for (data_len = 0; data_len <= 3 * bs; data_len++) {
total_len = bs * (data_len / bs + 1);
memset(buf, FILL_BYTE, sizeof(buf));
rc = add_pkcs_padding(buf + data_len, bs, data_len, total_len);
if (rc != CKR_OK) {
fprintf(stderr, "FAIL: round trip (bs=%lu, len=%lu): "
"add_pkcs_padding rc 0x%lx\n", bs, data_len, rc);
failed++;
continue;
}
out_len = LEN_UNTOUCHED;
rc = strip_pkcs_padding(buf, bs, total_len, &out_len);
if (rc != CKR_OK || out_len != data_len) {
fprintf(stderr, "FAIL: round trip (bs=%lu, len=%lu): "
"strip_pkcs_padding rc 0x%lx, out_len %lu\n",
bs, data_len, rc, out_len);
failed++;
}
}
result += failed;
if (failed == 0)
printf("PASS: round trip, block size %lu, data lengths 0..%lu\n",
bs, 3 * bs);
else
fprintf(stderr, "FAIL: round trip, block size %lu, data lengths "
"0..%lu: %d failure(s)\n", bs, 3 * bs, failed);
}
return result;
}
int main(void)
{
int result = 0;
result += test_strip_pkcs_padding();
result += test_round_trip();
if (result != 0) {
fprintf(stderr, "padtest: %d failure(s)\n", result);
return TEST_FAIL;
}
printf("padtest: all tests passed\n");
return TEST_PASS;
}