java - 将证书链保存在 pkcs12 keystore 中

标签 java security ssl bouncycastle digital-certificate

以下代码:

//used Bouncy Castle provider for keyStore
keyStore.setKeyEntry(alias, (Key)keyPair.getPrivate(), pwd, certChain);  

其中 certChain 持有最终证书和颁发者证书(即两个证书),
如果 keyStore 是 PKCS12 的实例,则不会将颁发者证书保存为已保存到文件系统 keystore 文件中的链的一部分。

如果 keystore 类型是 PKCS12-3DES-3DES,它会保存两个证书。 为什么是这样? PKCS12 不认为两个证书都是链的一部分吗?

编辑:这是一个 SSCCE .这适用于 "JKS",但适用于 "PKCS12":只有链中的第一个证书可通过 getCertificateChain(String) 访问。保存的文件可以用 openssl pkcs12 打开两个证书。

    public void testKeyStore() {
    try {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        Certificate[] outChain = { createCertificate("CN=CA", publicKey, privateKey), createCertificate("CN=Client", publicKey, privateKey) };

        KeyStore outStore = KeyStore.getInstance("PKCS12");
        outStore.load(null, "secret".toCharArray());
        outStore.setKeyEntry("mykey", privateKey, "secret".toCharArray(), outChain);            
        OutputStream outputStream = new FileOutputStream("c:/outstore.pkcs12");
        outStore.store(outputStream, "secret".toCharArray());
        outputStream.flush();
        outputStream.close();

        KeyStore inStore = KeyStore.getInstance("PKCS12");      
        inStore.load(new FileInputStream("c:/outstore.pkcs12"), "secret".toCharArray());
        Key key = outStore.getKey("myKey", "secret".toCharArray());
        assertEquals(privateKey, key);

        Certificate[] inChain = outStore.getCertificateChain("mykey");
        assertNotNull(inChain);
        assertEquals(outChain.length, inChain.length);
    } catch (Exception e) {
        e.printStackTrace();
        fail(e.getMessage());
    }
}

private static X509Certificate createCertificate(String dn, PublicKey publicKey, PrivateKey privateKey) throws Exception {
    X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
    certGenerator.setSerialNumber(new BigInteger("1"));
    certGenerator.setIssuerDN(new X509Name(dn));
    certGenerator.setSubjectDN(new X509Name(dn));
    certGenerator.setNotBefore(Calendar.getInstance().getTime());
    certGenerator.setNotAfter(Calendar.getInstance().getTime());
    certGenerator.setPublicKey(publicKey);
    certGenerator.setSignatureAlgorithm("SHA1withRSA");
    X509Certificate certificate = (X509Certificate)certGenerator.generate(privateKey, "BC");
    return certificate;
}

最佳答案

您的代码有 2 个错误:

第一:您没有为证书设置颁发者(客户端证书应该由CA颁发才能使链有效)。

第二个:你在创建证书链时使用了错误的顺序(应该是客户端证书,最后是CA)

这里是重做的 SSCCE,它可以正常工作。

@Test
public void testKeyStore() throws Exception{
        try {
        String storeName =  "/home/grigory/outstore.pkcs12";
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        Certificate trustCert =  createCertificate("CN=CA", "CN=CA", publicKey, privateKey);
        Certificate[] outChain = { createCertificate("CN=Client", "CN=CA", publicKey, privateKey), trustCert };

        KeyStore outStore = KeyStore.getInstance("PKCS12");
        outStore.load(null, "secret".toCharArray());
        outStore.setKeyEntry("mykey", privateKey, "secret".toCharArray(), outChain);
        OutputStream outputStream = new FileOutputStream(storeName);
        outStore.store(outputStream, "secret".toCharArray());
        outputStream.flush();
        outputStream.close();

        KeyStore inStore = KeyStore.getInstance("PKCS12");
        inStore.load(new FileInputStream(storeName), "secret".toCharArray());
        Key key = outStore.getKey("myKey", "secret".toCharArray());
        Assert.assertEquals(privateKey, key);

        Certificate[] inChain = outStore.getCertificateChain("mykey");
        Assert.assertNotNull(inChain);
        Assert.assertEquals(outChain.length, inChain.length);
    } catch (Exception e) {
        e.printStackTrace();
        throw new AssertionError(e.getMessage());
    }
   }
    private static X509Certificate createCertificate(String dn, String issuer, PublicKey publicKey, PrivateKey privateKey) throws Exception {
        X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
        certGenerator.setSerialNumber(BigInteger.valueOf(Math.abs(new Random().nextLong())));
        certGenerator.setSubjectDN(new X509Name(dn));
        certGenerator.setIssuerDN(new X509Name(issuer)); // Set issuer!
        certGenerator.setNotBefore(Calendar.getInstance().getTime());
        certGenerator.setNotAfter(Calendar.getInstance().getTime());
        certGenerator.setPublicKey(publicKey);
        certGenerator.setSignatureAlgorithm("SHA1withRSA");
        X509Certificate certificate = (X509Certificate)certGenerator.generate(privateKey, "BC");
        return certificate;
    }

关于java - 将证书链保存在 pkcs12 keystore 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13207378/

相关文章:

java - 可以向 Java 小程序添加什么安全性?

java - 具有多个参数的ArrayList(用户输入)

java - 从 Java 中的 blob 内容创建文件的代码片段

java - 获取图像周围的像素颜色

java - spring-hateoas,如何使用 onMethod 构建超媒体链接时设置占位符值

javascript - 如何将表记录标识符传递给客户端

android - 如何使 'android unlocker' 应用程序更安全地抵御黑客攻击?

.htaccess - AWS负载均衡器: 503 (Service Unavailable: Back-end server is at capacity)

python - mitmproxy 反向代理 - 仅在非标准端口上需要 SSL

Azure Http 到 Https 重定向不适用于 SPA