5.4 测试程序与编译:验证hsm-lite
测试程序设计
hsm-lite的测试程序hsm_test.c包含4个测试案例:
测试程序结构:
hsm_test.c(约230行)
│
├── test_basic_flow() 基础流程测试
│ ├── C_Initialize
│ ├── C_GetSlotList
│ ├── C_OpenSession
│ ├── C_CloseSession
│ └── C_Finalize
│
├── test_key_generation() 密钥生成测试
│ ├── C_GenerateKey
│ ├── C_GetAttributeValue
│ └── C_DestroyObject
│
├── test_encrypt_decrypt() 加密解密测试
│ ├── C_EncryptInit
│ ├── C_Encrypt
│ ├── C_DecryptInit
│ ├── C_Decrypt
│ └── 验证加密解密一致性
│
└── test_random() 随机数测试
└── C_GenerateRandom
基础流程测试
static int test_basic_flow(void)
{
CK_RV rv;
CK_SESSION_HANDLE hSession;
CK_SLOT_ID slots[1];
CK_ULONG slot_count;
printf("\n=== Test 1: Basic Flow ===\n\n");
/* 1. 初始化 */
rv = C_Initialize(NULL);
if (rv != CKR_OK) {
printf("FAIL: C_Initialize returned %lu\n", rv);
return -1;
}
printf("PASS: C_Initialize\n");
/* 2. 获取Slot列表 */
rv = C_GetSlotList(CK_TRUE, slots, &slot_count);
if (rv != CKR_OK || slot_count != 1) {
printf("FAIL: C_GetSlotList returned %lu, count=%lu\n", rv, slot_count);
return -1;
}
printf("PASS: C_GetSlotList (count=%lu)\n", slot_count);
/* 3. 打开Session */
rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION, &hSession);
if (rv != CKR_OK) {
printf("FAIL: C_OpenSession returned %lu\n", rv);
return -1;
}
printf("PASS: C_OpenSession (handle=%lu)\n", hSession);
/* 4. 关闭Session */
rv = C_CloseSession(hSession);
if (rv != CKR_OK) {
printf("FAIL: C_CloseSession returned %lu\n", rv);
return -1;
}
printf("PASS: C_CloseSession\n");
/* 5. 清理 */
rv = C_Finalize(NULL);
if (rv != CKR_OK) {
printf("FAIL: C_Finalize returned %lu\n", rv);
return -1;
}
printf("PASS: C_Finalize\n");
return 0;
}
密钥生成测试
static int test_key_generation(void)
{
CK_RV rv;
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_MECHANISM mechanism = {CKM_AES_KEY_GEN, NULL, 0};
CK_BYTE key_value[32];
CK_ULONG key_len;
printf("\n=== Test 2: Key Generation ===\n\n");
rv = C_Initialize(NULL);
rv = C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, &hSession);
/* 1. 生成AES密钥 */
rv = C_GenerateKey(hSession, &mechanism, NULL, 0, &hKey);
if (rv != CKR_OK) {
printf("FAIL: C_GenerateKey returned %lu\n", rv);
return -1;
}
printf("PASS: C_GenerateKey (handle=%lu)\n", hKey);
/* 2. 获取密钥属性 */
CK_ATTRIBUTE template[] = {
{CKA_VALUE, key_value, sizeof(key_value)},
{CKA_VALUE_LEN, &key_len, sizeof(key_len)}
};
rv = C_GetAttributeValue(hSession, hKey, template, 2);
print_bytes("Key value", key_value, key_len);
printf("PASS: C_GetAttributeValue (len=%lu)\n", key_len);
/* 3. 销毁密钥 */
rv = C_DestroyObject(hSession, hKey);
printf("PASS: C_DestroyObject\n");
C_CloseSession(hSession);
C_Finalize(NULL);
return 0;
}
加密解密测试
static int test_encrypt_decrypt(void)
{
CK_RV rv;
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_MECHANISM key_mech = {CKM_AES_KEY_GEN, NULL, 0};
CK_MECHANISM enc_mech = {CKM_AES_ECB, NULL, 0};
CK_BYTE plaintext[32] = "Hello, hsm-lite!";
CK_ULONG pt_len = 17;
CK_BYTE ciphertext[32];
CK_ULONG ct_len;
CK_BYTE decrypted[32];
CK_ULONG dec_len;
printf("\n=== Test 3: Encrypt/Decrypt ===\n\n");
rv = C_Initialize(NULL);
rv = C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, &hSession);
rv = C_GenerateKey(hSession, &key_mech, NULL, 0, &hKey);
print_bytes("Plaintext", plaintext, pt_len);
/* 1. 加密 */
ct_len = sizeof(ciphertext);
rv = C_EncryptInit(hSession, &enc_mech, hKey);
rv = C_Encrypt(hSession, plaintext, pt_len, ciphertext, &ct_len);
print_bytes("Ciphertext", ciphertext, ct_len);
printf("PASS: Encrypt (%lu -> %lu bytes)\n", pt_len, ct_len);
/* 2. 解密 */
dec_len = sizeof(decrypted);
rv = C_DecryptInit(hSession, &enc_mech, hKey);
rv = C_Decrypt(hSession, ciphertext, ct_len, decrypted, &dec_len);
print_bytes("Decrypted", decrypted, dec_len);
printf("PASS: Decrypt (%lu -> %lu bytes)\n", ct_len, dec_len);
/* 3. 验证一致性 */
if (memcmp(plaintext, decrypted, pt_len) == 0) {
printf("PASS: Plaintext matches decrypted text\n");
} else {
printf("FAIL: Plaintext does NOT match decrypted text\n");
return -1;
}
C_DestroyObject(hSession, hKey);
C_CloseSession(hSession);
C_Finalize(NULL);
return 0;
}
测试逻辑:
加密解密测试流程:
plaintext = "Hello, hsm-lite!"
│
│ C_EncryptInit + C_Encrypt
▼
ciphertext(加密后)
│
│ C_DecryptInit + C_Decrypt
▼
decrypted(解密后)
│
│ memcmp(plaintext, decrypted)
▼
验证:plaintext == decrypted ?
随机数测试
static int test_random(void)
{
CK_RV rv;
CK_SESSION_HANDLE hSession;
CK_BYTE random[32];
printf("\n=== Test 4: Random Generation ===\n\n");
rv = C_Initialize(NULL);
rv = C_OpenSession(0, CKF_SERIAL_SESSION, &hSession);
rv = C_GenerateRandom(hSession, random, sizeof(random));
print_bytes("Random", random, sizeof(random));
printf("PASS: C_GenerateRandom\n");
C_CloseSession(hSession);
C_Finalize(NULL);
return 0;
}
辅助函数
static void print_bytes(const char *label, CK_BYTE_PTR data, CK_ULONG len)
{
printf("%s: ", label);
for (CK_ULONG i = 0; i < len && i < 16; i++) {
printf("%02x", data[i]);
}
if (len > 16) {
printf("... (%lu bytes)", len);
}
printf("\n");
}
主测试入口
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
printf("========================================\n");
printf(" hsm-lite Test Suite (version %s)\n", HSM_LITE_VERSION);
printf("========================================\n");
int failed = 0;
// 运行所有测试
failed += test_basic_flow();
failed += test_key_generation();
failed += test_encrypt_decrypt();
failed += test_random();
printf("\n========================================\n");
if (failed == 0) {
printf(" ALL TESTS PASSED\n");
} else {
printf(" %d TESTS FAILED\n", failed);
}
printf("========================================\n");
return failed;
}
编译配置
Makefile:
# ==================== 编译器配置 ====================
# x86编译器(默认)
CC = gcc
# ARM架构编译器
CC_ARM64 = aarch64-linux-gnu-gcc
CC_ARM32 = arm-linux-gnueabihf-gcc # 硬浮点版本
# ==================== 编译选项 ====================
CFLAGS = -Wall -Wextra -O2 -std=gnu11
LDFLAGS =
# ==================== x86编译目标(默认) ====================
all: hsm_test
hsm_test: hsm_test.c hsm_lite.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
# ==================== ARM64编译目标 ====================
arm64: hsm_test_arm64
hsm_test_arm64: hsm_test.c hsm_lite.c
$(CC_ARM64) $(CFLAGS_ARM64) -o $@ $^ $(LDFLAGS_ARM64)
# ==================== ARM32编译目标 ====================
arm32: hsm_test_arm32
hsm_test_arm32: hsm_test.c hsm_lite.c
$(CC_ARM32) $(CFLAGS_ARM32) -o $@ $^ $(LDFLAGS_ARM32)
# ==================== 清理目标 ====================
clean:
rm -f hsm_test *.o
clean-arm64:
rm -f hsm_test_arm64 *.o
clean-arm32:
rm -f hsm_test_arm32 *.o
clean-all: clean clean-arm64 clean-arm32
# ==================== 辅助目标 ====================
# 编译所有架构版本
all-arch: all arm64 arm32
.PHONY: all arm64 arm32 clean clean-arm64 clean-arm32 clean-all all-arch
编译与运行
编译命令:
# 编译x86版本(默认)
make
# 编译ARM64版本
make arm64
# 编译ARM32版本
make arm32
# 编译所有架构
make all-arch
# 清理
make clean
运行测试:
./hsm_test
预期输出:
========================================
hsm-lite Test Suite (version 1.0.0)
========================================
=== Test 1: Basic Flow ===
[hsm-lite] Initialized (version 1.0.0)
PASS: C_Initialize
PASS: C_GetSlotList (count=1)
[hsm-lite] OpenSession: handle=1
PASS: C_OpenSession (handle=1)
[hsm-lite] CloseSession: handle=1
PASS: C_CloseSession
[hsm-lite] Finalized
PASS: C_Finalize
=== Test 2: Key Generation ===
[hsm-lite] Initialized (version 1.0.0)
[hsm-lite] OpenSession: handle=1
[hsm-lite] GenerateKey: handle=1 (AES-256)
PASS: C_GenerateKey (handle=1)
Key value: a3f5b8c1d2e4f6a7...
PASS: C_GetAttributeValue (len=32)
[hsm-lite] DestroyObject: handle=1
PASS: C_DestroyObject
=== Test 3: Encrypt/Decrypt ===
[hsm-lite] Initialized (version 1.0.0)
[hsm-lite] OpenSession: handle=1
[hsm-lite] GenerateKey: handle=1 (AES-256)
Plaintext: 48656c6c6f2c2068
[hsm-lite] EncryptInit: mech=ECB
[hsm-lite] Encrypt: 17 bytes -> 17 bytes
Ciphertext: 1b3d5f7a9c1e2f4...
PASS: Encrypt (17 -> 17 bytes)
[hsm-lite] DecryptInit: mech=ECB
[hsm-lite] Decrypt: 17 bytes -> 17 bytes
Decrypted: 48656c6c6f2c2068
PASS: Decrypt (17 -> 17 bytes)
PASS: Plaintext matches decrypted text
=== Test 4: Random Generation ===
[hsm-lite] Initialized (version 1.0.0)
[hsm-lite] OpenSession: handle=1
[hsm-lite] GenerateRandom: 32 bytes
Random: 7a3c9f2e1b5d8a4...
PASS: C_GenerateRandom
========================================
ALL TESTS PASSED
========================================
多架构编译说明
多架构支持:
架构:
├── 本机 原生架构(make all / make)
├── arm32 32位ARM Linux(Cortex-A,arm-linux-gnueabihf-gcc)
├── arm64 64位ARM Linux(Cortex-A,aarch64-linux-gnu-gcc)
└── 注意:arm32/arm64为交叉编译目标,需安装对应的交叉工具链
交叉编译需求:
├── arm32需要 arm-linux-gnueabihf-gcc(硬浮点)
├── arm64需要 aarch64-linux-gnu-gcc
├── 安装方法:
│ ├── Debian/Ubuntu:
│ │ sudo apt install gcc-arm-linux-gnueabihf
│ │ sudo apt install gcc-aarch64-linux-gnu
│ └── Fedora:
│ sudo dnf install arm-linux-gnueabihf-gcc
│ sudo dnf install aarch64-linux-gnu-gcc
一个类比:课程实验
课程实验类比:
hsm-lite测试(课程实验)
│
├── 测试目的
│ ├── 验证理论(PKCS#11概念)
│ ├── 检验实现(代码正确性)
│ ├── 理解流程(操作顺序)
│ └── 发现问题(错误处理)
│
├── 测试设计
│ ├── 基础流程:初始化→清理
│ ├── 密钥生成:生成→读取→销毁
│ ├── 加密解密:加密→解密→验证
│ └── 随机数:生成随机字节
│
├── 测试执行
│ ├── 每个测试独立运行
│ ├── 从初始化开始
│ ├── 打印每个步骤
│ └── 检查返回值
│
├── 结果判断
│ ├── PASS:返回CKR_OK
│ ├── FAIL:返回错误码
│ ├── 统计失败数
│ └── 最终汇总
│
└── 学习价值
├── 理解PKCS#11使用流程
├── 验证接口正确性
├── 学习测试设计方法
└── 可扩展更多测试
本篇小结
hsm-lite的测试与编译:
测试程序:
- 4个测试案例
- 约230行代码
- 每个测试独立完整
测试案例:
- test_basic_flow:初始化流程
- test_key_generation:密钥生成与销毁
- test_encrypt_decrypt:加密解密验证
- test_random:随机数生成
辅助函数:
- print_bytes:打印字节序列
编译配置:
- Makefile多架构支持
- 本机/arm32/arm64三种编译目标
- 交叉编译工具链需求
运行方法:
- make编译
- ./hsm_test运行
- 查看PASS/FAIL结果
预期结果:
- ALL TESTS PASSED
- 每个步骤打印日志
- 加密解密一致性验证
hsm-lite完成了从理论到实践的闭环——约600行代码实现PKCS#11核心功能,可编译运行,测试验证。
下一章,我们将进入真实项目集成——用现成SDK连接真实HSM芯片。
【第五章总结】
第五章结束了。我们亲手实现了PKCS#11核心功能:
- 项目定位:教学级实现,约600行代码
- 核心接口:初始化、Slot/Session管理、密钥生成、加密解密
- 安全存储:密钥数组、Handle分配、属性管理
- 测试验证:完整测试程序,多架构编译
“自己实现“完成了知识内化。接下来进入真实项目集成。
第六章,HSM集成实战。