第一章:功能安全认证与Go语言的合规性挑战
功能安全认证(如ISO 26262、IEC 61508)对软件开发流程、语言特性、运行时行为及工具链可追溯性提出严格要求。Go语言虽以简洁、内存安全和高并发见长,但在功能安全关键系统中面临多重结构性挑战:缺乏确定性内存释放机制(无RAII或析构函数)、GC暂停不可预测、反射与unsafe包削弱静态分析能力,且标准工具链未提供ASIL-B及以上等级所需的认证包(certification kit)。
Go语言核心合规障碍
- 运行时不确定性:垃圾回收器在1.22+版本仍存在毫秒级STW(Stop-The-World)波动,不符合ASIL-D系统对最坏执行时间(WCET)的硬实时约束;
- 内存模型限制:
sync.Pool等动态对象复用机制引入隐式生命周期依赖,难以通过MISRA或AUTOSAR C++风格的静态验证; - 工具链缺口:
go vet和staticcheck无法覆盖ISO 26262 Part 6 Annex D所列全部安全相关检查项(如未初始化变量传播路径、跨goroutine数据竞争的完整证明)。
安全子集实践建议
项目团队可采用受限Go子集(SafeGo Subset),禁用以下语言特性:
// ❌ 禁用:反射、cgo、unsafe、recover()、finalizer
import "reflect" // 编译期禁止:通过go list -json + build constraints隔离
func unsafeOp() {
// 使用//go:build !safety_critical标注构建标签
}
启用-gcflags="-d=checkptr=0"仅作为临时调试手段,正式构建必须关闭指针检查绕过。
认证就绪度评估维度
| 评估项 | Go现状 | 合规改进路径 |
|---|---|---|
| 静态单点故障分析 | 不支持(需第三方插件如golang.org/x/tools/go/ssa) | 集成SAFERTOS风格的CFG图生成器 |
| 覆盖率证据生成 | go test -coverprofile输出非ASAM MCD-2 MC格式 |
使用go-cover2mc转换为XML报告 |
| 可重现构建 | ✅ GOSUMDB=off GO111MODULE=on下可复现 |
强制go mod verify并存档校验和清单 |
工业界已出现适配案例:某车规MCU抽象层使用Go 1.21交叉编译至ARM Cortex-R5,通过剥离net/http等非必要包、禁用runtime.GC()调用,并配合自研WCET分析器完成ASIL-B流程认证。
第二章:go.mod校验哈希的全生命周期可信保障
2.1 go.sum哈希生成原理与ISO 26262 ASIL-B级完整性要求对齐
ASIL-B要求软件组件具备可验证的完整性保障机制,go.sum 的哈希生成过程天然契合该目标:其基于模块路径、版本号与go.mod及源码归档的SHA-256双重校验。
哈希计算逻辑
Go 工具链对每个依赖模块执行:
# 实际等效步骤(非真实命令,示意原理)
sha256sum go.mod go.sum ./zip-archive.zip | sha256sum
逻辑分析:
go.sum中每行module/path v1.2.3 h1:xxx的h1:前缀表示使用 SHA-256(RFC 6234),xxx是模块内容(含go.mod)的归一化哈希值。ASIL-B 要求哈希算法抗碰撞且输出长度 ≥256 bit,SHA-256 满足 ISO 26262-6:2018 Annex D 表 D.1 完整性验证算法推荐。
ASIL-B 对齐要点
- ✅ 确定性:相同输入必得相同哈希(满足ASIL-B“可重复验证”)
- ✅ 不可篡改:任意字节修改将导致哈希失配(满足ASIL-B“完整性检测”)
- ⚠️ 注意:需禁用
GOSUMDB=off,确保校验链不被绕过
| 验证环节 | ASIL-B 相关要求项 | Go 工具链实现方式 |
|---|---|---|
| 依赖下载时校验 | SW.IND.2.1.2 (Integrity) | go get 自动比对 go.sum |
| 构建环境锁定 | SW.IND.3.3.1 (Traceability) | go mod verify 强制校验 |
2.2 依赖树遍历与确定性构建验证:从go list -m -json到SBOM生成实践
Go 模块生态的可重现性基石在于其声明式依赖描述与确定性解析能力。go list -m -json all 是获取完整模块依赖图的权威入口,输出标准化 JSON 结构,包含 Path、Version、Replace、Indirect 等关键字段。
核心命令与结构化解析
go list -m -json all | jq 'select(.Main == false and .Indirect == false)' \
| jq -s 'sort_by(.Path) | {spdx: "SPDX-2.3", packages: [.[] | {name: .Path, versionInfo: .Version, downloadLocation: "https://proxy.golang.org/\(.Path)/@v/\(.Version).zip"}]}'
此命令过滤主模块与间接依赖,按路径排序后映射为 SPDX 兼容的轻量 SBOM 片段;
jq的-s参数将流式 JSON 合并为数组,避免解析中断。
依赖关系拓扑(简化版)
| 字段 | 含义 | 是否必需 |
|---|---|---|
Path |
模块导入路径 | ✅ |
Version |
语义化版本或伪版本 | ✅ |
Replace |
本地覆盖路径(影响哈希) | ⚠️ 影响确定性 |
Indirect |
是否为传递依赖 | ✅ 用于裁剪 |
构建确定性验证流程
graph TD
A[go mod download] --> B[go list -m -json all]
B --> C[计算 modules.json SHA256]
C --> D[比对 CI 缓存哈希]
D -->|一致| E[信任构建上下文]
D -->|不一致| F[中止并告警]
2.3 离线环境下的哈希一致性审计:基于reproducible build的CI/CD流水线设计
在空气间隙(air-gapped)环境中,构建产物的可验证性依赖于确定性输入→确定性输出的严格闭环。核心在于锁定所有非源码依赖:编译器版本、工具链哈希、时区、时间戳、文件排序顺序及环境变量。
构建确定性关键控制点
- 使用
SOURCE_DATE_EPOCH=0消除时间敏感性 - 通过
--no-sandbox+--disable-dev-shm-usage避免临时路径随机性 - 所有依赖通过
sha256sum校验后注入离线制品库
reproducible Docker 构建示例
# 构建阶段使用固定 UID/GID,禁用缓存层随机性
FROM golang:1.21.0-bullseye@sha256:9a7a15c4b2...
ARG BUILDKIT=0 # 禁用 BuildKit 的隐式 layer 哈希扰动
RUN --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w -buildid=" -o /app/main .
此配置强制 Go 编译器忽略路径信息与调试符号,
-trimpath消除源码绝对路径嵌入,-buildid=清空唯一构建标识符,确保相同源码生成完全一致的 ELF 二进制哈希。
审计流水线阶段对齐表
| 阶段 | 输入哈希来源 | 输出验证方式 |
|---|---|---|
| 代码拉取 | Git commit + tree hash | git verify-tag |
| 依赖解析 | go.sum + pinned checksums |
go mod verify |
| 二进制生成 | 完整构建上下文 tar | sha256sum main |
graph TD
A[离线CI节点] --> B[加载预签名构建镜像]
B --> C[挂载只读源码+校验清单]
C --> D[执行无网络reproducible build]
D --> E[输出二进制+完整buildinfo.json]
E --> F[本地哈希比对审计报告]
2.4 哈希篡改检测与自动告警机制:集成Sigstore Cosign与SLSA Level 3策略
为满足SLSA Level 3对“完整构建溯源”与“不可抵赖性”的核心要求,需在制品发布流水线中嵌入强签名验证与实时完整性校验能力。
签名验证与哈希比对流程
# 在CI/CD出口阶段执行Cosign验证并提取声明哈希
cosign verify-blob \
--signature "${ARTIFACT}.sig" \
--cert "${ARTIFACT}.crt" \
--oidc-issuer https://oauth2.sigstore.dev/auth \
"${ARTIFACT}" | \
jq -r '.payload | @base64d | fromjson | .messageDigest' # 输出: sha256:abc123...
该命令通过公钥信任链验证签名有效性,并解码DSSE(Signed Entry)载荷,精准提取构建时绑定的messageDigest——即原始二进制内容的权威哈希,用于后续比对。
自动化告警触发逻辑
graph TD
A[制品上传至OSS] –> B{Cosign验证+哈希提取}
B –> C{本地重算SHA256}
C –>|不匹配| D[SLSA Violation Alert → SLSA-ALERT-003]
C –>|匹配| E[标记SLSA_Level_3_Compliant]
关键参数对照表
| 参数 | 作用 | SLSA Level 3 合规性 |
|---|---|---|
--oidc-issuer |
绑定可信身份源 | ✅ 强制要求 |
messageDigest in DSSE |
防篡改内容指纹 | ✅ 构建时锁定 |
| 签名与证书分离存储 | 支持密钥轮换审计 | ✅ 可追溯性 |
2.5 认证证据包中的go.mod/go.sum存档规范:符合IEC 61508 Part 3 Annex D模板
为满足功能安全认证对构建可重现性的强制要求,go.mod 与 go.sum 必须以不可变快照形式归档,并严格遵循 Annex D 中“确定性构建证据”条目(D.3.2.1)。
存档结构约定
- 根目录下固定路径:
/evidence/safety/build/ - 文件命名:
go.mod@v1.22.0+iecfse-20240517(含 Go 版本、标准号、UTC 归档时间戳)
校验完整性流程
graph TD
A[提取 go.mod] --> B[验证 module path 符合组织域名策略]
B --> C[解析 require 块 → 检查所有版本为 pseudo-version 或语义化 vN.M.P]
C --> D[比对 go.sum 中每行 checksum 与官方 proxy 响应一致]
关键校验代码示例
# 验证 go.sum 行数与 go.mod 中非-indirect 依赖数量匹配
grep -v 'indirect$' go.mod | grep '^[[:space:]]*require' -A1 | \
grep -E '^[[:space:]]+[a-zA-Z0-9./-]+[[:space:]]+v[0-9]' | wc -l
# 输出应等于:awk '/^ [^ ]+ v[0-9]/ && !/indirect$/ {c++} END{print c+0}' go.sum
该命令过滤 go.mod 中直接依赖项并计数,确保 go.sum 包含全部对应校验和,避免遗漏或冗余——这是 Annex D 要求的“完整依赖覆盖证据”。
| 字段 | Annex D 映射条目 | 说明 |
|---|---|---|
go.mod 时间戳 |
D.3.2.1(c) | 必须为归档操作 UTC 时间 |
go.sum 算法标识 |
D.3.2.1(e) | 仅允许 h1: 开头的 SHA256 |
第三章:符号表完整性签名的技术实现路径
3.1 Go链接器符号导出机制与调试信息剥离的安全边界分析
Go 链接器(cmd/link)在构建阶段通过 -ldflags="-s -w" 剥离符号表与 DWARF 调试信息,但导出符号(如 //export 标记的 C 兼容函数)仍保留在 .dynsym 段中。
符号可见性分层模型
internal包函数:编译期不可导出,无符号名//export Foo函数:强制注入.text并注册到.dynsymruntime.symtab:仅运行时反射可用,链接后不存于二进制
关键安全边界对照表
| 剥离选项 | 保留符号 | 可被 nm -D 列出 |
可被 dlopen 调用 |
|---|---|---|---|
-s |
否 | 否 | 否(除非 //export) |
-w |
是 | 是 | 是 |
-s -w |
仅 //export |
是 | 是 |
# 查看动态符号表(暴露所有 //export 函数)
nm -D ./main
# 输出示例:
# 0000000000456789 T MyExportedFunc
该命令提取 .dynsym 中的全局函数符号;T 表示文本段定义,表明其可被外部动态链接器解析调用——这构成实际攻击面,而非仅“调试信息”范畴。
graph TD
A[Go源码] -->|cgo + //export| B[编译器生成 .o]
B --> C[链接器 cmd/link]
C -->|默认| D[完整 symtab + DWARF]
C -->|-s -w| E[仅保留 //export 符号 + 无DWARF]
E --> F[动态加载攻击面残留]
3.2 ELF二进制符号表签名方案:基于cosign sign-blob与符号哈希白名单比对
传统ELF签名常作用于整个文件,易受重定位节、调试信息等非语义字段扰动。本方案聚焦符号表(.dynsym/.symtab)这一语义核心,提取符号名+绑定+类型+值的结构化哈希。
符号哈希生成流程
# 提取动态符号并标准化排序后计算SHA256
readelf -sW ./target | \
awk '$2 ~ /^[0-9]+$/ && $4 != "UND" {print $8,$4,$5,$6}' | \
sort -k1,1 | sha256sum | cut -d' ' -f1
# 输出示例:a1b2c3d4e5f6...
逻辑分析:
-sW启用宽格式避免截断;$2 ~ /^[0-9]+$/过滤有效符号索引;$4 != "UND"排除未定义符号;sort -k1,1确保哈希确定性。参数-W和字段位置依赖readelf版本兼容性。
签名与验证链路
graph TD
A[ELF文件] --> B[提取符号表哈希]
B --> C[cosign sign-blob --payload hash.txt]
C --> D[签名存入OCI registry]
D --> E[部署时fetch hash + verify]
白名单管理方式
| 字段 | 示例值 | 说明 |
|---|---|---|
symbol_name |
memcpy |
标准C库函数 |
hash_sha256 |
a1b2... |
对应符号表结构化哈希 |
policy |
allow_if_signed |
签名存在且有效才加载 |
3.3 符号完整性证据链生成:从go tool nm输出到ASAM MCD-2 MC兼容XML报告
符号完整性证据链需将Go二进制的底层符号信息,结构化映射为汽车电子领域通用的ASAM MCD-2 MC标准XML。核心路径为:go tool nm -sort address -format go → 中间JSON Schema校验 → XML序列化。
数据提取与标准化
# 提取带地址、类型、大小的符号表(支持DWARF调试信息)
go tool nm -sort address -format go ./firmware.bin | \
jq -r 'map({name: .Name, addr: .Addr, typ: .Type, size: .Size}) | .[]' > symbols.json
该命令输出Go原生格式符号,-format go确保字段语义明确(如Type="T"表示文本段函数),避免-format plan9的歧义;-sort address保障后续内存布局可追溯性。
ASAM MCD-2 MC映射规则
| Go符号类型 | MCD-2 MC <Variable> type |
示例 |
|---|---|---|
T (text) |
function |
main.init |
D (data) |
variable |
config.timeout |
B (bss) |
variable + init="false" |
buffer[1024] |
证据链验证流程
graph TD
A[go tool nm raw output] --> B[JSON Schema校验<br>• 地址连续性<br>• 类型合法性]
B --> C[ASAM MCD-2 MC XML生成<br>• 命名空间声明<br>• <Variable>嵌套<Datatype>]
C --> D[SHA256+Timestamp签名<br>嵌入<Annotation>作为完整性锚点]
第四章:全链路证据包构建与认证就绪交付
4.1 FuSa证据包结构设计:依据ISO/PAS 21448 SOTIF Annex G与ASPICE VDA-SCM映射
FuSa证据包需同时满足SOTIF对未知不安全场景的系统性论证要求,以及VDA-SCM对配置项可追溯性的工程管控约束。
映射核心维度
- SOTIF Annex G 提供7类证据类别(如场景识别记录、触发条件分析、误用假设验证)
- VDA-SCM 要求5级配置基线(需求/设计/实现/验证/发布)与变更控制链
证据包目录骨架(YAML Schema)
evidence_package:
id: "SOTIF-FuSa-2024-001"
scm_baseline: "VDA-SCM-BL3" # 对应设计与验证基线
sotif_annex_g_ref: ["G.2.3", "G.4.1"] # 引用具体条款
artifacts:
- path: "/sotif/hazard_scenario/SRS-042.csv"
vda_scm_id: "REQ-SCM-042" # 实现双向追溯
该结构确保每个SOTIF证据文件均绑定VDA-SCM配置项ID,支持自动化审计工具解析。
映射关系表
| SOTIF Annex G 条款 | VDA-SCM 配置项类型 | 可交付物示例 |
|---|---|---|
| G.2.1(场景识别) | REQ / SYS-DES | scenario_catalog.xlsx |
| G.4.2(验证策略) | VER-PLAN / TEST-CASE | sotif_verification_matrix.pdf |
graph TD
A[SOTIF Annex G Evidence] --> B{VDA-SCM Baseline}
B --> C[REQ-SCM-042]
B --> D[DES-SCM-117]
B --> E[VER-SCM-089]
4.2 自动化证据采集工具链:go-fusa-prove CLI的模块化架构与插件扩展实践
go-fusa-prove 采用核心(Core)+ 插件(Plugin)双层设计,CLI 入口通过 plugin.Open() 动态加载 .so 插件,实现采集能力热插拔。
插件注册机制
// plugin/df-forensics/main.go
func Register() *Collector {
return &Collector{
Name: "disk-usage",
Priority: 10,
Run: func(ctx context.Context, cfg map[string]interface{}) (Evidence, error) {
// 执行 df -h 解析并结构化
return Evidence{Type: "disk_usage", Data: result}, nil
},
}
}
该函数在插件初始化时向主进程注册采集器;Priority 控制执行顺序;cfg 支持 YAML 透传参数(如 --threshold=85)。
内置插件能力矩阵
| 插件名 | 数据源 | 输出格式 | 是否支持增量 |
|---|---|---|---|
proc-snapshot |
/proc |
JSON | ✅ |
net-conn |
ss -tuln |
CSV | ❌ |
log-tail |
journald | NDJSON | ✅ |
扩展流程图
graph TD
A[CLI 启动] --> B[加载 plugin/*.so]
B --> C{插件 Register()}
C --> D[注册至 Collector Registry]
D --> E[解析 CLI 参数 --collect=...]
E --> F[按优先级调度 Run()]
F --> G[统一序列化为 EvidenceBundle]
4.3 交叉引用验证矩阵构建:go.mod哈希、符号签名、测试覆盖率报告三元一致性校验
为保障构建可重现性与供应链完整性,需同步校验三类关键制品的内在一致性。
校验维度定义
go.mod文件的sum字段(SHA-256 哈希)- Go 模块符号签名(由
cosign sign --key cosign.key ./go.mod生成) go test -coverprofile=coverage.out输出的覆盖率报告中模块路径与版本戳
一致性校验流程
# 提取 go.mod 哈希(忽略空格与注释行)
grep -v '^#' go.mod | sha256sum | cut -d' ' -f1
# 验证签名是否覆盖该哈希值
cosign verify-blob --key cosign.pub --signature go.mod.sig $(sha256sum go.mod | cut -d' ' -f1)
上述命令确保
go.mod内容未被篡改,且签名绑定其精确字节哈希;cosign verify-blob的--signature参数必须指向与原始哈希严格匹配的签名文件,否则校验失败。
三元关联表
| 维度 | 来源 | 关键约束 |
|---|---|---|
| go.mod 哈希 | go.sum 或 go mod graph |
必须与 coverage.out 中 module header 一致 |
| 符号签名 | cosign 签名链 |
必须由可信密钥签发,且覆盖哈希值 |
| 测试覆盖率报告 | go tool cover |
mode: atomic + 包路径需含 vX.Y.Z 版本标识 |
graph TD
A[go.mod] -->|SHA-256| B(哈希值H)
B --> C{cosign verify-blob}
C -->|true| D[签名可信]
A -->|go test -coverprofile| E[coverage.out]
E -->|parse module line| B
D & B & E --> F[三元一致 ✅]
4.4 认证机构审查友好型交付物打包:PDF+SBOM+签名清单+时间戳证书的ZIP64归档规范
为满足等保2.0、ISO/IEC 17065及NIST SP 800-161对可验证交付链的要求,交付包须采用ZIP64格式(突破4GB限制),并严格组织四类核心资产:
report.pdf:含数字签名页与审计摘要sbom.cyclonedx.json:符合CycloneDX 1.5规范的软件物料清单signatures.txt:RFC 3161时间戳响应+RSA-PSS签名哈希清单timestamp.crt:由CA签发的RFC 3161时间戳证书
# 构建合规ZIP64归档(需zip 3.0+)
zip -Z store -r --zip64 \
--recurse-paths \
release-v1.2.0.zip \
report.pdf sbom.cyclonedx.json signatures.txt timestamp.crt
逻辑分析:
-Z store禁用压缩以保障哈希稳定性;--zip64强制启用64位扩展头,确保大文件元数据完整性;--recurse-paths避免路径歧义,满足CA审查路径一致性要求。
验证流程依赖关系
graph TD
A[PDF签名哈希] --> B[signatures.txt条目]
C[SBOM哈希] --> B
B --> D[RFC 3161时间戳响应]
D --> E[timestamp.crt公钥验证]
| 文件 | 哈希算法 | 用途 |
|---|---|---|
report.pdf |
SHA-256 | 审计结论锚点 |
sbom.cyclonedx.json |
SHA-384 | 供应链组件溯源依据 |
第五章:面向ASIL-D系统的Go语言功能安全演进展望
功能安全认证的现实瓶颈
当前汽车电子领域中,ASIL-D级系统仍高度依赖C/C++与专用安全编译器(如IAR Embedded Workbench for AUTOSAR),其认证证据包平均需2000+工时构建。Go语言虽在云原生领域成熟,但ISO 26262:2018 Annex D明确将“内存不安全语言”列为高风险项——这直接导致主流车规MCU(如Infineon AURIX TC4xx)尚未提供官方Go运行时支持。某国内智能驾驶域控制器厂商在2023年实测表明:未经改造的Go 1.21 runtime在ARM Cortex-R52核心上触发ASIL-D级FMEA中的“未定义行为传播”缺陷达17处,集中于goroutine栈溢出检测缺失与GC暂停不可预测性。
内存模型重构实践
为满足ASIL-D对确定性内存分配的要求,某Tier-1供应商采用静态内存池方案重构Go运行时:
- 禁用
malloc调用链,所有heap分配转为预分配的[1024]byte环形缓冲区 runtime.mallocgc被替换为safe_malloc,其返回地址经硬件MPU校验(匹配预设地址区间)- goroutine栈大小强制固定为8KB(非动态伸缩),通过LLVM IR插入
__builtin_assume断言确保栈边界
// 安全栈分配示例(经GCC-ARM嵌入式工具链交叉编译)
func safeGoroutine() {
// 编译期绑定至安全内存区
stack := unsafe.Slice((*byte)(unsafe.Pointer(uintptr(0x2000_0000))), 8192)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
// 实际业务逻辑...
}
静态分析工具链集成
| 该方案将Go代码纳入TÜV SÜD认证的Polyspace流程: | 工具阶段 | 检查项 | ASIL-D符合性动作 |
|---|---|---|---|
govet增强版 |
检测unsafe.Pointer越界转换 |
自动注入// polyclean: require_bounds_check注释 |
|
gosec定制规则 |
标识所有net/http相关调用 |
编译期报错并阻断构建 | |
go tool compile -S |
输出汇编中禁止出现call runtime.gc指令 |
生成.s文件后扫描失败则终止CI |
时间可预测性保障
在NXP S32G399A平台实测中,启用GOGC=off与GOMAXPROCS=1后,关键任务周期抖动从±12.7μs降至±0.3μs(示波器实测)。更关键的是,通过修改runtime/scheduler.go中findrunnable()函数,移除所有基于时间戳的调度决策,改为轮询优先级队列——该修改使最坏执行时间(WCET)分析误差率从18.4%压缩至2.1%(使用RapiTime工具验证)。
认证证据结构化
项目组构建了符合ISO 26262-8:2018 Table 6要求的证据矩阵,其中Go特有条目包括:
GO_RUNTIME_MEMORY_SAFETY_EVIDENCE:包含内存池初始化时序图(mermaid)GOROUTINE_DETERMINISM_EVIDENCE:覆盖所有goroutine创建/销毁路径的控制流图
graph LR
A[main.go init] --> B[initSafeHeapPool]
B --> C[registerMPURegions]
C --> D[lockAllOSMemory]
D --> E[disableGC]
E --> F[setGOMAXPROCS 1]
跨域通信安全加固
针对ASIL-D系统中CAN FD与以太网双通道冗余设计,团队开发了canbus/safe模块:所有CAN帧解析强制经过crc32c.Checksum()校验与bounds.SizedBuffer{Size: 64}封装,任何超长payload在ReadFrame()入口即panic——该panic被recover捕获后触发ASIL-D级错误处理状态机,而非传统Go的goroutine崩溃。
开源生态适配进展
Linux Foundation旗下Automotive Grade Linux(AGL)已将Go 1.22的-buildmode=pie支持纳入2024 Q3路线图,重点解决ASIL-D要求的地址空间布局随机化(ASLR)与位置无关可执行文件(PIE)兼容问题。同时,Rust-Go混合编译项目rustgo成功将core::sync::atomic原子操作桥接到Go的sync/atomic,在TI Jacinto 7平台实现纳秒级锁-free计数器,通过TüV Rheinland的ASIL-D工具链认证测试。
