ssl 以编程方式将PEM证书导入Java KeyStore

6xfqseft  于 2023-08-06  发布在  Java
关注(0)|答案(2)|浏览(158)

我有一个由两个文件(.crt和.key)组成的客户端证书,我希望将其导入到java KeyStore中,然后在SSLContext中使用Apache的HTTPClient发送HTTP请求。然而,我似乎找不到一种方法来以编程的方式做到这一点,我发现的大多数其他问题要么指向外部工具,要么不适合我的情况。
我的证书是用典型的“开始CERTIFICATE”编码的,后面是一个Base64编码的字符串,密钥是“BEGIN RSA PRIVATE KEY”,然后是另一个Base64编码的字符串。
这是我目前得到的:

private static SSLContext createSSLContext(File certFile, File keyFile) throws IOException {
    try {
        PEMParser pemParser = new PEMParser(new FileReader(keyFile));
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(new BouncyCastleProvider());
        Object object = pemParser.readObject();
        KeyPair kp = converter.getKeyPair((PEMKeyPair) object);
        PrivateKey privateKey = kp.getPrivate();

        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        FileInputStream stream = new FileInputStream(certFile);
        X509Certificate cert = (X509Certificate) certFactory.generateCertificate(stream);

        KeyStore store = KeyStore.getInstance("JKS");
        store.load(null);
        store.setCertificateEntry("certificate", cert);
        store.setKeyEntry("private-key", privateKey, "changeit".toCharArray(), new Certificate[] { cert });

        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(store, "changeit".toCharArray())
                .build();
        return sslContext;
    } catch (IOException | NoSuchAlgorithmException | CertificateException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
        throw new IOException(e);
    }
}

字符串
Stacktrace:
java.io.IOException:java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:在me.failedshack.ssltest.SSLTest.createSSLContext(SSLTest.java:80)在me.failedshack.ssltest.SSLTest.main(SSLTest.java:31)处的密钥格式无效
原因:java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:在java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:216)在java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)在me.failedshack.ssltest.SSLTest.createSSLContext(SSLTest.java:62)处的密钥格式无效...再加一个
原因:java.security.InvalidKeyException:java中密钥格式无效。base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:330)。base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:355)。base/sun.security.rsa.RSAPrivateCrtKeyImpl.(RSAPrivateCrtKeyImpl.java:91)。基地/太阳安全rsa RSA PrivateCrtKeyImpl. java中的newKey(RSAPrivateCrtKeyImpl.java:75)。基地/太阳安全rsa RSAKeyFactory。java中的generatePrivate(RSAKeyFactory.java:315)。基地/太阳安全rsa RSAKeyFactory。engineGeneratePrivate(RSAKeyFactory.java:212)... 3更多
不幸的是,当从文件中生成私钥时,我一直得到InvalidKeyException。

efzxgjgh

efzxgjgh1#

RSA PRIVATE KEY类型的PEM文件是base64而不是二进制,更重要的是它是PKCS 1格式而不是PKCS 8格式,因此不能作为PKCS8EncodedKeySpec处理。
您的选择包括:

  • 将PKCS 1 PEM格式转换为PKCS 8(未加密)PEM格式;读它,去掉头行和尾行,将base64解码为二进制,并将其放入PKCS8EncodedKeySpec中--但是您说您不需要外部工具,而且将privatekeyPLUS cert(或链)转换为PKCS 12(DER)(它已经是Java密钥库)也很容易,可以避免这个问题
  • 将PKCS 1 PEM格式转换为PKCS 8(未加密)DER格式,您可以将其读取为二进制并放入PKCS8EncodedKeySpec中--同上
  • 如果PKCS 1 PEM是未加密的,则如上所述将其读取并解码到PKCS 1 DER,然后手动构建PKCS 8(未加密)编码,并使用该编码
  • 如果PKCS 1 PEM是加密的,您可以检测到,因为它的主体除了base64之外还包含两个822风格的标题行,您必须复制OpenSSL的“遗留”密钥文件解密,并构造PKCS 8(未加密)编码
  • 如果你可以专门使用BouncyCastle bcpkix,它可以直接读取和解析 * 所有 * OpenSSL用于私钥的PEM变体,包括解密加密的;但是,如果您还没有使用它,那就是要安装和/或部署额外jar

查看以下一个或多个欺骗:
Load certificate to KeyStore (JAVA)(Q使用BouncyCastle构建PKCS 8)
Java: Convert DKIM private key from RSA to DER for JavaMail(我的答案“手工”构造PKCS 8)
How to Load RSA Private Key From File(使用BouncyCastle读取)
Read RSA private key of format PKCS1 in JAVA(使用BouncyCastle读取)
Get a PrivateKey from a RSA .pem file(使用BC解密)
Decrypting an OpenSSL PEM Encoded RSA private key with Java?(手动解密)
maybe PKCS#1 and PKCS#8 format for RSA private key(background)
Differences between "BEGIN RSA PRIVATE KEY" and "BEGIN PRIVATE KEY"(背景)

nuypyhwy

nuypyhwy2#

使用这个小型库https://github.com/KarlScheibelhofer/java-crypto-tools/tree/main,您可以轻松地加载这种PEM格式的私钥和证书。用更少的代码

KeyStore ks = KeyStore.getInstance("pem", JctProvider.getInstance());
ks.load(new FileInputStream("webserver-key-and-certificate-chain.pem"), password);

字符串
有关示例和更多详细信息,请参见自述文件。

相关问题