字数:约 5000 字
前言
密评(商用密码应用安全性评估)是每一个使用国密的系统必须过的关。但真实密评流程对多数工程师来说是黑盒:流程繁琐、文档晦涩、需要真机环境。
这篇文章做一件具体的事:用 LLM + gm-agent-stack,模拟走完一次 GM/T 0029 签名验签服务器的接口合规性验证,覆盖从环境搭建到生成模拟报告的完整过程。不需要真实设备,不需要购买证书,所有步骤可以在本地复现。
预计总时间:3 小时(含环境安装)。
准备工作
需要的软件
| 软件 | 版本 | 用途 |
|---|---|---|
| Docker Desktop | 4.x | 运行 mock 服务 |
| LLM | 最新 | AI 辅助操作 |
| Go | 1.21+ | 运行测试套件 |
| curl | 任意 | 手动验证接口 |
克隆代码
git clone https://github.com/kintaiW/gm-agent-stack
cd gm-agent-stack
目录结构:
gm-agent-stack/
├── 0029-svs-mock/ ← SVS 模拟服务(本篇主角)
├── 0029-svs-test/ ← GM/T 0029 合规测试套件
└── ...
第一步:启动 SVS Mock(20 分钟)
方案 A:Docker(推荐)
cd 0029-svs-mock
docker build -t svs-mock .
docker run -d \
--name svs-mock \
-p 9000:9000 \
-v $(pwd)/mock_certs.toml:/app/mock_certs.toml \
svs-mock
方案 B:本地编译
cd 0029-svs-mock
cargo run --target-dir /tmp/svs-build -- --mode both
验证服务启动
curl -s -X POST http://localhost:9000/Digest \
-H "Content-Type: application/json" \
-d '{"algId": 1, "data": "SGVsbG8gV29ybGQ="}' | python3 -m json.tool
期望输出:
{
"respValue": 0,
"hashData": "Yfx4dFBiqaZXEzOb1oJ5JRfkrqVE1PkdxFOHxKFJbLo="
}
respValue: 0 表示成功。hashData 是 "Hello World" 的 SM3 摘要(base64)。
第二步:配置证书和密钥(30 分钟)
mock_certs.toml 是 SVS Mock 的核心配置,定义了:
- 可信根证书(用于验证叶证书)
- 签名密钥对(用于 SignData / SignMessage)
- 加密密钥对(用于 envelopeDec)
对于模拟密评,我们有两种方案:
方案 A:使用测试自签证书(快速开始)
如果只是做接口联调,可以用 openssl 临时生成测试用的 SM2 证书(需要支持 SM2 的 openssl,或者用 Go 的 gmssl 库)。
目前 mock_certs.toml 已有配置项占位,填入真实测试证书后即可使用。
方案 B:从真实设备导出(对标真机)
如果有真实 SVS 设备:
- 调用真实设备的
/ExportCert接口导出签名证书 - 联系设备厂商获取测试私钥(通常有配套测试环境)
- 将 DER base64 编码的证书和 hex 编码的私钥填入 mock_certs.toml
配置格式:
[server]
port = 9000
log_level = "info"
[[trusted_roots]]
name = "测试根证书"
cert = "MIIC..." # DER base64
[[signing_keys]]
index = 1
pin = "12345678"
private_key = "3945..." # 32字节私钥 hex
cert = "MIIC..." # 签名证书 DER base64
[[enc_keys]]
index = 1
private_key = "56B9..." # 32字节加密私钥 hex
cert = "MIIC..." # 加密证书 DER base64
第三步:把 MCP 接入 LLM(10 分钟)
LLM mcp add svs-mock --url http://localhost:9000/mcp
验证:
LLM mcp list
# 应该显示 svs-mock 已连接
测试 MCP 连通性
打开 LLM,输入:
用 svs_digest 工具,计算字符串 "Hello, 密评!" 的 SM3 摘要。
字符串的 UTF-8 十六进制是:48656c6c6f2c20e5af86e8af84efbc81
LLM 会调用 svs_digest tool,返回 SM3 哈希值。这一步确认 MCP 连通正常。
第四步:用 LLM 做接口探索(45 分钟)
这一步用 AI 辅助,逐个了解接口语义。这是密评前必须做的"接口摸底"。
4.1 ExportCert — 证书导出
在 LLM 里:
我想测试 SVS Mock 的 ExportCert 接口。
先帮我用 svs_cert 工具(action=export)导出一个签名证书,
然后解析(action=parse)出它的:
- 序列号(info_type=2)
- 主题 CN(info_type=0x31)
- 有效期(info_type=6)
LLM 会串联调用 svs_cert 两次,先导出证书,再解析字段。你会看到类似这样的输出:
// export 结果
{"cert_der_hex": "30820...", "cert_der_base64": "MIIC..."}
// parse 序列号(info_type=2)
{"respValue": 0, "certInfo": "0102030405060708"}
// parse CN(info_type=0x31)
{"respValue": 0, "certInfo": "测试签名证书"}
// parse 有效期(info_type=6)
{"respValue": 0, "certInfo": "20240101000000Z~20261231235959Z"}
4.2 SignData / VerifySignedData — P1 格式签名验签
现在测试签名验签流程:
1. 用 svs_sign(mode=data)对 hex 数据 "deadbeef01020304" 进行 SM2 签名
2. 用 svs_verify(mode=data)验证签名
3. 告诉我签名的 DER 结构是什么格式
LLM 的回复会包含:
- 签名结果的 hex(DER SEQUENCE{INTEGER r, INTEGER s} 格式)
- 验证结果
{"valid": true} - 对 DER 结构的解释(r 和 s 各 32 字节,带长度前缀)
4.3 SignMessage / VerifySignedMessage — CMS 格式签名验签
用 svs_sign(mode=message)对同样的数据签名,生成 CMS SignedData。
然后用 svs_verify(mode=message)验证。
解释 CMS 和 P1 格式的区别,以及什么场景用哪个。
4.4 envelopeEnc / envelopeDec — 数字信封
测试数字信封全流程:
1. 用 svs_envelope_enc 加密明文 "4d792073656372657420646174612121"("My secret data!!")
2. 用 svs_envelope_dec 解密,验证明文还原
3. 解释 SM2+SM4 数字信封的原理
LLM 会:
- 调用
svs_envelope_enc,返回包含加密 SM4 密钥、密文、IV 的 envelope - 直接把 envelope 传给
svs_envelope_dec - 确认明文
4d792073656372657420646174612121还原成功
第五步:运行合规测试套件(30 分钟)
0029-svs-test 是针对 GM/T 0029-2014 的 Go 语言测试套件,模拟 svsc 客户端行为。
配置环境变量
cd 0029-svs-test
# 设置你在第二步导出的证书 ID
export SVS_BASE_URL=http://localhost:9000
export SVS_TEST_IDENTIFICATION="<你的签名证书 subject base64>"
如果不知道证书 ID,用 LLM 问:
帮我获取 svs-mock 里签名密钥对应的证书标识(cert_id),
用于设置 SVS_TEST_IDENTIFICATION 环境变量。
运行完整测试
go test ./... -v -timeout 120s 2>&1 | tee test_result.txt
测试覆盖:
=== RUN TestApiExportCert
--- PASS: TestApiExportCert (0.02s)
=== RUN TestApiValidateCert
--- PASS: TestApiValidateCert (0.01s)
=== RUN TestApiParseCert
--- PASS: TestApiParseCert (0.02s)
=== RUN TestApiDigest
--- PASS: TestApiDigest (0.01s)
=== RUN TestApiSignData
--- PASS: TestApiSignData (0.03s)
=== RUN TestApiVerifySignedData
--- PASS: TestApiVerifySignedData (0.02s)
=== RUN TestApiSignMessage
--- PASS: TestApiSignMessage (0.05s)
=== RUN TestApiVerifySignedMessage
--- PASS: TestApiVerifySignedMessage (0.04s)
=== RUN TestApiEnvelopeEnc
--- PASS: TestApiEnvelopeEnc (0.03s)
=== RUN TestApiEnvelopeDec
--- PASS: TestApiEnvelopeDec (0.02s)
ok github.com/ccasa-project/svs-test
全部通过意味着:SVS Mock 的接口行为与 GM/T 0029-2014 规范要求一致。
第六步:用 LLM 生成模拟合规报告(30 分钟)
这步是真正体现"AI 有手"的地方。让 LLM 基于测试结果生成结构化报告。
在 LLM 里:
我刚完成了 GM/T 0029-2014 签名验签服务器的接口合规测试,
测试结果在 test_result.txt 里(已全部通过)。
请帮我生成一份模拟密评报告,包含:
1. 被测系统基本信息(SVS Mock v0.1,GM/T 0029-2014)
2. 测试范围和方法
3. 各接口测试结果汇总表
4. 密码算法使用情况(SM2/SM3/SM4 覆盖情况)
5. 结论与建议
格式参考 GB/T 39786-2021 的评估报告结构。
LLM 会读取测试结果,结合其对 GM/T 0029 和 GB/T 39786 的知识,生成一份结构化的模拟报告。
示例输出片段:
## 密码产品合规性测试报告(模拟)
### 被测系统
- 产品名称:SVS Mock(签名验签服务器软件模拟)
- 版本:v0.1.0
- 执行标准:GM/T 0029-2014《签名验签服务器技术规范》
### 测试接口清单
| 接口 | 算法 | 测试结果 | GM/T 0029 条款 |
|------|------|---------|----------------|
| /Digest | SM3 | ✅ 通过 | 5.3.1 |
| /SignData | SM2-SM3 | ✅ 通过 | 5.3.3 |
| /VerifySignedData | SM2-SM3 | ✅ 通过 | 5.3.4 |
| /SignMessage | SM2-SM3+CMS | ✅ 通过 | 5.3.5 |
| /VerifySignedMessage | SM2-SM3+CMS | ✅ 通过 | 5.3.6 |
| /envelopeEnc | SM2+SM4-CBC | ✅ 通过 | 5.3.7 |
| /envelopeDec | SM2+SM4-CBC | ✅ 通过 | 5.3.8 |
| /ExportCert | — | ✅ 通过 | 5.2.1 |
| /ValidateCert | — | ✅ 通过 | 5.2.2 |
| /ParseCert | — | ✅ 通过 | 5.2.3 |
### 密码算法覆盖
- 非对称算法:SM2(GM/T 0003-2012),签名算法标识 SGD_SM3_SM2=0x00020201 ✅
- 哈希算法:SM3(GM/T 0004-2012)✅
- 对称算法:SM4-CBC(GM/T 0002-2012),含 PKCS7 填充 ✅
- 数字信封:SM2+SM4-CBC(GM/T 0010-2012)✅
### 结论
被测系统接口行为符合 GM/T 0029-2014 规范要求。
建议在实际密评中补充:
1. 证书 CRL/OCSP 吊销查询能力(当前 Mock 不实现)
2. 密钥保护机制审查(Mock 以明文存储,真实设备需 HSM 保护)
3. 接口访问控制和审计日志
补充:用 LLM 排查不通过的测试
如果某个测试挂了,这是真正体现 LLM + MCP 价值的时刻。
假设 TestApiValidateCert 失败:
TestApiValidateCert 失败了,错误信息是:
"expected state=0, got state=1"
请帮我:
1. 用 svs_cert(action=validate)直接调一下验证接口,看实际返回什么
2. 用 svs_cert(action=parse)看一下证书的有效期
3. 判断是证书过期了还是 mock 的 state 含义有问题
LLM 会立刻调用 MCP 工具实际排查,而不是泛泛给建议。这是关键差异。
常见问题
Q:mock_certs.toml 里没有配置证书,测试会怎样?
签名/验签相关接口会返回 ERR_KEY_INDEX(0x04000005)或 ERR_CERT_INVALID(0x04000007)。只有 Digest 和(空白证书的)ValidateCert 能正常工作。
Q:Form-urlencoded 和 JSON 都支持吗?
是的。SVS Mock 根据请求头 Content-Type 自动分流:
Content-Type: application/json→ JSON 解析Content-Type: application/x-www-form-urlencoded→ form 解析
两种模式响应格式也各自匹配,与真实 svsc 客户端行为一致。
Q:多包接口(SignDataInit/Update/Final 等)支持吗?
目前 12 个多包接口全部返回 ERR_INTERNAL(0x0400000e)。MCP tool 通过单次调用完成对应功能(内部自动处理分包逻辑),不暴露流式 API。
总结
3 小时能做到什么:
| 阶段 | 时间 | 产出 |
|---|---|---|
| 环境搭建 | 20 min | SVS Mock 跑起来 |
| 证书配置 | 30 min | mock_certs.toml 填好 |
| MCP 接入 | 10 min | LLM 可调用 |
| 接口探索 | 45 min | 10 个接口全部摸清楚 |
| 合规测试 | 30 min | go test 全绿 |
| 报告生成 | 30 min | 模拟合规报告 |
做不到什么(也不应该期待):
- 不替代真实密评:真实密评需要真实设备、真实证书、资质机构
- 不覆盖 CRL/OCSP:Mock 不实现证书吊销查询
- 不覆盖 SM9/TLCP:当前只覆盖 SM2/SM3/SM4 三件套
这套工具的定位是开发测试沙箱:让工程师在没有真机的情况下,把接口调通、代码调对、流程摸清。等真机来了,改一个 URL,就能直接对接。
延伸阅读
声明:本文所有操作均在模拟环境中进行,gm-agent-stack 仅供学习和开发测试使用,严禁用于生产环境。密评合规结论需由具备资质的测评机构出具。