1
0
mirror of https://github.com/opencryptoki/opencryptoki.git synced 2026-10-24 05:39:17 +03:00

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>
This commit is contained in:
Ingo Franzki
2026-10-19 16:16:08 +02:00
committed by Ingo Franzki
parent 594f41b08b
commit 3f6fb6d30b
4 changed files with 380 additions and 2 deletions

1
.gitignore vendored
View File

@@ -74,6 +74,7 @@ testcases/unit/pintest
testcases/unit/asn1test
testcases/unit/asn1fuzztest
testcases/unit/objectflattentest
testcases/unit/padtest
usr/sbin/p11sak/p11sak
usr/sbin/p11kmip/p11kmip
usr/sbin/pkcscca/pkcscca

209
testcases/unit/padtest.c Normal file
View File

@@ -0,0 +1,209 @@
/*
* 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;
}

View File

@@ -0,0 +1,156 @@
/*
* 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
*/
/*
* Stub implementations for padtest
* These stubs satisfy the external references of utility.c, which is linked
* into padtest to test add_pkcs_padding() and strip_pkcs_padding(). None of
* the stubbed functions is called by the code under test.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pkcs11types.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "p11util.h"
#include "attributes.h"
#include "shared_memory.h"
/* Global data */
token_spec_t token_specific = { 0 };
const char manuf[] = "IBM";
const char model[] = "PadTest";
const char descr[] = "IBM padtest";
const char label[] = "padtest";
const CK_BYTE default_so_pin_sha[SHA1_HASH_SIZE] = { 0 };
const CK_BYTE default_so_pin_md5[MD5_HASH_SIZE] = { 0 };
/* loadsave.c */
CK_RV generate_master_key(STDLL_TokData_t *tokdata, CK_BYTE *key)
{
(void)tokdata;
(void)key;
return CKR_FUNCTION_FAILED;
}
CK_RV save_masterkey_so(STDLL_TokData_t *tokdata)
{
(void)tokdata;
return CKR_FUNCTION_FAILED;
}
CK_RV save_token_data(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id)
{
(void)tokdata;
(void)slot_id;
return CKR_FUNCTION_FAILED;
}
char *get_pk_dir(STDLL_TokData_t *tokdata, char *fname, size_t len)
{
(void)tokdata;
(void)fname;
(void)len;
return NULL;
}
/* mech_rng.c */
CK_RV rng_generate(STDLL_TokData_t *tokdata, CK_BYTE *output, CK_ULONG bytes)
{
(void)tokdata;
(void)output;
(void)bytes;
return CKR_FUNCTION_FAILED;
}
/* shared_memory.c */
int sm_open(const char *sm_name, int mode, void **p_addr, size_t len,
int force, const char *group)
{
(void)sm_name;
(void)mode;
(void)p_addr;
(void)len;
(void)force;
(void)group;
return -1;
}
int sm_close(void *addr, int destroy, int ignore_ref_count)
{
(void)addr;
(void)destroy;
(void)ignore_ref_count;
return -1;
}
/* obj_mgr.c */
CK_RV object_mgr_find_in_map1(STDLL_TokData_t *tokdata,
CK_OBJECT_HANDLE handle, OBJECT **ptr,
OBJ_LOCK_TYPE lock_type)
{
(void)tokdata;
(void)handle;
(void)ptr;
(void)lock_type;
return CKR_FUNCTION_FAILED;
}
CK_RV object_put(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL unlock)
{
(void)tokdata;
(void)obj;
(void)unlock;
return CKR_FUNCTION_FAILED;
}
/* template.c */
CK_RV template_attribute_get_ulong(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type,
CK_ULONG *value)
{
(void)tmpl;
(void)type;
(void)value;
return CKR_FUNCTION_FAILED;
}
/* attributes.c */
CK_RV get_ulong_attribute_by_type(CK_ATTRIBUTE_PTR attrs,
CK_ULONG attrs_len, CK_ULONG type,
CK_ULONG *value)
{
(void)attrs;
(void)attrs_len;
(void)type;
(void)value;
return CKR_FUNCTION_FAILED;
}
CK_RV dup_attribute_array_no_alloc(CK_ATTRIBUTE_PTR orig, CK_ULONG num_attrs,
CK_ATTRIBUTE_PTR dest)
{
(void)orig;
(void)num_attrs;
(void)dest;
return CKR_FUNCTION_FAILED;
}
/* p11util.c */
CK_BBOOL is_attribute_attr_array(CK_ATTRIBUTE_TYPE type)
{
(void)type;
return FALSE;
}

View File

@@ -2,13 +2,15 @@ check_PROGRAMS = testcases/unit/policytest testcases/unit/hashmaptest \
testcases/unit/mechtabletest testcases/unit/configdump \
testcases/unit/buffertest testcases/unit/uritest \
testcases/unit/pintest testcases/unit/asn1test \
testcases/unit/asn1fuzztest testcases/unit/objectflattentest
testcases/unit/asn1fuzztest testcases/unit/objectflattentest \
testcases/unit/padtest
TESTS = testcases/unit/policytest testcases/unit/hashmaptest \
testcases/unit/mechtabletest testcases/unit/configdump \
testcases/unit/buffertest testcases/unit/uritest \
testcases/unit/pintest.sh testcases/unit/asn1test \
testcases/unit/asn1fuzztest testcases/unit/objectflattentest
testcases/unit/asn1fuzztest testcases/unit/objectflattentest \
testcases/unit/padtest
EXTRA_DIST += testcases/unit/pintest.sh
noinst_HEADERS += testcases/unit/unittest.h testcases/unit/asn1test_keys.h \
@@ -119,3 +121,13 @@ testcases_unit_objectflattentest_CFLAGS=-I${top_srcdir}/usr/lib/common \
-DSTDLL_NAME=\"objectflattentest\" -DOCK_UNIT_TESTS
testcases_unit_objectflattentest_LDFLAGS=-lpthread -lcrypto
testcases_unit_padtest_SOURCES=testcases/unit/padtest.c \
testcases/unit/padtest_stubs.c usr/lib/common/utility.c \
usr/lib/common/trace.c
testcases_unit_padtest_CFLAGS=-I${top_srcdir}/usr/lib/common \
-I${top_srcdir}/usr/include -I${top_srcdir}/usr/lib/api \
-DSTDLL_NAME=\"padtest\" -DTOK_NEW_DATA_STORE=0x0003000c
testcases_unit_padtest_LDFLAGS=-lpthread -lcrypto