在Java中,用PEM文件创建SSLContext最简单的方法是什么?
我使用LetsEncrypt的CertBot免费生成PEM文件。在其他语言中,只需几行代码和PEM/key文件就可以轻松启动HTTPS服务器。到目前为止,我在java中找到的解决方案过于复杂,我正在寻找更简单的解决方案在Java中,用PEM文件创建SSLContext最简单的方法是什么?,java,ssl,https,java-8,lets-encrypt,Java,Ssl,Https,Java 8,Lets Encrypt,我使用LetsEncrypt的CertBot免费生成PEM文件。在其他语言中,只需几行代码和PEM/key文件就可以轻松启动HTTPS服务器。到目前为止,我在java中找到的解决方案过于复杂,我正在寻找更简单的解决方案 我不想使用java的命令行“keytool”。我只想将PEM/key文件拖放到eclipse中,并使用SSLContext以编程方式启动HTTPS服务器 我不想包括像BouncyCastle这样的大型外部库。有关使用BouncyCastle的假定解决方案,请参见以下链接: 有更好
有更好/更简单的方法吗?下面的代码一般显示了如何通过解析具有多个条目(例如多个证书和一个
RSA私钥)的PEM文件来为HTTPS服务器创建SSLContext。但是,它是不完整的,因为普通Java 8无法解析PKCS#1 RSA私钥数据。因此,似乎您希望在没有任何库的情况下完成这项工作是不可能的。至少需要BouncyCastle来解析PKCS#1数据(然后也可以使用BouncyCastle的PEM解析器)
private SSLContext createSslContext()引发异常{
URL=getClass().getResource(“/a.pem”);
InputStream in=url.openStream();
String pem=新字符串(in.readAllBytes(),StandardCharsets.UTF_8);
模式解析=模式。编译(“(?m)(?s)^-*开始([^-]+)-*$([^-]+)^-*结束[^-]+-+$”;
Matcher m=parse.Matcher(pem);
CertificateFactory=CertificateFactory.getInstance(“X.509”);
解码器解码器=Base64.getMimeDecoder();
List certList=new ArrayList();//java.security.cert.Certificate
PrivateKey PrivateKey=null;
int start=0;
while(m.find(start)){
字符串类型=m.组(1);
字符串base64Data=m.group(2);
字节[]数据=解码器.decode(base64Data);
start+=m.group(0.length();
type=type.toUpperCase();
if(type.contains(“证书”)){
Certificate cert=certFactory.generateCertificate(新的ByteArrayInputStream(数据));
证书列表。添加(证书);
}else if(type.contains(“RSA私钥”)){
//TODO:加载并解析PKCS1数据结构以获取RSA私钥
私钥=。。。
}否则{
System.err.println(“不支持的类型:“+type”);
}
}
if(privateKey==null)
抛出新的运行时异常(“在PEM文件中找不到RSA私钥”);
char[]keystrepassword=新字符[0];
KeyStore KeyStore=KeyStore.getInstance(“JKS”);
load(null,null);
整数计数=0;
用于(证书:证书列表){
密钥库.setCertificateEntry(“证书”+计数,证书);
计数++;
}
证书[]链=certList.toArray(新证书[certList.size()]);
keyStore.setKeyEntry(“key”、privateKey、keyStorePassword、chain);
TrustManagerFactory tmf=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(密钥库);
KeyManagerFactory kmf=KeyManagerFactory.getInstance(“RSA”);
kmf.init(keyStore,keyStorePassword);
SSLContext SSLContext=SSLContext.getInstance(“TLS”);
sslContext.init(kmf.getKeyManager(),tmf.getTrustManager(),new SecureRandom());
返回sslContext;
}
- 这是一个临时解决方案,因为下面的代码允许您接受任何服务器,因此,在尝试这些解决方案时,您应该深入检查代码
- 此代码根本不需要任何证书
- 问题是,如果情况需要,您为什么要避免此过程?您不应该使用非安全服务器吗
我目前使用的完整解决方案:
在服务器上使用certbot生成证书。我使用命令“certbot certonly-d myawesomedomain.com”
我使用以下代码将certbot证书转换为java SSLContext:
packagebowser;
导入静态com.google.common.base.premissions.checkState;
导入静态ox.util.Utils.propagate;
导入java.io.File;
导入java.security.KeyStore;
导入javax.net.ssl.KeyManagerFactory;
导入javax.net.ssl.SSLContext;
导入javax.net.ssl.TrustManagerFactory;
导入com.google.common.base.Splitter;
进口牛油;
输入牛日志;
公共类方案{
公共静态SSLContext createContext(字符串域){
字符串pass=“spamspam”;
File dir=新文件(“/etc/letsencrypt/live/”+域);
如果(!dir.exists()){
Log.warn(“找不到letsencrypt目录:“+dir”);
返回null;
}
File keystoreFile=新文件(dir,“keystore.jks”);
File pemFile=新文件(dir,“fullchain.pem”);
布尔generateKeystore=false;
if(keystoreFile.exists()){
if(keystoreFile.lastModified()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;
}
logger.info("Starting instance ");
TrustManager[] tm = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers(){return new X509Certificate[]{};}
public void checkClientTrusted(X509Certificate[] chain, String authType) {logger.info(" checkClientTrusted");}
public void checkServerTrusted(X509Certificate[] chain, String authType) {logger.info(" checkServerTrusted");}
}};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, tm , new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
package bowser;
import static com.google.common.base.Preconditions.checkState;
import static ox.util.Utils.propagate;
import java.io.File;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import com.google.common.base.Splitter;
import ox.IO;
import ox.Log;
public class SSLUtils {
public static SSLContext createContext(String domain) {
String pass = "spamspam";
File dir = new File("/etc/letsencrypt/live/" + domain);
if (!dir.exists()) {
Log.warn("Could not find letsencrypt dir: " + dir);
return null;
}
File keystoreFile = new File(dir, "keystore.jks");
File pemFile = new File(dir, "fullchain.pem");
boolean generateKeystore = false;
if (keystoreFile.exists()) {
if (keystoreFile.lastModified() < pemFile.lastModified()) {
Log.info("SSUtils: It looks like a new PEM file was created. Regenerating the keystore.");
keystoreFile.delete();
generateKeystore = true;
}
} else {
generateKeystore = true;
}
if (generateKeystore) {
Splitter splitter = Splitter.on(' ');
try {
String command = "openssl pkcs12 -export -out keystore.pkcs12 -in fullchain.pem -inkey privkey.pem -passout pass:"
+ pass;
Log.debug(command);
Process process = new ProcessBuilder(splitter.splitToList(command))
.directory(dir).inheritIO().start();
checkState(process.waitFor() == 0);
command = "keytool -importkeystore -srckeystore keystore.pkcs12 -srcstoretype PKCS12 -destkeystore keystore.jks -srcstorepass "
+ pass + " -deststorepass " + pass;
Log.debug(command);
process = new ProcessBuilder(splitter.splitToList(command))
.directory(dir).inheritIO().start();
checkState(process.waitFor() == 0);
new File(dir, "keystore.pkcs12").delete();// cleanup
} catch (Exception e) {
throw propagate(e);
}
}
try {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(IO.from(keystoreFile).asStream(), pass.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, pass.toCharArray());
SSLContext ret = SSLContext.getInstance("TLSv1.2");
TrustManagerFactory factory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
factory.init(keystore);
ret.init(keyManagerFactory.getKeyManagers(), factory.getTrustManagers(), null);
return ret;
} catch (Exception e) {
throw propagate(e);
}
}
}
final String ca1 = "..load PEM file in string..";
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final Certificate cert1 = cf.generateCertificate(new ByteArrayInputStream(ca1.getBytes()));
final KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
// Can add multiple truststore certificates here...
keyStore.setCertificateEntry("my-ca-1", cert1);
final SSLContext sslContext = SSLContexts.custom().setKeyStoreType(saToken)
.loadTrustMaterial(keyStore, null)
.build();
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial("certificate-chain.pem", "private-key.pem", "private-key-password".toCharArray());
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial("some-trusted-certificate.pem");
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
SSLContext sslContext = sslFactory.getSslContext();