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

2022-09-04 01:52:43

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

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

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

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

提前致谢!


答案 1

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

在第一次尝试中,您尝试执行的操作是单独存储证书,这不起作用。

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

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

编辑关于钥匙串商店:

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

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

对此有几点说明:

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

答案 2

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

这是如何将具有关联私钥的证书添加到 PKCS12 密钥库的方法。使用客户机认证时,密钥库还需要包含私钥,在这种情况下,您需要使用 KeyStore.getInstance(“PKCS12”)。

如果您不使用客户机认证,而只使用服务器认证(并且私钥不会添加到密钥库,因为它属于服务器),则最好使用 KeyStore.getInstance(“JKS”),而不是将多个具有别名的证书添加到该密钥库。

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


推荐