Jarsigner签名验证疑问:根证书需求及自定义信任库失效排查
场景背景
使用集成Jsign的jarsigner对JAR文件签名,签名命令如下:
jarsigner -J-cp -J<Path-to-Jsing.jar> -J--add-modules -Jjava.sql -providerClass net.jsign.jca.JsignJcaProvider -providerArg eus.codesigning.azure.net -storetype TRUSTEDSIGNING -keystore NONE -storepass <generated-access-token> "path-to-jar-files-to-sign/installer.jar" <accountName>/<profileName>
执行验证命令:
jarsigner -verify -verbose -certs -strict installer.jar
出现警告:
jar verified, with signer errors.
Error:This jar contains entries whose certificate chain is invalid. Reason: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
将Microsoft 2020根证书添加到JRE信任库后,验证警告消失。
问题1解答
签名过程不需要信任库中的根证书,仅验证阶段需要。
你的测试结果已经直接证明了这一点:用不含根证书的信任库可以正常完成签名操作,仅在验证时需要信任库中的根证书来构建完整的证书链,从而确认签名的合法性。
签名的核心逻辑是使用签名证书(从Azure Trusted Signing获取)对JAR内容执行签名运算,此过程不需要验证证书链的有效性——只要签名私钥可用、能完成签名即可。
问题2解答
使用自定义信任库验证仍报错,通常是以下原因导致:
自定义信任库未正确导入根证书
先确认Microsoft 2020根证书已正确导入到mycacerts中,可通过以下命令检查:keytool -list -keystore C:\path\to\mycacerts -storepass changeit确保输出列表中能看到对应的根证书条目。
参数使用错误
-J-Djavax.net.ssl.trustStore是指定SSL连接的信任库,但jarsigner验证证书链时,默认使用JRE的cacerts信任库,而非SSL信任库。正确指定验证用信任库的参数是-truststore,修改后的验证命令应为:jarsigner -verify -verbose -certs -strict -truststore "C:\path\to\mycacerts" -storepass changeit installer.jar信任库格式不匹配
jarsigner默认使用JKS格式的信任库,如果你的mycacerts是PKCS12等其他格式,需要添加-storetype PKCS12参数。
Jarsigner签名与验证的信任库处理逻辑
签名阶段
- 签名时,jarsigner依赖指定的安全提供者(此处为JsignJcaProvider)获取签名密钥和证书链,不会检查证书链的信任性,仅需确保密钥能正常完成签名操作。
- 信任库在签名阶段的唯一作用是:若签名过程中需要与远程服务(如Azure Trusted Signing)建立SSL连接,会用SSL信任库验证服务端证书,但这与签名本身的证书链有效性无关。
验证阶段
- 验证时,jarsigner需完成两项核心检查:
- JAR内容完整性:确认签名与内容匹配,未被篡改。
- 签名证书合法性:构建完整的证书链,从签名证书向上追溯到信任库中的根证书,只有整个链都被信任时,才会判定签名有效。
- 默认情况下,jarsigner使用JRE默认的
cacerts信任库;也可通过-truststore参数指定自定义信任库,替代默认库。
内容的提问来源于stack exchange,提问作者priyanka

