我使用 LetsEncrypt 的 CertBot 免费生成 PEM 文件。在其他语言中,只需使用几行代码和 PEM/ key 文件即可轻松启动 HTTPS 服务器。到目前为止,我在 Java 中找到的解决方案过于复杂,我正在寻找更简单的解决方案。
- 我不想使用 java 的命令行“keytool”。我只想将我的 PEM/ key 文件拖放到我的 eclipse 中,然后使用 SSLContext 以编程方式启动 HTTPS 服务器。
- 我不想包含像 BouncyCaSTLe 这样的大量外部库。请参阅以下链接,了解使用 BouncyCaSTLe 的假定解决方案:How to build a SSLSocketFactory from PEM certificate and key without converting to keystore?
有更好/更简单的方法吗?
最佳答案
以下代码大体展示了如何通过解析具有多个条目的 PEM 文件为 HTTPS 服务器创建 SSLContext,例如几个证书和一个 RSA PRIVATE KEY
。然而它是不完整的,因为纯 Java 8 无法解析 PKCS#1 RSA 私钥数据。因此,您似乎无法在没有任何图书馆的情况下做到这一点。至少需要用于解析 PKCS#1 数据的 BouncyCaSTLe(然后也可以使用 BouncyCaSTLe 的 PEM 解析器)。
private SSLContext createSslContext() throws Exception {
URL url = getClass().getResource("/a.pem");
InputStream in = url.openStream();
String pem = new String(in.readAllBytes(), StandardCharsets.UTF_8);
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN ([^-]+)---*$([^-]+)^---*END[^-]+-+$");
Matcher m = parse.matcher(pem);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Decoder decoder = Base64.getMimeDecoder();
List<Certificate> certList = new ArrayList<>(); // java.security.cert.Certificate
PrivateKey privateKey = null;
int start = 0;
while (m.find(start)) {
String type = m.group(1);
String base64Data = m.group(2);
byte[] data = decoder.decode(base64Data);
start += m.group(0).length();
type = type.toUpperCase();
if (type.contains("CERTIFICATE")) {
Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(data));
certList.add(cert);
} else if (type.contains("RSA PRIVATE KEY")) {
// TODO: load and parse PKCS1 data structure to get the RSA private key
privateKey = ...
} else {
System.err.println("Unsupported type: " + type);
}
}
if (privateKey == null)
throw new RuntimeException("RSA private key not found in PEM file");
char[] keyStorePassword = new char[0];
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
int count = 0;
for (Certificate cert : certList) {
keyStore.setCertificateEntry("cert" + count, cert);
count++;
}
Certificate[] chain = certList.toArray(new Certificate[certList.size()]);
keyStore.setKeyEntry("key", privateKey, keyStorePassword, chain);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("RSA");
kmf.init(keyStore, keyStorePassword);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
return sslContext;
}
关于java - 在 Java 中,仅使用 PEM 文件创建 SSLContext 的最简单方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50025086/