来自 CA 的 PKCS12 Java 密钥库和 Java 中的用户证书

Posted

技术标签:

【中文标题】来自 CA 的 PKCS12 Java 密钥库和 Java 中的用户证书【英文标题】:PKCS12 Java Keystore from CA and User certificate in java 【发布时间】:2011-04-06 13:37:07 【问题描述】:

我最近负责用 Java 模拟 Apple 产品(iPhone 配置实用程序)。我有点卡住的部分之一是关于 Exchange ActiveSync 的部分。在那里,它允许您从钥匙串中选择一个证书以用作您的 EAS 帐户的凭据。经过一番研究,我发现它实际上是在创建一个 PKCS12 密钥库,插入我选择的证书的私钥,并将其编码为 XML。到目前为止没什么大不了的。如果我使用 Keychain Access 创建一个 .p12 文件,它会毫无问题地上传。但是当我尝试将它带到 Java 时遇到了问题。

假设我将之前与 .p12 文件一起使用的那些证书之一导出为 .cer 文件(这是我们期望在环境中获得的)。现在,当我将它上传到 Java 中时,我得到一个 Certificate 对象,如下所示...

KeyStore ks = java.security.KeyStore.getInstance("PKCS12");
ks.load(null, "somePassword".toCharArray());

CertificateFactory cf = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());
java.security.cert.Certificate userCert  = cf.generateCertificate(new FileInputStream("/Users/me/Desktop/RecentlyExportedCert.cer"));

但是当我尝试...

ks.setCertificateEntry("SomeAlias", userCert);

我得到了异常...

java.security.KeyStoreException: TrustedCertEntry not supported

所以我从证书转到密钥。但是有了这些证书(我也得到了 CA 证书),我只能访问公钥,而不能访问私钥。如果我尝试像这样添加公钥......

java.security.cert.Certificate[] chain = CACert;
ks.setKeyEntry("SomeAlias", userCert.getPublicKey().getEncoded(), chain);

我明白了……

java.security.KeyStoreException: Private key is not stored as PKCS#8 EncryptedPrivateKeyInfo: java.io.IOException: DerValue.getOctetString, not an Octet String: 3

所以现在我来了。有谁知道如何从 .cer 文件中获取私钥到 Java 中的 PKCS12 密钥库中?我是否走在正确的轨道上?

提前致谢!

【问题讨论】:

【参考方案1】:

http://www.docjar.com/html/api/org/bouncycastle/jce/examples/PKCS12Example.java.html

这是将带有关联私钥的证书添加到 PKCS12 密钥库的方法。 当您使用客户端身份验证时,密钥库还需要包含私钥,在这种情况下您使用 KeyStore.getInstance("PKCS12")。

当你不使用客户端认证而只使用服务器认证(并且私钥不会添加到密钥库,因为它属于服务器)时,最好使用 KeyStore.getInstance("JKS"),然后您可以将多个具有别名的证书添加到该密钥库。

当您使用 PKCS12 时,据我所知,您只能添加 1 个与您想要用于该证书的私钥关联的证书(您必须添加整个证书链)。

【讨论】:

【参考方案2】:

PKCS#12 格式用于存储与证书链关联的私钥,两者都是必需的(尽管您可能不需要整个链)。 尽管 PKCS12 密钥库类型在将此格式映射到 Java KeyStore 方面做得很好,但并非所有内容都因此受到支持。

您在第一次尝试时尝试做的是自己存储证书,这是行不通的。

您在第二次尝试 (ks.setKeyEntry("SomeAlias", userCert.getPublicKey().getEncoded(), chain)) 中尝试做的是使用公钥代替应该是私钥的内容(请参阅 KeyStore#setKeyEntry)。

.cer 文件往往只用于证书而不是私钥(当然,扩展名最终只是一个指示)。如果您从 Keychain Access.app 导出您的 .cer 文件,您将无法获得私钥(这就是 .p12 导出格式的用途)。

编辑关于 KeychainStore:

如果您尝试进行此转换的原因最终是为了访问钥匙串中已经存在的私钥和证书,您可以直接从KeychainStore 加载它们:

KeyStore ks = KeyStore.getInstance("KeychainStore", "Apple");
ks.load(null, "-".toCharArray());

对此有几点说明:

任何非空、非空密码都可以使用私钥(例如"-".toCharArray()),因为操作系统的安全服务会提示访问(就像在其他应用程序中一样)。 据我所知,仍然存在错误和it only allows access to one private key/certificate pair(即使钥匙串中存在多对私钥/证书对)

【讨论】:

正确。感谢您的信息!

以上是关于来自 CA 的 PKCS12 Java 密钥库和 Java 中的用户证书的主要内容,如果未能解决你的问题,请参考以下文章

ktor sslConnector 从 jar p12 pkcs12 jks 密钥库和 mtls 相互 ssl 连接中服务/读取

如何从字符串获取 PKCS8 RSA 私钥/从 XML 获取 RSA 密钥对

如何以编程方式在 OpenSSL 中加载 PKCS#12 文件?

CA证书申请认证原理

使用OpenSSL创建多级CA证书链签发证书并导出为pkcs12/p12/pfx文件

如何使用 keytool 列出存储在 PKCS12 密钥库中的证书?