maven
<!-- https 双向认证 -->
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-pem</artifactId>
<version>5.3.0</version>
</dependency>
代码
package com.cfnoc.ts.utils;
import com.cfnoc.ts.config.FilePathConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.util.Assert;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class HttpsSslUtils {
private static final int CONNECT_TIMEOUT_MILLES = 3000;
private static final Charset ENCODING;
private static final String HTTP_GET = "GET";
private static final String HTTP_POST = "POST";
private static final String[] METHODS;
static {
ENCODING = StandardCharsets.UTF_8;
METHODS = new String[]{HTTP_GET, HTTP_POST};
}
public static String doSslGet(String url, Map<String, String> headers, Map<String, String> params, String content, SSLKeyStore ssl) throws Exception {
return doOutput(url, HTTP_GET, headers, params, content, true, ssl);
}
public static String doSslPost(String url, Map<String, String> headers, Map<String, String> params, String content, SSLKeyStore ssl) throws Exception {
return doOutput(url, HTTP_POST, headers, params, content, true, ssl);
}
private static String doOutput(final String url, final String method, final Map<String, String> headers, final Map<String, String> params, final String content, boolean isSsl, SSLKeyStore ssl) throws Exception {
HttpURLConnection conn = null;
try {
conn = createConnection(setParams(url, params), isSsl, ssl);
setMethod(conn, method);
setHeaders(conn, headers);
conn.connect();
output(conn, content);
return input(conn);
} catch (Exception e) {
throw e;
} finally {
connClose(conn);
}
}
private static void connClose(HttpURLConnection conn) {
if (conn != null) {
conn.disconnect();
}
}
private static String input(HttpURLConnection conn) throws IOException {
int len;
char[] cbuf = new char[1024 * 8];
StringBuilder buf = new StringBuilder();
int status = conn.getResponseCode();
InputStream in = null;
BufferedReader reader = null;
try {
in = conn.getErrorStream();
if (in == null && status < 400) {
in = conn.getInputStream();
}
if (in != null) {
reader = new BufferedReader(new InputStreamReader(in, ENCODING));
while ((len = reader.read(cbuf)) > 0) {
buf.append(cbuf, 0, len);
}
}
} finally {
if (reader != null) {
reader.close();
}
if (in != null) {
in.close();
}
}
return buf.toString();
}
private static void output(HttpURLConnection conn, String content) throws IOException {
if (StringUtils.isBlank(content)) {
return;
}
OutputStream out = conn.getOutputStream();
try {
out.write(content.getBytes(ENCODING));
} finally {
if (out != null) {
out.flush();
out.close();
}
}
}
private static HttpsURLConnection createConnection(String url, boolean isSsl, SSLKeyStore ssl) throws Exception {
HttpsURLConnection conn;
if (isSsl) {
try {
conn = (HttpsURLConnection) (new URL(url)).openConnection();
if (ssl != null) {
SSLSocketFactory sslSocketFactory = getSSLSocketFactory(ssl.getCaAlias(), ssl.getCaPath(), ssl.getCrtAlias(), ssl.getCrtPath(), ssl.getKeyPath(), ssl.getPassword());
conn.setSSLSocketFactory(sslSocketFactory);
} else {
httpssl(conn);
}
} catch (Exception e) {
throw e;
}
} else {
conn = (HttpsURLConnection) (new URL(url)).openConnection();
}
assert conn != null;
setConfig(conn);
return conn;
}
private static void setMethod(HttpURLConnection conn, String method) throws IOException {
Assert.isTrue(StringUtils.containsAny(method, METHODS), "只支持GET、POST、PUT、DELETE操作");
conn.setRequestMethod(method);
}
private static void setConfig(HttpURLConnection conn) {
conn.setConnectTimeout(CONNECT_TIMEOUT_MILLES);
conn.setUseCaches(false);
conn.setInstanceFollowRedirects(true);
conn.setRequestProperty("Connection", "close");
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setDoOutput(true);
conn.setDoInput(true);
}
private static void setHeaders(HttpURLConnection conn, Map<String, String> headers) {
if (headers == null || headers.size() <= 0) {
return;
}
headers.forEach(conn::setRequestProperty);
}
private static String setParams(String url, Map<String, String> params) {
if (params == null || params.size() <= 0) {
return url;
}
StringBuilder sb = new StringBuilder(url);
sb.append("?");
params.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
return sb.substring(0, sb.length() - 1);
}
private static void httpssl(HttpURLConnection conn) throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new SslManager();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
((HttpsURLConnection) conn).setSSLSocketFactory(sc.getSocketFactory());
((HttpsURLConnection) conn).setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String str, SSLSession session) {
return true;
}
});
}
private static SSLSocketFactory getSSLSocketFactory(String caAlias, String caPath, String crtAlias, String crtPath, String keyPath, String password) throws Exception {
CertificateFactory cacf = CertificateFactory.getInstance("X.509");
FileInputStream caInputStream = null;
try {
caInputStream = new FileInputStream(caPath);
} catch (FileNotFoundException e) {
log.error("https工具类中加载CA证书失败");
}
List<X509Certificate> caList = cacf.generateCertificates(caInputStream).stream().map(v ->
(X509Certificate) v).collect(Collectors.toList());
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null, password.toCharArray());
for (X509Certificate ca : caList) {
keystore.setCertificateEntry(ca.getSubjectDN().getName(), ca);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
caInputStream.close();
CertificateFactory crtcf = CertificateFactory.getInstance("X.509");
InputStream crtStream = null;
try {
crtStream = new FileInputStream(new File(crtPath));
} catch (FileNotFoundException e) {
log.error("https工具类中加载客户端证书失败");
}
Certificate crt = crtcf.generateCertificate(crtStream);
KeyStore crtks = KeyStore.getInstance(KeyStore.getDefaultType());
crtks.load(null, password.toCharArray());
crtks.setCertificateEntry(crtAlias, crt);
PrivateKey privateKey = null;
try {
privateKey = getPrivateKey(keyPath);
} catch (Exception e) {
log.error("https工具类中加载私钥失败");
}
crtks.setKeyEntry(crtAlias + ".private.key", privateKey, password.toCharArray(), new Certificate[]{crt});
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(crtks, password.toCharArray());
crtStream.close();
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory();
}
private static PrivateKey getPrivateKey(String keyPath) throws Exception {
PrivateKey privKey = null;
PemReader pemReader = null;
File file = new File(keyPath);
try {
if (!file.exists()) {
throw new FileNotFoundException("未找到私钥文件:" + keyPath);
}
pemReader = new PemReader(new FileReader(file));
PemObject pemObject = pemReader.readPemObject();
byte[] pemContent = pemObject.getContent();
if (pemObject.getType().endsWith("RSA PRIVATE KEY")) {
RSAPrivateKey asn1PrivKey = RSAPrivateKey.getInstance(pemContent);
RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());
KeyFactory keyFactory = KeyFactory.getInstance("rsa");
privKey = keyFactory.generatePrivate(rsaPrivKeySpec);
} else if (pemObject.getType().endsWith("PRIVATE KEY")) {
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pemContent);
KeyFactory kf = KeyFactory.getInstance("rsa");
privKey = kf.generatePrivate(privKeySpec);
}
} finally {
try {
if (pemReader != null) {
pemReader.close();
}
} catch (IOException e) {
log.error("系统异常", e);
}
}
return privKey;
}
public static class SslManager implements TrustManager, X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
public static class SSLKeyStore {
private String caAlias;
private String caPath;
private String crtAlias;
private String crtPath;
private String keyPath;
private String password;
public String getCaAlias() {
return caAlias;
}
public void setCaAlias(String caAlias) {
this.caAlias = caAlias;
}
public String getCaPath() {
return caPath;
}
public void setCaPath(String caPath) {
this.caPath = caPath;
}
public String getCrtAlias() {
return crtAlias;
}
public void setCrtAlias(String crtAlias) {
this.crtAlias = crtAlias;
}
public String getCrtPath() {
return crtPath;
}
public void setCrtPath(String crtPath) {
this.crtPath = crtPath;
}
public String getKeyPath() {
return keyPath;
}
public void setKeyPath(String keyPath) {
this.keyPath = keyPath;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
public static SSLKeyStore getSSLKeyStore() {
SSLKeyStore ssl = new SSLKeyStore();
ssl.setCaAlias("ca");
ssl.setCaPath(FilePathConfig.getInstance().getNormal() + "root.ca.pem");
ssl.setCrtAlias("client");
ssl.setCrtPath(FilePathConfig.getInstance().getNormal() + "ts.device.pem");
ssl.setKeyPath(FilePathConfig.getInstance().getNormal() + "ts.device-prikey.pem");
ssl.setPassword("changeit");
return ssl;
}
public static void main(String[] args) throws Exception {
String httpsUrl = "https://cfbp.cf-noc.com/hello/postHello";
String content = "{\"user_id\":\"1\"}";
SSLKeyStore ssl = new SSLKeyStore();
ssl.setCaAlias("ca");
ssl.setCaPath("E:\\cert\\allca.crt");
ssl.setCrtAlias("client");
ssl.setCrtPath("E:\\cert\\ts.device.pem");
ssl.setKeyPath("E:\\cert\\ts.device-prikey.pem");
ssl.setPassword("changeit");
String html = doSslPost(httpsUrl, null, null, content, ssl);
System.out.println(html);
}
}