我有两个文本文件,一个带有“-----BEGIN CERTIFICATE-----
”标题,另一个带有“-----BEGIN RSA PRIVATE KEY-----
”标题。我需要使用CXF ClientBuilder来对远程主机进行REST服务调用。
我认为我加载的cert文件没问题,但我无法弄清楚如何正确处理私钥文件。
我有以下暂定代码(尚未完全编译,正如您所见)初始化Client对象(带有一些小的缺点):
private Certificate buildCertFromFile(String fileName) throws CertificateException {
return CertificateFactory.getInstance("X.509").generateCertificate(ClassLoaderUtils.getResourceAsStream(fileName, <ThisClass>.class));
}
@PostConstruct
public void init() {
try {
KeyStore trustStore = KeyStore.getInstance("jks");
trustStore.load(null, null);
trustStore.setCertificateEntry("cert", buildCertFromFile("<path to cert file>"));
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(null, "abc".toCharArray());
// Need something here.
keyStore.setKeyEntry("key", key, "abc", chain);
ClientBuilder builder = ClientBuilder.newBuilder();
builder.trustStore(trustStore);
builder.keyStore(keyStore, "abc");
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String host, SSLSession session) {
try {
Certificate[] certs = session.getPeerCertificates();
return certs != null && certs[0] instanceof X509Certificate;
}
catch (SSLException ex) {
return false;
}
}
});
client = builder.build();
}
catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException ex) {
ex.printStackTrace();
}
}
更新
我正在尝试使用以下方法加载私钥文件:
public static PrivateKey getPrivateKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
String contents = IOUtils.toString(ClassLoaderUtils.getResourceAsStream(filename, TguardService.class), "UTF-8");
contents = contents.replaceAll("-----[A-z ]+-----", "").trim();
System.out.println("contents[" + contents + "]");
byte[] bytes = Base64.getDecoder().decode(contents);
System.out.println("decoded[" + new String(bytes) + "]");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
但是,这给了我以下错误:
Caused by: java.lang.IllegalArgumentException: Illegal base64 character a
at java.util.Base64$Decoder.decode0(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at com.att.detsusl.tguardrest.TguardService.getPrivateKey(TguardService.java:58)
调试输出显示“内容”看起来像这样:
contents[MIIEp....
...
...
...kdOA=]
更新:
好吧,我设法弄清楚我必须从编码字符串中删除所有换行符,所以现在它通过base64解码,但现在它在调用“generatePrivate()”时失败,具有以下内容: / p>
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source)
at java.security.KeyFactory.generatePrivate(Unknown Source)
at com.att.detsusl.tguardrest.TguardService.getPrivateKey(TguardService.java:63)
我看到一些注释暗示我必须使用“PKCS#1”格式,而不是“PKSC#8”,并谈论调用“openssl”来转换文件。我真的不愿意这样做。在Java中有没有直接的方法来进行这种转换(假设这是我需要的)?我打算在应用程序启动时只执行一次此代码。
更新:
好的,在考虑了替代方案之后,我使用openssl将文件转换为PKCS#8格式。之后,我能够完成Client对象的构造,但在尝试建立连接时出现了另一个错误。我认为这可能是一个相关但又不同的问题(我希望减少单个帖子中“更新”的数量),所以我在CXF REST client call with 2-way auth failing with "unable to find valid certification path to requested target"将其作为一个单独的问题发布。
另请注意,我已将密钥文件从PKCS#1转换为PKCS#8,但我从未对证书文件做过任何操作。
与此同时,我可以在PKCS#1与PKCS#8上使用更多背景知识。 PKCS#1的“遗产”如何?我注意到,给我的密钥文件的原始名称使用了代表我们组织的先前名称的首字母缩略词,该名称在几年前发生了变化。