java keystore pem_关于ssl:以编程方式将PEM证书导入Java KeyStore

我有一个客户端证书,由两个文件(.CRT和.Key)组成,我希望将其导入到Java密钥存储库中,然后在SSLVIEW中使用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);

}

}

Stacktrace:

java.io.IOException: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

at me.failedshack.ssltest.SSLTest.createSSLContext(SSLTest.java:80)

at me.failedshack.ssltest.SSLTest.main(SSLTest.java:31)

Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:216)

at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)

at me.failedshack.ssltest.SSLTest.createSSLContext(SSLTest.java:62)

... 1 more

Caused by: java.security.InvalidKeyException: invalid key format

at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:330)

at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:355)

at java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.(RSAPrivateCrtKeyImpl.java:91)

at java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)

at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:315)

at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:212)

... 3 more

遗憾的是,在从文件生成私钥时,我一直得到一个InvalidKeyException。

堆栈跟踪。注意,你不应该叫setCertificateEntry(),只叫setKeyEntry()。

您还需要用KeyManager而不是TrustManager初始化SSLContext。否则将永远找不到您的私钥。

您也不能将私钥强制转换为公钥。这些都没有什么意义。

@EJP对PublicKey的演员阵容感到抱歉,这是我在玩的东西,不小心抄到了问题上。你说得对,钥匙管理器的事。我修改了这个问题。

好吧,这个例外只能说明它所说的:密钥文件有问题。你能用openssl读吗?

@EJP只是试了一下,没有抱怨什么。

EJPS: OpenSSL可以根据类型(RSA 4)透明地为PrimeAtKEY读取几个PEM格式,但是Java,除非您添加BC,根本不能读取PEM,而只有一种DER格式(PKCS8未加密)。

RSA PRIVATE KEY类型的pem文件是base64而不是二进制文件,更重要的是pkcs1格式不是pkcs8,因此不能作为PKCS8EncodedKeySpec处理。

您的选择是:

将PKCS1 PEM格式转换为PKCS8(未加密)PEM格式;读取并删除头和尾部行,并将Base64解码为二进制,并将其放在EDCOX1×1中,但您不需要外部工具,而且将私有密钥+证书(或链)转换为已经是Java密钥存储和AV的PKCS12(DER)也同样容易。回避这个问题

将pkcs1 pem格式转换为pkcs8(未加密)der格式,您只需将其作为二进制文件读取并放入PKCS8EncodedKeySpec--同上

如果pkcs1 pem是未加密的,则按照上述方法将其读取并解码为pkcs1 der,然后手动构造pkcs8(未加密)编码,并使用它

如果pkcs1 pem是加密的,您可以检测到它的主体除了base64之外还包含两个822样式的头行,那么您必须复制openssl的"遗留"密钥文件解密,再构造pkcs8(未加密)编码。

如果您可以使用bouncycastle,特别是bcpkix,它可以直接读取和解析openssl用于私钥的所有PEM变量,包括解密加密的PEM变量;但是,如果您还没有使用它,这是安装和/或部署的额外jar

请参阅以下一个或多个副本:向KeyStore(Java)加载证书(Q使用PojCyCARS构建PKCS8)Java:将DKIM私钥从RSA转换为DER,用于JavaMail(我的答案用手构造PKCS8)如何从文件加载RSA私钥(使用BouncyCastle读取)读取Java中的pkCS1格式的RSA私钥(使用PosiCyCar读取)从rsa.pem文件获取私钥(使用bc解密)用Java解密OpenSSL PEM编码的RSA私钥?(手动解密)可能是RSA私钥的pkcs_1和pkcs_8格式(背景)"begin rsa private key"和"begin private key"的区别(背景)

非常感谢您的澄清,我选择使用BouncyCastle来读取私钥,并且似乎正在做它的工作。但是,我无法获得要处理的请求,我得到以下异常:"pkix路径生成失败:sun.security.provider.certpath.suncertpathbuilderexception:找不到请求目标的有效证书路径"。我读到这意味着证书不可信。我使用的代码与问题中的代码相同,只是我更改了几行代码,用BouncyCastle加载私钥。

这是一个不同的问题;您在keymanager中加载的用于验证您自己身份的privatekey+cert与trustmanager验证任何其他方(反之亦然)完全不同,与之毫无关系。但是您发布的代码似乎使用了一个没有初始化的tmf,这根本不起作用,并且抛出了一个与您所说的完全不同的异常。请检查您的代码,并(如果您仍然有问题)将您尝试连接时使用的信任库添加到您的Q中。

我以为我已经更新了问题中的代码,但显然没有。我正试图做到这一点:github.com/plailect/plaicdn/blob/master/plaicdn.py l123

现在,我尝试用openssl手动将证书和密钥导入到pkcs12密钥存储库,并按照下面的说明加载它:stackoverflow.com/questions/21223084/…但是在连接时一直收到相同的消息,我觉得此时应该打开一个新问题。

(1)好的,您的代码现在有效地使用(或者更确切地说,让JSSE使用)默认信任库(2)该python中引用的两个主机提供由"任天堂CA-G3"颁发的叶证书。CA当然不在Java默认CA列表中,尽管我不知道哪个商店(您的?)如果这个CA在任何标准的分布式CA列表中,而不进行任何修改,那么Python会使用我会非常惊讶的。您确定没有(按照一些说明或设置过程)将该证书添加到系统上的存储区吗?

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值