将私钥添加到密钥库

4
为了更新某些证书,我不得不将一个jks密钥库转换为PKCS#12密钥库并在转换过程中包含私钥。我们收到的密钥库是JKS密钥库,但是我们的Web服务器使用PKCS#12密钥库,并且我们收到的密钥库仅包含证书而没有私钥。
我试图在Google上搜索并阅读了SO的几个条目,只找到了一种解决方案,这似乎更像是一个变通方法而不是一个好的方法,因此我想知道是否有人有更好的方法来注入私钥并以更简单的方式从jks密钥库转换为PKCS#12密钥库。
看起来只有keytool可以操纵JKS密钥库,但是据我所知,keytool实用程序不支持将私钥注入trustedCertEntries,因此我使用的方法如下:
假设我有私钥作为pem文件。
1. 使用keytool从jks密钥库中提取所有证书。 2. 使用openssl创建PKCS#12密钥库。 3. 重命名使用keytool创建的PKCS12中的别名。 4. 再次使用openssl创建另一个PKCS#12密钥库。 5. 使用keytool重命名另一个创建的PKCS#12中的别名。 6. 使用keytool合并两个密钥库。 7. 导入非私钥证书。
因此,整个流程如下(如果需要):
openssl pkcs12 -in orig.alias.p12 -nodes -nocerts -out key.pem -passin pass:PASSWORD
keytool -keystore keystore1 -storepass PASSWORD -list
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.root.pem -alias "root" -exportcert
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.ca3.pem -alias "ca3" -exportcert
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.long.pem -alias "long" -exportcert
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.short.pem -alias "short" -exportcert
openssl pkcs12 -export -out keystore.p12 -inkey key.pem -in alias.short.pem -passout pass:PASSWORD
keytool -changealias -alias "1" -destalias "short" -keypass PASSWORD -keystore keystore.p12 -storepass PASSWORD
openssl pkcs12 -export -out keystore2.p12 -inkey key.pem -in alias.long.pem -passout pass:PASSWORD
keytool -changealias -alias "1" -destalias "long" -keypass PASSWORD -keystore keystore2.p12 -storepass PASSWORD
keytool -importkeystore -srckeystore keystore2.p12 -srcstoretype pkcs12 -srcstorepass PASSWORD -destkeystore keystore.p12 -deststoretype pkcs12 -deststorepass PASSWORD
keytool -keystore keystore.p12 -storepass PASSWORD -file alias.ca3.pem -alias "ca3" -importcert -noprompt
keytool -keystore keystore.p12 -storepass PASSWORD -file alias.root.pem -alias "root" -importcert  -noprompt
keytool -keystore keystore.p12 -storepass PASSWORD -list

比如说,如果我在导入私钥证书时就能设置别名,那么我就不需要之后再重命名别名了。这个可能吗?

无论如何,提前感谢。


我假设你只需执行此操作一次(或者可能是一年一次)。在这种情况下,我认为基于GUI的程序比那个糟糕的旧keytool要简单得多。我建议使用开源软件[KeyStore Explorer](http://keystore-explorer.org/)。据我所知,它应该能够加载JKS密钥库并将其保存为PKCS#12。 - Robert
这里有一些严重的问题。如果您将私钥发送给其他人,那么您已经致命地危及了它。从他们没有归还私钥的事实来看,似乎他们根本不需要它。无论如何,现在你所需要做的就是将更新后的“证书”导入到原始的JKS密钥库中,该密钥库已经拥有了私钥。但你真的需要重新生成密钥。 - user207421
@EJP或许我没有表述清楚,但私钥从未发送给对方。我只是发送带有公钥签名的CSR,并获得了一个包含证书的.JKS文件。 - M. A. Tanaka
@Robert,这可能是一个可行的解决方案。感谢您的建议。 - M. A. Tanaka
1个回答

4
  1. 通过在pkcs12 -export步骤中使用-name long-name short,您可以消除-changealias步骤。

  2. 对于keystore.p12keystore2.p12,您的输入是key.pem和(cert)alias.short.pem。您是否打算在其中一个中使用(cert)alias.long.pem

  3. 在免费的Oracle Java中,只有较新版本的j8(在java.security中设置keystore.compat)才能读取JKS和P12密钥库而不需要指定类型。默认情况下,j7及更低版本仅执行JKS,j9及更高版本仅执行P12。

  4. 顺便说一句,如果您将原始JKS(带有trustedCert)转换为P12(仅适用于j8+),则openssl pkcs12 -nokeys将在一次操作中输出所有trustedcerts--但由于您需要对它们进行不同的处理,因此您需要将其拆分为单独的文件或按需执行,例如:

    awk '/friendlyName: short/,/-END CERT/' allcerts.pem | \
      openssl pkcs12 -export -inkey key.pem -name short -out file -passout pass:PW
    # similar for long -- or make loop
    # combine the p12s as before
    awk '/friendlyName: root/,/-END CERT/' allcerts.pem | \
      keytool -keystore file -storepass PW -importcert -file root.pem -alias root -noprompt
    # similar for ca3 -- or make loop

... 我不确定这是否真的是一种改进

或者,既然这是SO,您可以编写一个更直接执行此操作的程序:

char[] pw = "PASSWORD".toCharArray(); // or whatever as appropriate
KeyStore ks1 = KeyStore.getInstance("JKS"); ks1.load (new FileInputStream ("certs",pw));
KeyStore ks2 = KeyStore.getInstance("PKCS12"); 
try( InputStream is = new FileInputStream("oldp12") ){ ks2.load(is,pw); }
String alias = ks2.getAliases().nextElement(); // assume only one
PrivateKey key = (PrivateKey) ks2.getKey(alias,pw); 
ks2.deleteAlias(alias); 
ks2.setKeyEntry("short",key,pw,new Certificate[]{ ks1.getCertificate("short") });
ks2.setKeyEntry("long" ,key,pw,new Certificate[]{ ks1.getCertificate("long" ) });
// assuming those combinations are what you intended, see above
ks2.setCertificateEntry("root", ks1.getCertificate("root") );
ks2.setCertificateEntry("ca3" , ks1.getCertificate("ca3" ) );
try( OutputStream os = new FileOutputStream ("newp12") ){ ks2.store(os,pw); }

  1. 是的,这确实可以为我节省两个步骤。
  2. 是的,你说得对。那是一个剪切和粘贴错误,但证书是一样的,只是别名不同。
  3. 感谢提供信息。
  4. 或许这样简化了,但还是感谢提供信息。
Java解决方案似乎很有趣...但我仍然惊讶于将私钥注入密钥库如此复杂...我本以为这是运营团队的标准操作,但也许我错了。
- M. A. Tanaka
我本想给你点赞的,但我需要15个声望点数,所以我只能在评论中这样做。 - M. A. Tanaka
作为提问者,您可以使用检查标记来接受回答(请参见链接),以解决您的问题(或如果有多个解决方案,则选择一个最佳方案)-- 这也意味着该问题不再被列为“未回答”,其他人也就不必再花费时间了。 - dave_thompson_085

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接