我有一个由两个文件(.crt 和 .key)组成的客户端证书,我希望将其导入到 java KeyStore 中,然后在 SSLContext 中使用,以通过 Apache 的 HTTPClient 发送 HTTP 请求。但是,我似乎找不到一种以编程方式执行此操作的方法,我发现的大多数其他问题要么指向外部工具,要么不适合我的情况。
我的证书使用典型的“BEGIN 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);
}
}
堆栈跟踪:
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)
... 1 更多
引起原因:java.security.InvalidKeyException:密钥格式无效
在 java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:330)
在 java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:355)
在 java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.(RSAPrivateCrtKeyImpl.java:91)
在 java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
在 java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:315)
在 java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:212)
... 3 更多
遗憾的是,当我从文件生成私钥时,我不断收到 InvalidKeyException 异常。
类型的 PEM 文件RSA PRIVATE KEY
是 base64 不是二进制,更重要的是采用 PKCS1 格式而不是 PKCS8,因此不能作为PKCS8EncodedKeySpec
.
您的选择是:
将 PKCS1 PEM 格式转换为 PKCS8(未加密)PEM 格式;读取该内容并删除标头和尾部行,将 Base64 解码为二进制并将其放入PKCS8EncodedKeySpec
-- 但你说你不需要外部工具,而且将私钥 PLUS 证书(或链)转换为 PKCS12 (DER) 也同样容易alreadyJava 密钥库并避免该问题
将 PKCS1 PEM 格式转换为 PKCS8(未加密)DER 格式,您可以将其作为二进制读取并放入PKCS8EncodedKeySpec
——同上
如果 PKCS1 PEM 未加密,请按照上述方式将其读取并解码为 PKCS1 DER,然后手动构建 PKCS8(未加密)编码,并使用该编码
如果 PKCS1 PEM 已加密(您可以检测到它,因为除了 base64 之外,它的主体还包含两个 822 样式的标题行),您必须复制 OpenSSL 的“旧版”密钥文件解密,再加上构建 PKCS8(未加密)编码
如果你可以专门使用 BouncyCastlebcpkix
,可以直接读取解析allOpenSSL 用于私钥的 PEM 变体,包括解密加密的私钥;但是,如果您尚未使用它,则需要安装和/或部署一个额外的 jar
查看以下一个或多个骗局:
加载证书到KeyStore (JAVA) https://stackoverflow.com/questions/50514553/load-certificate-to-keystore-java(Q使用BouncyCastle构建PKCS8)
Java:将 DKIM 私钥从 RSA 转换为 JavaMail 的 DER https://stackoverflow.com/questions/23709898/java-convert-dkim-private-key-from-rsa-to-der-for-javamail(我的答案“手动”构造 PKCS8)
如何从文件加载 RSA 私钥 https://stackoverflow.com/questions/3243018/how-to-load-rsa-private-key-from-file(使用 BouncyCastle 阅读)
JAVA读取PKCS1格式的RSA私钥 https://stackoverflow.com/questions/41934846/read-rsa-private-key-of-format-pkcs1-in-java(使用 BouncyCastle 阅读)
从 RSA .pem 文件获取私钥 https://stackoverflow.com/questions/44681737/get-a-privatekey-from-a-rsa-pem-file(使用BC解密)
使用 Java 解密 OpenSSL PEM 编码的 RSA 私钥? https://stackoverflow.com/questions/35276820/decrypting-an-openssl-pem-encoded-rsa-private-key-with-java(手动解密)
maybe RSA 私钥的 PKCS#1 和 PKCS#8 格式 https://stackoverflow.com/questions/48958304/pkcs1-and-pkcs8-format-for-rsa-private-key(背景)
and “BEGIN RSA PRIVATE KEY”和“BEGIN PRIVATE KEY”之间的区别 https://stackoverflow.com/questions/20065304/differences-between-begin-rsa-private-key-and-begin-private-key(背景)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)