参考资料
本页面整理 sslTrus 远程代码签名服务在不同集成方式中共用的参考信息,包括:
- 代码签名次数计算规则。
- Authenticode 和 RFC 3161 时间戳协议。
- 常用代码签名时间戳服务器。
- 生产环境选择时间戳服务时需要关注的事项。
签名次数计算
签名次数按实际完成的签名动作计算。
简单理解:
一个文件成功完成一次签名 = 一次签名次数
签名次数不是按照源代码文件数量计算,也不是按照一次构建、一次打包或一次 CI/CD Pipeline 计算。
例如:
100 个源代码文件
↓
编译生成 1 个 app.exe
↓
app.exe 成功签名一次
↓
1 次签名
如果一次构建产生:
app.exe
helper.dll
installer.msi
并且三个文件都分别完成签名,则:
签名次数 = 3 次
基本规则
签名次数主要看:
- 最终有哪些文件或对象被签名。
- 每个对象实际完成了多少次签名。
- 使用的是普通客户端签名,还是 KSP、Jarsigner 等底层签名调用方式。
- 构建工具是否自动签名了额外的 EXE、DLL、卸载程序或安装包。
常见签名对象包括:
.exe.dll.msi.msp.sys.cat.jar- 卸载程序,例如
uninstall.exe
只要某个对象实际成功完成一次签名,就按照对应的计次规则计算。
成功才计次
只有远程代码签名服务成功完成签名,才产生签名次数。
以下情况通常不计次:
- 鉴权失败。
- 参数错误。
- 证书不可用。
- 网络请求失败。
- 服务端没有成功返回签名结果。
- 查询证书。
- 查询签名记录。
- 验证签名。
- 移除已有签名。
- 生成验证文件。
如果远程服务已经成功返回签名结果,但客户端随后在本地写入文件、添加时间戳或执行后续处理时失败,则已经完成的远程签名仍然按照成功签名计算。
时间戳不单独计次
时间戳用于证明签名在特定时间已经存在,不属于新的代码签名操作。
因此:
代码签名 → 产生签名次数
添加时间戳 → 不额外产生签名次数
验证签名 → 不产生签名次数
时间戳服务是否成功,只影响最终签名文件的时间戳结果,不代表额外执行了一次代码签名。
SignTool CLI
使用 sslTrus SignTool CLI:
signtool sign \
--cert-code CERT_CODE \
--file app.exe
如果签名成功:
1 个文件 × 1 次成功签名 = 1 次
例如:
signtool sign --cert-code CERT_CODE --file app.exe
signtool sign --cert-code CERT_CODE --file helper.dll
signtool sign --cert-code CERT_CODE --file installer.msi
三个文件全部成功:
合计 = 3 次
SignTool CLI 双签
如果使用普通 SignTool CLI 同时启用 SHA-1 和 SHA-2:
signtool sign \
--cert-code CERT_CODE \
--file app.exe \
--sha1=true \
--sha2=true
普通 CLI 双签按照一个客户端签名任务计算:
GUI / SignTool CLI 双签 = 1 次
这是普通客户端签名流程与 KSP 底层签名调用最容易混淆的地方。
Windows KSP
KSP 是 Windows CNG Provider 集成方式。
Microsoft SignTool、MSBuild、Visual Studio、Electron 打包工具或其他 Windows 软件通过 KSP 调用远程代码签名时,计次更接近:
底层远程私钥签名调用次数
例如:
| 操作 | 签名次数 |
|---|---|
对 app.exe 执行一次 SHA256 签名 | 1 次 |
| 先执行 SHA256,再追加 SHA1 | 2 次 |
分别签名 app.exe、helper.dll、uninstall.exe | 3 次 |
因此:
SignTool CLI 双签 = 1 次
KSP 双签 = 2 次
如果工具对同一个文件执行多次底层签名操作,每次成功的远程签名都会分别计算。
CSP
CSP 是传统 Windows CryptoAPI Provider。
CSP 同样由 Microsoft SignTool 或其他 Windows 应用通过 Provider 调用远程签名服务。
判断签名次数时,应以实际发生的远程私钥签名操作为准。
如果工具分别对多个文件或对同一个文件执行多次签名,应分别计算。
Jarsigner
使用 sslTrusJarsigner Provider 时,标准 jarsigner 会在签名过程中调用远程代码签名服务。
通常:
| 操作 | 签名次数 |
|---|---|
对 app.jar 签名 | 1 次 |
| 对 3 个 JAR 分别签名 | 3 次 |
| 对同一个 JAR 再执行一次签名 | 再增加 1 次 |
jarsigner -verify | 0 次 |
| 生成验证用 keystore | 0 次 |
因此:
每个 JAR 每次成功完成签名 = 1 次
安装包
安装包需要区分:
- 安装包内部的可执行文件。
- 安装包本身。
例如:
app.exe → 签名 1 次
installer.msi → 签名 1 次
则:
合计 = 2 次
如果还有其他文件:
| 文件 | 是否签名 | 签名次数 |
|---|---|---|
app.exe | 是 | 1 |
helper.dll | 是 | 1 |
driver.sys | 是 | 1 |
installer.msi | 是 | 1 |
| 合计 | 4 |
安装包中包含多少源代码、资源文件、图片或配置文件不会直接影响签名次数。
关键是:
最终到底有哪些产物被实际签名
Electron
Electron Builder、Electron Forge 等桌面应用构建工具可能在一次打包过程中自动签名多个文件。
常见对象包括:
- 主程序
.exe - DLL
- 更新程序
- 卸载程序
- 安装包
.exe - MSI
- 其他辅助可执行文件
例如:
| 产物 | 签名次数 |
|---|---|
MyApp.exe | 1 |
ffmpeg.dll | 1 |
update.exe | 1 |
uninstall.exe | 1 |
MyApp Setup.exe | 1 |
| 合计 | 5 |
因此:
一次 Electron Build ≠ 一次签名
应该根据实际签名的产物数量和每个产物执行的签名次数计算。
如果 Electron 使用 KSP,并对同一个文件执行双签,该文件还可能产生两次远程签名。
快速判断
不知道一次构建会产生多少签名次数时,可以依次确认:
1. 最终有哪些文件被签名?
2. 每个文件签了几次?
3. 使用的是 SignTool CLI 还是 KSP / Jarsigner?
4. 构建工具有没有自动签额外文件?
可以简单理解为:
签名次数 = 成功完成的签名动作数量之和
特别注意:
GUI / SignTool CLI 双签 = 1 次
KSP 对同一个文件执行两次底层签名 = 2 次
Jarsigner 每个 JAR 每次成功签名 = 1 次
时间戳 = 0 次
验证签名 = 0 次
时间戳服务器
代码签名通常会同时使用时间戳服务。
时间戳可以证明数字签名在特定时间已经存在,从而使验证方能够结合签名证书、时间戳证书、撤销状态和验证策略判断签名的有效性。
代码签名常见两种时间戳协议:
| 协议 | 说明 |
|---|---|
| Authenticode | Microsoft 传统时间戳协议,主要用于兼容旧式 Windows 代码签名流程 |
| RFC 3161 | 通用时间戳协议,适合现代代码签名场景 |
现代代码签名场景通常优先使用 RFC 3161。
RFC 3161
RFC 3161 时间戳请求发送的是待时间戳数据的摘要,而不是原始文件。
基本流程:
代码签名
↓
计算待时间戳数据摘要
↓
发送摘要到 TSA
↓
TSA 返回时间戳令牌
↓
写入最终签名
时间戳令牌通常包含:
- 数据摘要。
- 时间戳签发时间。
- TSA 策略。
- TSA 数字签名。
时间戳服务器不会因为添加时间戳而额外消耗 sslTrus 代码签名次数。
常用时间戳服务器
以下端点适用于常见代码签名场景。
生产使用前,应重新确认对应提供商的最新官方文档、服务策略和可用性。
Microsoft
http://timestamp.acs.microsoft.com
主要用于 RFC 3161 时间戳。
适合作为 Windows 现代代码签名场景的时间戳候选。
示例:
--timestamp-rfc3161=http://timestamp.acs.microsoft.com
Microsoft SignTool:
/tr http://timestamp.acs.microsoft.com
/td SHA256
Sectigo
http://timestamp.sectigo.com
支持:
- Authenticode
- RFC 3161
可用于 Windows 和其他支持相应协议的代码签名工具。
Sectigo 对批量调用存在服务侧使用要求,生产系统应根据其当前官方策略控制调用频率。
DigiCert
http://timestamp.digicert.com
支持 RFC 3161,可用于 Microsoft Authenticode 等代码签名场景。
Certum
http://time.certum.pl
支持:
- Authenticode
- RFC 3161
Certum 官方代码签名资料覆盖 Windows 和 Java JAR 签名场景。
GlobalSign
http://timestamp.globalsign.com/tsa/r45standard
当前 GlobalSign 代码签名资料使用该 RFC 3161 时间戳地址。
不建议继续使用已经不在当前官方代码签名文档中的历史 GlobalSign 地址。
SSL.com
http://ts.ssl.com
支持 RFC 3161,不支持传统 Authenticode 时间戳协议。
如果目标签名工具或旧系统对 TSA 使用的密钥算法存在兼容性限制,应在生产接入前进行实际验证。
时间戳服务器对比
| 提供商 | 地址 | Authenticode | RFC 3161 |
|---|---|---|---|
| Microsoft | http://timestamp.acs.microsoft.com | 未确认 | 支持 |
| Sectigo | http://timestamp.sectigo.com | 支持 | 支持 |
| DigiCert | http://timestamp.digicert.com | 未确认 | 支持 |
| Certum | http://time.certum.pl | 支持 | 支持 |
| GlobalSign | http://timestamp.globalsign.com/tsa/r45standard | 未确认 | 支持 |
| SSL.com | http://ts.ssl.com | 不支持 | 支持 |
表中的“支持”描述的是对应提供商公开资料所确认的协议能力。
时间戳服务策略可能发生变化,生产配置前应重新核对提供商当前官方资料。
受限时间戳服务
部分时间戳服务器虽然提供 RFC 3161 服务,但不能直接作为匿名公共 TSA 使用。
QuoVadis
公开的 RFC 3161 地址包括:
http://ts.quovadisglobal.com/eu
http://ts.quovadisglobal.com/ch
该服务要求预先注册调用方出口 IP,因此接入前需要完成相应授权。
Apple
http://timestamp.apple.com/ts01
属于 Apple 代码签名生态使用的时间戳服务。
不应将其直接作为 Windows Authenticode 的通用时间戳服务器。
测试型时间戳服务
某些公开 RFC 3161 服务更适合协议测试,而不是直接作为生产代码签名 TSA。
例如:
https://freetsa.org/tsr
这类服务可能使用自己的 CA 和 TSA 证书。
因此不能假定:
Windows
macOS
Java
其他代码签名验证器
默认都会信任其证书链。
生产环境应使用目标平台实际验证签名产物。
生产环境检查
将一个时间戳服务器加入生产配置前,建议至少确认:
- 服务商官方资料明确公布该端点。
- 服务商明确支持所需时间戳协议。
- 使用 SHA-256 或更强的时间戳摘要算法。
- 目标系统能够验证 TSA 的完整证书链。
- DNS、代理、防火墙和出口网络可以稳定访问 TSA。
- 已确认认证方式、速率限制、区域限制和服务条款。
- 使用实际签名产物完成验签测试。
不要仅通过:
浏览器可以打开
HTTP 返回 200
判断时间戳服务器是否适合代码签名。
必须使用实际签名工具发送时间戳请求,并对最终产物执行验证。
时间戳选择建议
对于现代 Windows SHA-2 代码签名,通常优先选择支持 RFC 3161 的时间戳服务。
例如:
Microsoft
Sectigo
DigiCert
Certum
GlobalSign
最终选择应综合考虑:
- 目标操作系统。
- 签名工具。
- TSA 证书链。
- 网络可达性。
- 区域限制。
- 调用频率限制。
- 服务条款。
- 服务等级协议。
- 实际签名产物验证结果。
如果证书提供商对时间戳服务有明确要求,应优先遵循对应证书策略和服务商要求。
相关集成方式
不同集成方式会使用本页中的签名次数和时间戳规则:
| 使用场景 | 文档 |
|---|---|
| SignTool CLI | 客户端工具 |
| Windows KSP / CSP | Windows Provider |
| Jarsigner | Java 集成 |
| GitHub Actions、Electron Builder、Advanced Installer | CI/CD 与构建工具 |
| 直接调用远程签名接口 | API 集成 |