14

我最近负责用 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 密钥库中?我什至走在正确的轨道上吗?

提前致谢!

4

2 回答 2

18

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

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

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

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

关于 KeychainStore 的编辑:

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

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

对此有几点注意事项:

  • 任何非空、非空密码都可以使用私钥(例如"-".toCharArray()),因为操作系统的安全服务将提示访问(就像在其他应用程序中一样)。
  • 据我所知,仍然存在一个错误,它只允许访问一个私钥/证书对(即使钥匙串中存在多对私钥/证书对)
于 2010-09-01T01:20:04.323 回答
3

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

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

当您不使用客户端身份验证而仅使用服务器身份验证时(并且私钥不会添加到密钥库,因为它属于服务器),最好使用 KeyStore.getInstance("JKS"),而不是添加多个证书该密钥库的别名。

When you are using PKCS12, as far as I know, you can only add 1 certificate(you have to add the whole certificate chain) associated with the private key, you want to use for that certificate.

于 2010-11-30T08:17:56.080 回答