首页 > 解决方案 > 签署 jar 文件时的证书链接

问题描述

如何在签署 jar 文件时引入一级证书链?我想做的是,

  1. 使用生成的私钥对 jar 进行签名。
  2. 生成 CSR(证书签名请求)
  3. 生成 CA 签名证书,其中 CA 是自签名 CA
  4. 在 jcontrol 和浏览器中导入 CA 并运行 java web start 应用程序。

但不幸的是,它不起作用并发出了安全警告。

请提出一些好的方法。

标签: sslssl-certificatex509certificatetls1.2java-web-start

解决方案


TLDR:首先获得证书

Java 代码签名使用 PKCS7/CMS 签名格式,wbich 基于 X.509/PKIX 公钥证书。您发布的序列使用私钥,就像它神奇地出现一样,但这是不可能的。我敢打赌你的顺序实际上是:

‍0.keytool -genkeypair

尽管名称集中在“生成密钥对”上,但这个命令实际上做了三件事:生成密钥对;为该密钥对的公共部分创建一个虚拟的自签名证书;并将密钥的私有部分和虚拟证书一起存储在密钥库(通常是文件)中。请注意,java.security.KeyStoreAPI 不支持单独存储私钥(或公钥或原始密钥对),仅支持与证书链组合的私钥。(虚拟证书本身就构成了一条微不足道的链。)为了具体起见,我将这个虚拟证书称为 A。

‍1. 使用生成的私钥签署 jar =jarsigner

您指定密钥库中的jarsigner私钥条目,但如上所述,该条目实际上也包含证书链,在本例中为虚拟证书。PKCS7/CMS 签名包含使用私钥计算的原始 PKC 签名(RSA、DSA 或 ECDSA),加上与该私钥匹配的证书,因此可用于验证签名,以及验证所需的任何链证书签名证书。如果您查看META-INF/<alias>.{RSA,DSA,EC}生成的 jar 中条目的内容,您可以看到这一点。

‍2. 生成 CSR(证书签名请求)=keytool -certreq

‍3. 生成 CA 签名证书,其中 CA 是自签名 CA

您如何做到这一点取决于您的 CA,但在这里无关紧要。准确地说,CA 可能拥有 CA 密钥对的公共部分的自签名证书,但如上所述,它实际上使用私有部分签署了它颁发的证书。具体而言,我将调用 CA为签名密钥 B颁发的证书,以及 CA 自己的自签名证书 C。

‍4. 在 jcontrol 和浏览器中导入 CA 并运行 java web start 应用程序。

我不确定您在这里是指 B 还是 C。但两者都无助于验证步骤 1 中完成的签名,因为该签名包含并将 A 指定为“签名者”证书,即用于验证签名的证书。B 是同一公钥的证书堡垒,如果签名指定证书 B,则可用于验证签名,但它没有,也不能,因为在创建签名时 B 甚至不存在。

正确的顺序是:

  1. -genkeypair

  2. -certreq

  3. 使用 CSR 从 CA 获取证书 B。这里实际上不需要 C,尽管您可能会为了方便或参考而得到它。

  4. -importcert将证书 B放入私钥条目中。(如果您将-genkeypair别名默认为mykey您也可以默认-importcert,否则您必须指定相同的别名。)这会将虚拟证书 A替换为私钥条目中的“真实”证书 B。(注意不要将证书 B 导入到不同的别名或不同的密钥库;这通常不会出错。但结果将无法正常工作。)

    如果“真实”证书 B 需要一个或多个链证书来验证,对于来自真实公共 CA(如 Digicert、GoDaddy、LetsEncrypt 等)的证书(总是?)如此,则此类链证书必须是包含在第 4 步中(作为组合文件,通常是“p7b”或“p7c”文件),或在第 4 步之前单独导入到单独的可信证书条目中。但是,您的内部 CA 不需要任何链证书。

  5. 现在jarsigner- 所以签名包括证书 B(以及它的链证书,如果有的话)

    A. 另外,证书 C 必须包含在客户端系统使用的信任库中;这可以在任何时候完成:在步骤 1-5 之后、期间或之前。对于 webstart,我相信将它放在 Java 控制面板中就足够了;浏览器未验证 AFAIK webstart。小程序可能是这样,但小程序已经有好几年没有在浏览器中运行了,也没有在高于 8 的 Oracle Java 中运行。


推荐阅读