我们的 CA GlobalSign 已颁发适用于 HSM 的代码签名证书。我在 Azure 中创建了高级许可的 Key Vault,因为基本版不支持 HSM。然后,我使用以下颁发策略在 Key Vault 中生成了一个证书:
高级策略配置
在密钥保管库中实例化后,我单击“证书操作”并下载 CSR。
我按照 Global Sign 提供的下载链接复制并粘贴了 CSR。证书生成后,我得到了一个可以下载数字证书和 2 个中间证书的页面。文件名是:OS123456789.cer、intermediate1.cer 和 middle2.cer
然后我返回到 Azure Key Vault 并单击“合并签名请求”,然后选择 OS123456789.cer 文件,并且成功了。
然后我开始使用 jarsigner 来签署我的 jar。 我下载了 azure-security-keyvault-jca-2.8.1.jar 并将其放在 %JAVA_HOME&/jre/lib/ext
中我使用的jarsigner命令是这样的:
jarsigner -keystore NONE -storetype AzureKeyVault -verbose -storepass "" -tsa http://timestamp.globalsign.com/tsa/r6advanced1 -providerName AzureKeyVault -providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider -J"-Dazure.keyvault.uri=$KEYVAULT_URL" -J"-Dazure.keyvault.tenant-id=$TENANT" -J"-Dazure.keyvault.client-id=$CLIENT_ID" -J"-Dazure.keyvault.client-secret=$CLIENT_SECRET" -signedjar "signed.jar" "unsigned.jar" $CERT_ALIAS
签名输出如下所示:
updating: META-INF/MANIFEST.MF
adding: META-INF/GLOBALSI.SF
requesting a signature timestamp
TSA location: http://timestamp.globalsign.com/tsa/r6advanced1
adding: META-INF/GLOBALSI.RSA
A BUNCH OF FILES
signing: clientlogging.properties
adding: JNLP-INF/
signing: JNLP-INF/APPLICATION_TEMPLATE.JNLP
>>> Signer
X.509, [email protected], CN=JohnDoe, O=JohnDoe, L=DoeVille, C=US
[trusted certificate]
>>> TSA
X.509, CN=Globalsign TSA for CodeSign1 - R6 - 202311, O=GlobalSign nv-sa, C=BE
[certificate is valid from 07/11/23 18:13 to 09/12/34 18:13]
X.509, CN=GlobalSign Timestamping CA - SHA384 - G4, O=GlobalSign nv-sa, C=BE
[certificate is valid from 20/06/18 02:00 to 10/12/34 01:00]
X.509, CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R6
[trusted certificate]
jar signed.
The timestamp will expire on 2034-12-09.
我认为到目前为止看起来不错。 然而,当我跑步时:
jarsigner -verify -verbose -certs signed.jar
我得到以下输出:
s 291951 Tue Sep 24 12:09:10 CEST 2024 META-INF/MANIFEST.MF
>>> Signer
X.509, [email protected], CN=JohnDoe, O=JohnDoe, L=DoeVille, C=US
[certificate is valid from 20/09/24 16:00 to 03/09/27 14:19]
[Invalid certificate chain: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
>>> TSA
X.509, CN=Globalsign TSA for CodeSign1 - R6 - 202311, O=GlobalSign nv-sa, C=BE
[certificate is valid from 07/11/23 18:13 to 09/12/34 18:13]
X.509, CN=GlobalSign Timestamping CA - SHA384 - G4, O=GlobalSign nv-sa, C=BE
[certificate is valid from 20/06/18 02:00 to 10/12/34 01:00]
X.509, CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R6
[trusted certificate]
292002 Tue Sep 24 12:09:12 CEST 2024 META-INF/GLOBALSI.SF
8401 Tue Sep 24 12:09:12 CEST 2024 META-INF/GLOBALSI.RSA
0 Tue Sep 10 16:47:38 CEST 2024 META-INF/
A BUNCH OF FILES
sm 1111 Tue Sep 10 16:47:36 CEST 2024 JNLP-INF/APPLICATION_TEMPLATE.JNLP
[entry was signed on 24/09/24 12:09]
>>> Signer
X.509, [email protected], CN=JohnDoe, O=JohnDoe, L=DoeVille, C=US
[certificate is valid from 20/09/24 16:00 to 03/09/27 14:19]
[Invalid certificate chain: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
>>> TSA
X.509, CN=Globalsign TSA for CodeSign1 - R6 - 202311, O=GlobalSign nv-sa, C=BE
[certificate is valid from 07/11/23 18:13 to 09/12/34 18:13]
X.509, CN=GlobalSign Timestamping CA - SHA384 - G4, O=GlobalSign nv-sa, C=BE
[certificate is valid from 20/06/18 02:00 to 10/12/34 01:00]
X.509, CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R6
[trusted certificate]
s = signature was verified
m = entry is listed in manifest
k = at least one certificate was found in keystore
i = at least one certificate was found in identity scope
Signed by "[email protected], CN=JohnDoe, O=JohnDoe, L=DoeVille, C=US"
Digest algorithm: SHA-256
Signature algorithm: SHA256withRSA, 4096-bit key
Timestamped by "CN=Globalsign TSA for CodeSign1 - R6 - 202311, O=GlobalSign nv-sa, C=BE" on Tue Sep 24 10:09:12 UTC 2024
Timestamp digest algorithm: SHA-256
Timestamp signature algorithm: SHA256withSHA256withRSA, 3072-bit key
jar verified.
Warning:
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
The signer certificate will expire on 2027-09-03.
The timestamp will expire on 2034-12-09.
验证失败并出现以下警告:
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
据我了解,发生这种情况是因为它无法确定 CA 的信任链。 然后,我使用 keytool 将中间证书导入到位于我的主目录下的本地密钥库中。然后我再次对 jar 文件进行签名,这次 jarsigner 能够验证 jar 文件而不会出现任何警告。
但是,当我部署 java 应用程序并且用户下载 jnlp 文件并尝试安装 java 应用程序时,他们会收到一个警告弹出窗口,指出签名的应用程序不受信任。
我们正在使用 java 8。尝试了最新的 Amazon Corretto 和 Oracles
我的问题是:
感谢您提供的任何帮助。
我能够弄清楚。 您需要通过 -certchain 选项将证书信任链作为 pem 文件提供给 jarsigner。 这是正确的命令:
jarsigner -certchain trustchain.pem -keystore NONE -storetype AzureKeyVault -verbose -storepass "" -tsa http://timestamp.globalsign.com/tsa/r6advanced1 -providerName AzureKeyVault -providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider -J"-Dazure.keyvault.uri=$KEYVAULT_URL" -J"-Dazure.keyvault.tenant-id=$TENANT" -J"-Dazure.keyvault.client-id=$CLIENT_ID" -J"-Dazure.keyvault.client-secret=$CLIENT_SECRET" -signedjar "signed.jar" "unsigned.jar" $CERT_ALIAS
要创建 pem 文件,您需要将代码签名证书与中间证书连接起来。顺序很重要:
cat codesigner.cer, intermediate1.cer, intermediate.cer > bundle.pem
您还可以使用文本编辑器来组合证书。
当您使用 -verbose 选项运行 jarsigner 并查看完整的信任链时,您就会知道它是有效的:
>>> Signer
X.509, [email protected], CN=JohnDoe, O=JohnDoe, L=DoeVille, C=US
[certificate is valid from 20/09/24 16:00 to 03/09/27 14:19]
X.509, CN=GlobalSign Code Signing Root R45, O=GlobalSign nv-sa, C=BE
[trusted certificate]
X.509, CN=GlobalSign GCC R45 CodeSigning CA 2020, O=GlobalSign nv-sa, C=BE
[trusted certificate]