CMS签名验签服务 集成测试设计文档

| 文档版本 | V1.2 | | 编写日期 | 2026-06-27 |


1. 概述

1.1 测试目标

本文档定义CMS签名验签服务的集成测试方案,覆盖正常场景、异常场景和边界场景,验证:

  • 业务逻辑正确性(签名、验签、验签+签名流程)
  • 通信层可靠性(vsock+TLS双向认证)
  • 错误处理完整性(错误码返回、边界条件处理)

1.2 测试范围

范围 说明
正常场景 三种典型业务流程(双节点、三节点、单节点)
异常场景 验签失败类、签名失败类、验签+签名失败类、请求格式类
边界场景 证书过期、通信层限制、数据边界
未覆盖范围 性能测试、压力测试、安全渗透测试(另设专项)

1.3 测试环境

项目 要求
执行环境 WSL(Windows Subsystem for Linux)
编译环境 Rust工具链(通过WSL执行cargo命令)
通信层 vsock内核模块(vmw_vsock)、TLS证书体系
进程管理 测试框架自动启动/停止多进程实例

2. 测试架构

2.1 分层测试策略

采用分层测试方案,核心业务逻辑通过handler层模块集成测试验证,通信层通过实际连接测试验证:

层级 测试方式 关注点 环境
Handler层 模块集成测试 签名/验签业务逻辑、错误码映射 WSL,无需vsock
通信层 实际连接测试 vsock连接、TLS双向认证、报文收发 WSL,需要vsock+真实证书

2.2 测试crate结构

创建独立测试crate:

rust/
├── integration-tests/
│   ├── Cargo.toml
│   ├── src/
│   │   ├── lib.rs                 # 公共模块导出
│   │   ├── proc_manager.rs        # 进程启动管理
│   │   ├── vsock_client.rs        # vsock客户端封装
│   │   ├── test_cert_gen.rs       # 测试证书生成
│   │   ├── test_crl_gen.rs        # CRL吊销列表生成
│   │   ├── test_helpers.rs        # 测试辅助工具(路径管理、断言辅助)
│   │   └── tests/
│   │       ├── normal_scenarios.rs    # 正常场景测试
│   │       ├── error_scenarios.rs     # 异常场景测试
│   │       ├── boundary_scenarios.rs  # 边界场景测试
│   │       ├── communication_tests.rs # 通信层测试
│   │       ├── cert_check_tests.rs    # 证书检查测试
│   │       ├── handler_tests.rs       # Handler层测试
│   │       ├── lifecycle_tests.rs     # 进程生命周期测试
│   │       ├── tls_debug_test.rs      # TLS调试测试
│   │       └── proc_debug_test.rs     # 进程调试测试

2.3 证书生成策略

测试证书在 test_cert_gen.rs 中通过 OpenSSL 编程生成,无需独立工具:

  • 正常证书(CA、节点A/B/C):运行时生成临时证书
  • 过期证书:使用固定时间戳(Unix epoch)构造
  • 未生效证书:not_before 设置为未来时间(365天后)
  • 被吊销证书:生成 CRL 并加入对应证书序列号
  • 自签名证书:issuer 与 subject 相同

证书生成函数(test_cert_gen.rs):

pub fn generate_ca_and_signer() -> (Vec<u8>, Vec<u8>, Vec<u8>);
pub fn generate_expired_signer_cert() -> CertBundle;
pub fn generate_revoked_signer_cert() -> CertBundle;
pub fn generate_self_signed_signer_cert() -> (Vec<u8>, Vec<u8>, Vec<u8>);
pub fn generate_crl_for_cert(ca_pem, ca_key_pem, serial_to_revoke) -> Vec<u8>;

3. 测试环境

3.1 WSL环境要求

项目 要求
WSL版本 WSL2(支持Linux内核模块)
发行版 Ubuntu 22.04或更高
vsock模块 vmw_vsock内核模块已加载
Rust工具链 1.70+(通过rustup安装)
OpenSSL 3.0+(用于证书生成、TLS握手)

vsock模块检查命令

lsmod | grep vsock
# 应显示:vmw_vsock 或 vsock

3.2 证书体系

3.2.1 CMS签名验签证书

证书 用途 有效期 特殊配置
CMS CA根证书 签发所有节点签名证书 10年 ECC-256,BasicConstraints: CA
节点A签名证书 正常签名测试 10年 SubjectKeyIdentifier扩展
节点B签名证书 正常签名测试 10年 SubjectKeyIdentifier扩展
节点C签名证书 正常签名测试 10年 SubjectKeyIdentifier扩展
过期签名证书 证书过期边界测试 已过期(-1天) 有效期已结束
被吊销签名证书 CRL吊销测试 10年 已加入cms.crl
自签名证书 证书链无效测试 10年 自签名,无CA签发

3.2.2 TLS通信证书

证书 用途 有效期 特殊配置
TLS CA根证书 签发所有TLS证书(除wrong-ca) 10年 ECC-256
另一个TLS CA根证书 签发wrong-ca客户端证书 10年 ECC-256,与主CA独立
节点A/B/C TLS服务端证书 vsock TLS服务端 10年 正常证书
正常客户端TLS证书 正常通信测试 10年 正常证书
被吊销客户端TLS证书 CRL吊销测试 10年 已加入client-crl.crt
wrong-ca客户端证书 CA链不匹配测试 10年 由other-ca签发,非主CA签发
TLS客户端CRL 吊销客户端证书校验 包含revoked.crt

3.3 进程启动管理

测试框架自动管理多进程实例:

进程 vsock端口 配置文件 证书目录
节点A 12345 /tmp/test-node-a/config.toml test-certs/cms/node-a/, test-certs/tls/server/node-a/
节点B 12346 /tmp/test-node-b/config.toml test-certs/cms/node-b/, test-certs/tls/server/node-b/
节点C 12347 /tmp/test-node-c/config.toml test-certs/cms/node-c/, test-certs/tls/server/node-c/

进程管理流程

启动 → 等待就绪(检测vsock端口) → 执行测试 → 停止进程 → 清理临时文件

3.4 配置文件模板

节点配置文件模板config.toml):

[vsock]
port = {{PORT}}

[log]
path = "/tmp/{{NODE_NAME}}/trustring.log"
max_file_size = 10
max_roll_count = 10

[certificate]
signer_cert = "{{CMS_DIR}}/signer.crt"
signer_key = "{{CMS_DIR}}/signer.key"
ca_root_cert = "test-certs/cms/ca.crt"
cms_crl = "test-certs/cms/cms.crl"

comm_cert = "{{TLS_DIR}}/node.crt"
comm_key = "{{TLS_DIR}}/node.key"
comm_ca_root = "test-certs/tls/ca.crt"

4. 测试场景设计

4.1 正常场景

编号 场景名称 涉及节点 发起者标识传递 验证点
N01 双节点签名验证认证通信 A、B idA作为发起者标识,全程传递 B验签A签名(验签通过即签名),A验签B签名(身份判定)
N02 三节点签名验证认证通信 A、B、C idA作为发起者标识,全程传递 B验签A签名(验签通过即签名),C验签B签名(身份判定:其他节点)
N03 单节点签名验证认证通信 A idA作为发起者标识,全程传递 A验签自己签名(身份判定:证书身份冲突)

发起者标识:首次签名者的证书Subject Key ID,在多节点通信链路中始终传递此id,用于追溯签名请求的原始发起者身份。实际签名方可为后续节点(B、C),使用发起者ID签名表示"代签"语义。

验签职责差异

  • 验签+签名接口(0x12):仅验证签名有效性,验签通过即继续签名,不执行身份判定
  • 验签接口(0x14):验签通过后执行身份判定,返回result=0/1/2

4.2 异常场景

4.2.1 验签失败类(单独验签接口)

编号 场景名称 错误类型 预期result 说明
E01 签名不匹配 签名篡改 5 data被篡改,签名验证失败
E02 证书链无效 证书链 3 使用自签名证书签名,CA无法验证
E03 CRL吊销 CRL 4 签名方证书已加入CMS CRL
E04 CMS格式错误 格式 6 signed_data非CMS DER结构
E05 请求JSON解析失败 JSON 10 请求报文字段缺失或类型错误
E06 Base64解码失败 Base64 11 signed_data或id非有效Base64

4.2.2 签名失败类(单独签名接口)

编号 场景名称 错误类型 预期result 说明
E07 签名证书加载失败 证书 7 signer.crt文件不存在或损坏
E08 签名私钥不可用 私钥 8 signer.key文件不存在或损坏

4.2.3 验签+签名失败类(验签步骤失败)

编号 场景名称 to-verify to-sign 验签result 最终result signed_data id
E09 验签-签名不匹配 data篡改 正常 5 5 "" ""
E10 验签-证书链无效 自签名证书签名 正常 3 3 "" ""
E11 验签-CRL吊销 被吊销证书签名 正常 4 4 "" ""
E12 验签-CMS格式错误 非CMS结构 正常 6 6 "" ""

注意:验签+签名接口(0x12)仅验证签名有效性,验签失败类(result≥3)不执行签名。result=1/2(身份判定结果)不适用于验签+签名接口。

4.2.4 验签+签名失败类(验签通过但签名失败)

编号 场景名称 to-verify to-sign 验签result 签名result 最终result signed_data id
E15 签名-证书加载失败 正常(本节点签名) 本节点证书缺失 0 7 7 "" ""
E16 签名-私钥不可用 正常(本节点签名) 本节点私钥缺失 0 8 8 "" ""

4.2.5 请求格式类错误

编号 场景名称 错误类型 预期result 说明
E17 to-sign缺失 JSON 10 VerifySignRequest缺少to-sign字段
E18 to-verify缺失 JSON 10 VerifySignRequest缺少to-verify字段
E19 to-sign.id格式错误 Base64 11 to-sign.id非有效Base64
E20 to-verify.signed_data格式错误 Base64 11 to-verify.signed_data非有效Base64

4.3 边界场景

4.3.1 证书过期场景

编号 场景名称 描述 预期result 说明
B01 签名证书过期 使用过期证书签名 0 签名证书过期不影响签名结果(仅日志warn)
B02 验签-签名方证书过期 验签时签名方证书已过期 0/1/2 忽略过期错误,正常验签并返回身份判断结果

4.3.2 数据边界场景

编号 场景名称 描述 预期result 说明
B03 data为空字符串 to-sign.data = "" 0 正常签名空数据
B04 data含特殊字符 含中文、UTF-8字符 0 正常签名
B05 id为空字符串 to-verify.id = ""(非Base64) 11 Base64解码失败

4.4 通信层测试场景

通信层测试验证vsock连接建立、TLS双向认证握手、报文收发的完整链路。

执行环境:仅在WSL(Linux)环境执行,使用 #[cfg(target_os = "linux")] 条件编译。Windows环境的TCP fallback不执行TLS验证,不适用于通信层测试。

4.4.1 正常通信场景

编号 场景名称 描述 验证点
C01 TLS双向认证成功 正常客户端连接服务端,TLS握手成功,报文收发正常 连接成功、收到响应报文

4.4.2 TLS认证失败场景

编号 场景名称 客户端证书 预期结果 说明
C02 客户端证书被CRL吊销 revoked.crt TLS握手失败 客户端证书已加入client-crl.crt,服务端拒绝连接
C03 CA链不匹配 wrong-ca.crt TLS握手失败 客户端证书由other-ca签发,服务端CA无法验证
C04 客户端证书无效 损坏/格式错误的证书 TLS握手失败 证书文件损坏,OpenSSL无法加载

验证方式:TLS握手失败时,客户端收到 VsockError::TlsHandshake 错误,不区分具体失败原因(OpenSSL错误信息不可靠,服务端日志会记录具体原因)。

4.4.3 报文边界场景

编号 场景名称 描述 预期type len 说明
C05 报文超长 vsock报文data > 10KB 0x02 0 框架层拦截,返回通用错误
C06 version不匹配 version ≠ 0xFFFF0400 0x01 0 框架层拦截,返回通用错误

实现方式:VsockClient扩展 send_raw_header() 方法,测试代码可手动构造非法报文头。


4.5 证书检查测试场景

证书检查测试验证 CertificateChecker 的证书状态检测能力,包括过期检测和未生效检测。

执行环境:无需 vsock 环境,使用 OpenSSL 编程生成临时证书进行测试。

4.5.1 配置解析场景

编号 场景名称 描述 验证点
CC03 周期检查间隔默认值 解析不包含 cert_check 配置的 TOML interval_hours=24
CC04 周期检查间隔自定义值 解析包含 interval_hours=48 的配置 interval_hours=48

4.5.2 证书状态检测场景

编号 场景名称 描述 验证点
CC05 过期证书检测 使用 CertificateChecker 检查已过期证书 expired=true
CC06 有效证书检测 使用 CertificateChecker 检查有效证书(365天有效期) expired=false, not_yet_valid=false
CC07 未生效证书检测 使用 CertificateChecker 检查尚未生效证书(not_before在未来365天) not_yet_valid=true, expired=false

证书生成方式

  • 过期证书:not_before/not_after 使用固定时间戳(2000-2001年)
  • 未生效证书:not_before = days_from_now(365),not_after = days_from_now(3650)
  • 有效证书:not_before = days_from_now(0),not_after = days_from_now(365)

4.5.3 证书用途校验场景

编号 场景名称 描述 验证点
CC08 签名证书KeyUsage精确匹配 签名证书仅含digitalSignature check_key_usage_exact 返回 Ok
CC09 签名证书KeyUsage包含额外位 签名证书含digitalSignature+keyEncipherment check_key_usage_exact 返回 Err
CC10 通信证书KeyUsage包含匹配 通信证书含digitalSignature+keyEncipherment check_key_usage_contains 返回 Ok
CC11 通信证书ExtendedKeyUsage校验 通信证书含serverAuth check_extended_key_usage 返回 Ok
CC12 通信证书缺少必需KeyUsage位 通信证书仅含digitalSignature check_key_usage_contains 返回 Err
CC13 通信证书缺少ExtendedKeyUsage 通信证书无EKU扩展 check_extended_key_usage 返回 Err

证书生成方式

  • 使用 cert-gen 库的 create_cert_with_usage 函数
  • 支持自定义 KeyUsage 和 ExtendedKeyUsage
  • KeyUsage 标志位:DIGITAL_SIGNATURE (0x80), KEY_ENCIPHERMENT (0x20)
  • ExtendedKeyUsage OID:serverAuth, clientAuth

5. 测试用例详细设计

5.1 正常场景用例表

N01: 双节点签名验证认证通信

步骤 操作 输入 预期输出
N01-1 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=0, id=idA, signed_data=signA
N01-2 调用B节点验签并签名接口 {"to-verify":{"data":"字符串A","signed_data":"signA","id":"idA"},"to-sign":{"data":"字符串B","id":"idA"}} result=0, id=idA, signed_data=signB
N01-3 调用A节点验签接口 {"to-verify":{"data":"字符串B","signed_data":"signB","id":"idA"}} result=0

验证点

  • 步骤1:签名成功,id为A节点本地证书id
  • 步骤2:B验签A签名通过(仅验证签名有效性,不做身份判定),B签名使用idA(代签语义),返回result=0
  • 步骤3:A验签B签名,验签通过后执行身份判定:输入id=idA,A本地id=idA,id相同,签名方证书=B证书(公钥不同),返回result=0(id相同优先)

N02: 三节点签名验证认证通信

步骤 操作 输入 预期输出
N02-1 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=0, id=idA, signed_data=signA
N02-2 调用B节点验签并签名接口 {"to-verify":{"data":"字符串A","signed_data":"signA","id":"idA"},"to-sign":{"data":"字符串B","id":"idA"}} result=0, id=idA, signed_data=signB
N02-3 调用C节点验签接口 {"to-verify":{"data":"字符串B","signed_data":"signB","id":"idA"}} result=1

验证点

  • 步骤2:B验签A签名通过(仅验证签名有效性,不做身份判定),B签名使用idA(代签语义),返回result=0
  • 步骤3:C验签B签名,验签通过后执行身份判定:输入id=idA,C本地id=idC,id不同,签名方证书=B证书(公钥不同),返回result=1(其他节点签名)

N03: 单节点签名验证认证通信

步骤 操作 输入 预期输出
N03-1 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=0, id=idA, signed_data=signA
N03-2 调用A节点验签并签名接口 {"to-verify":{"data":"字符串A","signed_data":"signA","id":"idA"},"to-sign":{"data":"字符串B","id":"idA"}} result=0, id=idA, signed_data=signB
N03-3 调用A节点验签接口 {"to-verify":{"data":"字符串B","signed_data":"signB","id":"idA"}} result=2

验证点

  • 步骤2:A验签A签名通过(仅验证签名有效性,不做身份判定),A签名使用idA,返回result=0
  • 步骤3:A验签A签名,验签通过后执行身份判定:签名方证书=A证书(公钥相同),返回result=2(公钥相同,优先级最高)

5.2 异常场景用例表

E01: 签名不匹配(验签接口)

步骤 操作 输入 预期输出
E01-1 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=0, id=idA, signed_data=signA
E01-2 调用B节点验签接口 {"to-verify":{"data":"字符串B","signed_data":"signA","id":"idA"}} result=5

验证点:签名时data为"字符串A",验签时传入"字符串B",签名不匹配。

E02: 证书链无效(验签接口)

步骤 操作 输入 预期输出
E02-1 使用自签名证书签名 data="字符串A" signed_data=signSelfSigned
E02-2 调用B节点验签接口 {"to-verify":{"data":"字符串A","signed_data":"signSelfSigned","id":"idSelfSigned"}} result=3

验证点:自签名证书无CA签发,验签方CA无法验证证书链。

E03: CRL吊销(验签接口)

步骤 操作 输入 预期输出
E03-1 使用被吊销证书签名 data="字符串A" signed_data=signRevoked
E03-2 调用B节点验签接口 {"to-verify":{"data":"字符串A","signed_data":"signRevoked","id":"idRevoked"}} result=4

验证点:被吊销证书已加入cms.crl,验签时CRL校验失败。

E04: CMS格式错误(验签接口)

步骤 操作 输入 预期输出
E04-1 调用B节点验签接口 {"to-verify":{"data":"字符串A","signed_data":"invalid_random_bytes","id":"idA"}} result=7

验证点:signed_data为随机字节,非CMS DER结构。

E05: 请求JSON解析失败(验签接口)

步骤 操作 输入 预期输出
E05-1 调用B节点验签接口 {"to-verify":{"data":"字符串A"}}(缺少signed_data和id字段) result=20

验证点:请求报文缺少必填字段,JSON解析失败。

E06: Base64解码失败(验签接口)

步骤 操作 输入 预期输出
E06-1 调用B节点验签接口 {"to-verify":{"data":"字符串A","signed_data":"validSign","id":"!!!invalidBase64!!!"}} result=21

验证点:id字段非有效Base64编码。

E07-E08: 签名失败类

步骤 操作 输入 预期输出
E07-1 删除A节点signer.crt
E07-2 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=10
E08-1 删除A节点signer.key
E08-2 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=11

E09-E14: 验签+签名失败类(验签步骤失败)

E09: 验签-签名不匹配

步骤 操作 输入 预期输出
E09-1 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=0, id=idA, signed_data=signA
E09-2 调用B节点验签并签名接口 {"to-verify":{"data":"字符串B","signed_data":"signA","id":"idA"},"to-sign":{"data":"字符串C","id":"idA"}} result=5, signed_data="", id=""

验证点:验签步骤data篡改,验签失败(result=5),不执行签名步骤。

E10-E14类似,略(见4.2.3表格)

E15-E16: 验签+签名失败类(验签通过但签名失败)

E15: 签名-证书加载失败

步骤 操作 输入 预期输出
E15-1 调用A节点签名接口 {"to-sign":{"data":"字符串A"}} result=0, id=idA, signed_data=signA
E15-2 删除B节点signer.crt
E15-3 调用B节点验签并签名接口 {"to-verify":{"data":"字符串A","signed_data":"signA","id":"idA"},"to-sign":{"data":"字符串B","id":"idA"}} result=10, signed_data="", id=""

验证点:验签通过(result=0),签名步骤证书缺失,签名失败(result=10)。

E16类似,略(见4.2.4表格)

E17-E20: 请求格式类错误

E17: to-sign缺失

步骤 操作 输入 预期输出
E17-1 调用B节点验签并签名接口 {"to-verify":{"data":"字符串A","signed_data":"signA","id":"idA"}}(缺少to-sign) result=20

验证点:VerifySignRequest缺少to-sign字段,JSON解析失败。

E18-E20类似,略(见4.2.5表格)

5.3 边界场景用例表

B01: 签名证书过期

步骤 操作 输入 预期输出
B01-1 使用过期证书配置启动临时进程
B01-2 调用临时进程签名接口 {"to-sign":{"data":"字符串A"}} result=0

验证点:签名证书过期不影响签名结果(仅日志warn)。

B02: 验签-签名方证书过期

步骤 操作 输入 预期输出
B02-1 使用过期证书签名 data="字符串A" signed_data=signExpired
B02-2 调用B节点验签接口 {"to-verify":{"data":"字符串A","signed_data":"signExpired","id":"idExpired"}} result=1

验证点:忽略签名方证书过期错误,正常验签并返回身份判断结果(其他节点签名)。

B03-B05: 数据边界场景

B03: data为空字符串

步骤 操作 输入 预期输出
B03-1 调用A节点签名接口 {"to-sign":{"data":""}} result=0, signed_data有效

验证点:正常签名空数据。

B04-B05类似,略(见4.3.2表格)


5.4 通信层场景用例表

环境要求:仅WSL(Linux),需vsock模块和真实TLS证书。

C01: TLS双向认证成功

步骤 操作 输入 预期输出
C01-1 启动节点A 正常TLS证书配置 进程启动成功
C01-2 客户端连接 client.crt + client.key TLS握手成功
C01-3 发送签名请求 {"to-sign":{"data":"test"}} type=0x11, len>0

验证点:TLS双向认证成功,报文收发正常。不验证业务逻辑(业务逻辑由N01-N03覆盖)。

C02: 客户端证书被CRL吊销

步骤 操作 输入 预期输出
C02-1 启动节点A 配置client-crl.crt 进程启动成功
C02-2 客户端连接 revoked.crt + revoked.key TLS握手失败

验证点:客户端证书已加入CRL,服务端拒绝TLS连接。

C03: CA链不匹配

步骤 操作 输入 预期输出
C03-1 启动节点A 正常TLS CA配置 进程启动成功
C03-2 客户端连接 wrong-ca.crt + wrong-ca.key TLS握手失败

验证点:客户端证书由other-ca签发,服务端CA无法验证,拒绝TLS连接。

C04: 客户端证书无效

步骤 操作 输入 预期输出
C04-1 启动节点A 正常TLS证书配置 进程启动成功
C04-2 客户端连接 损坏的证书文件 TLS握手失败

验证点:证书文件损坏/格式错误,OpenSSL无法加载,TLS握手失败。

C05: 报文超长

步骤 操作 输入 预期输出
C05-1 启动节点A 正常配置 进程启动成功
C05-2 客户端连接 正常TLS证书 TLS握手成功
C05-3 发送超长报文 header.len=12000, data>10KB type=0x02, len=0

验证点:报文超过10KB上限,框架层拦截返回通用错误(type=0x02)。

实现方式:使用 VsockClient.send_raw_header() 手动构造非法报文头。

C06: version不匹配

步骤 操作 输入 预期输出
C06-1 启动节点A 正常配置 进程启动成功
C06-2 客户端连接 正常TLS证书 TLS握手成功
C06-3 发送version错误报文 version=0xFFFF0000 type=0x01, len=0

验证点:version不匹配,框架层拦截返回通用错误(type=0x01)。

实现方式:使用 VsockClient.send_raw_header() 手动构造非法报文头。


6. 测试执行流程

6.1 测试执行命令

# 1. 进入WSL(Windows环境需要)
wsl

# 2. 进入测试crate目录
cd <PROJECT_ROOT>/rust/integration-tests

# 3. 编译测试
cargo build --release

# 4. 运行全部测试
cargo test --release

# 或运行特定场景
cargo test --release normal_scenarios
cargo test --release error_scenarios
cargo test --release boundary_scenarios
cargo test --release communication_tests

注意:测试证书由 test_cert_gen.rs 在运行时自动生成,无需预生成。

6.2 进程启动流程(测试代码内部)

// 1. 创建临时配置目录
let temp_dir = TempDir::new()?;

// 2. 生成测试证书(运行时生成)
let certs = setup_test_certificates(&temp_dir);

// 3. 写入配置文件
let config = NodeConfig {
    name: "node-a",
    port: 12345,
    cms_cert_path: certs.signer_path,
    cms_key_path: certs.signer_key_path,
    tls_cert_path: ...,
    tls_key_path: ...,
};

// 4. 启动进程
let pm = ProcessManager::new(binary_path, cert_base_path);
pm.start_node(config)?;

// 5. 等待就绪(ProcessManager内部自动检测vsock端口)

// 6. 执行测试
// ...

// 7. 清理(ProcessManager::drop 自动调用 stop_all)

6.3 清理流程

测试结束后自动清理:

  • ProcessManager 的 Drop 实现:自动停止所有进程实例
  • TempDir 的 Drop 实现:自动删除临时目录和配置文件
  • 测试证书:随临时目录一起删除

7. 测试代码结构

7.1 证书生成辅助函数

文件rust/integration-tests/src/test_cert_gen.rs

功能

  • 生成CA根证书和签名证书
  • 生成过期签名证书(固定时间戳)
  • 生成被吊销签名证书(并生成CRL)
  • 生成自签名证书

文件rust/integration-tests/src/test_helpers.rs

功能

  • 构造测试请求JSON
  • 解析测试响应
  • 路径管理辅助函数
  • 插件测试上下文

主要函数

// 证书生成
pub fn generate_ca_and_signer() -> (Vec<u8>, Vec<u8>, Vec<u8>);
pub fn generate_expired_signer_cert() -> CertBundle;
pub fn generate_not_yet_valid_signer_cert() -> CertBundle;
pub fn generate_revoked_signer_cert() -> CertBundle;
pub fn generate_self_signed_signer_cert() -> (Vec<u8>, Vec<u8>, Vec<u8>);
pub fn generate_crl_for_cert(ca_pem, ca_key_pem, serial) -> Vec<u8>;

// 测试辅助
pub fn setup_test_certificates(temp_dir: &TempDir) -> TestCertificates;
pub fn setup_plugin_test_context(temp_dir: &TempDir) -> PluginTestContext;
pub fn build_sign_request(data: &str) -> Vec<u8>;
pub fn build_verify_request(data, signed_b64, cert_id_b64) -> Vec<u8>;
pub fn build_verify_sign_request(verify_data, signed_b64, cert_id_b64, sign_data, sign_id_b64) -> Vec<u8>;

7.2 进程管理模块

文件rust/integration-tests/src/proc_manager.rs

接口

pub struct NodeConfig {
    pub name: String,
    pub port: u32,
    pub cms_cert_path: PathBuf,
    pub cms_key_path: PathBuf,
    pub tls_cert_path: PathBuf,
    pub tls_key_path: PathBuf,
    pub tls_client_crl: Option<PathBuf>,
}

pub struct ProcessInstance {
    pub name: String,
    pub port: u32,
    pub child: Child,
    pub temp_dir: TempDir,
}

pub struct ProcessManager {
    processes: Arc<Mutex<HashMap<String, ProcessInstance>>,
    binary_path: PathBuf,
    cert_base_path: PathBuf,
}

impl ProcessManager {
    pub fn new(binary_path: PathBuf, cert_base_path: PathBuf) -> Self;
    pub fn start_node(&self, config: NodeConfig) -> Result<(), ProcessError>;
    pub fn start_multiple(&self, configs: Vec<NodeConfig>) -> Result<(), ProcessError>;
    pub fn stop_node(&self, name: &str) -> Result<(), ProcessError>;
    pub fn stop_all(&self) -> Result<(), ProcessError>;
}

impl Drop for ProcessManager {
    fn drop(&mut self); // 自动清理所有进程
}

7.3 vsock客户端模块

文件rust/integration-tests/src/vsock_client.rs

接口

pub struct VsockClient {
    stream: Box<dyn VsockStream>,
}

impl VsockClient {
    pub fn connect(
        port: u32,
        tls_ca_cert: &PathBuf,
        tls_client_cert: &PathBuf,
        tls_client_key: &PathBuf,
    ) -> Result<Self, VsockError>;

    pub fn sign(&mut self, data: &str) -> Result<SignResponse, VsockError>;
    pub fn verify_and_sign(&mut self, req: VerifySignRequest) -> Result<VerifySignResponse, VsockError>;
    pub fn verify(&mut self, data: &str, signed_data: &str, id: &str) -> Result<VerifyResponse, VsockError>;
    pub fn verify_raw(&mut self, raw_json: String) -> Result<VerifyResponse, VsockError>;
    pub fn close(&mut self) -> Result<(), VsockError>;

    // 用于边界测试:手动构造报文头
    pub fn send_raw_header(&mut self, version: u32, msg_type: u32, len: u32) -> Result<RawResponse, VsockError>;
}

7.4 测试用例代码结构

文件rust/integration-tests/src/tests/normal_scenarios.rs

#[test]
fn n01_two_node_sign_verify() {
    // 启动节点A、B
    // 执行N01-1/2/3步骤
    // 验证结果
    // 清理进程
}

#[test]
fn n02_three_node_sign_verify() {
    // 启动节点A、B、C
    // 执行N02-1/2/3步骤
    // 验证结果
    // 清理进程
}

#[test]
fn n03_single_node_sign_verify() {
    // 启动节点A
    // 执行N03-1/2/3步骤
    // 验证结果
    // 清理进程
}

文件rust/integration-tests/src/tests/error_scenarios.rs

#[test]
fn e01_signature_mismatch() { ... }

#[test]
fn e02_certificate_chain_invalid() { ... }

// ... 其他异常场景测试

文件rust/integration-tests/src/tests/boundary_scenarios.rs

#[test]
fn b01_expired_signer_cert() { ... }

#[test]
fn b03_message_too_long() { ... }

// ... 其他边界场景测试

修订历史

版本 日期 修订内容
V1.4 2026-07-15 修正模块名称:test_utils.rs 拆分为 test_cert_gen.rs、test_crl_gen.rs、test_helpers.rs 三个模块
V1.3 2026-07-02 新增证书检查测试设计:4.5证书检查测试场景(CC03-CC07),覆盖配置解析和证书状态检测(过期、未生效);更新测试crate结构
V1.2 2026-06-27 修正测试代码结构:移除独立证书生成工具,改为test_utils.rs运行时生成;更新进程管理和vsock_client接口描述与实际代码一致
V1.1 2026-06-24 新增通信层测试设计:4.4通信层测试场景(C01-C06)、5.4通信层场景用例表、扩展TLS异常测试证书、调整边界场景编号
V1.0 2026-06-23 初始版本:定义集成测试架构、场景设计、用例详细设计、执行流程