Java实现自动安装校验TLS/SSL证书?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 主要实现如下功能:
1.自动检测,校验根证书,校验过期时间,校验签名的证书是否有效,校验证书和域名是否匹配 2.实现证书的自动存储,自动安装,加载 3.实现普通Socket自动升级为SSLSocket 一.实现配置类
首先,我们先添加2个配置类 package com.ssl.rx.http;
import java.security.KeyStore;
public class ConnectionConfiguration {
/** 证书文件路径 */
private String truststorePath;
/** 证书类型 */
private String truststoreType;
/** 证书文件密码 */
private String truststorePassword;
/** 是否验证证书链的签名有效性 */
private boolean verifyChainEnabled = true;
/** 是否校验根证书,注意,自签名证书没有根证书 */
private boolean verifyRootCAEnabled = true;
/** 是否允许通过自签名证书 */
private boolean selfSignedCertificateEnabled = false;
/** 是否检查证书的有效期 */
private boolean expiredCertificatesCheckEnabled = true;
/** 检查域名的匹配情况 */
private boolean notMatchingDomainCheckEnabled = true;
private String server;
private int port;
public ConnectionConfiguration() {
truststorePassword = "WlZSak5GcFVUbTlsVjJSNg==";
truststorePath = "socket_tls_clientTrust.cert";
truststoreType = "jks";
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public boolean isExpiredCertificatesCheckEnabled() {
return expiredCertificatesCheckEnabled;
}
public void setSelfSignedCertificateEnabled(boolean selfSignedCertificateEnabled) {
this.selfSignedCertificateEnabled = selfSignedCertificateEnabled;
}
public void setExpiredCertificatesCheckEnabled(boolean expiredCertificatesCheckEnabled) {
this.expiredCertificatesCheckEnabled = expiredCertificatesCheckEnabled;
}
public boolean isSelfSignedCertificateEnabled() {
return selfSignedCertificateEnabled;
}
public boolean isNotMatchingDomainCheckEnabled() {
return notMatchingDomainCheckEnabled;
}
public boolean isVerifyRootCAEnabled() {
return verifyRootCAEnabled;
}
public void setVerifyRootCAEnabled(boolean verifyRootCAEnabled) {
this.verifyRootCAEnabled = verifyRootCAEnabled;
}
public void setVerifyChainEnabled(boolean verifyChainEnabled) {
this.verifyChainEnabled = verifyChainEnabled;
}
public boolean isVerifyChainEnabled() {
return verifyChainEnabled;
}
public String getTruststoreType() {
return truststoreType;
}
public void setTruststoreType(String truststoreType) {
this.truststoreType = truststoreType;
}
public String getTruststorePassword() {
return truststorePassword;
}
public void setTruststorePassword(String truststorePassword) {
this.truststorePassword = truststorePassword;
}
public String getTruststorePath() {
return truststorePath;
}
public void setTruststorePath(String truststorePath) {
this.truststorePath = truststorePath;
}
public void setNotMatchingDomainCheckEnabled(boolean notMatchingDomainCheckEnabled) {
this.notMatchingDomainCheckEnabled = notMatchingDomainCheckEnabled;
}
}
然后增加一个用于存储keystore的javaBean
package com.ssl.rx.http;
public class KeyStoreOptions {
private final String type;
private final String path;
private final String password;
public KeyStoreOptions(String type, String path, String password) {
super();
this.type = type;
this.path = path;
this.password = password;
}
public String getType() {
return type;
}
public String getPath() {
return path;
}
public String getPassword() {
return password;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((password == null) ? 0 : password.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
KeyStoreOptions other = (KeyStoreOptions) obj;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (path == null) {
if (other.path != null)
return false;
} else if (!path.equals(other.path))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
} 最后,我们来实现核心部分,证书管理器 二.实现核心代码 package com.ssl.rx.http;
public class SSLX509CertificateManager {
private static final Logger logger = Logger.getLogger("SSLX509CertificateManager");
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static Pattern cnPattern = Pattern.compile("(?i)(cn=)([^,]*)");
private static Map<KeyStoreOptions, KeyStore> stores = new HashMap<KeyStoreOptions, KeyStore>();
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 3);
for (int b : bytes) {
b &= 0xff;
sb.append(HEXDIGITS[b >> 4]);
sb.append(HEXDIGITS[b & 15]);
sb.append(' ');
}
return sb.toString();
}
/**
* 开始握手等一系列密钥协商
*
* @param socket
* @return
*/
public static boolean startHandshake(SSLSocket socket) {
try {
logger.log(Level.INFO, "-开始握手,认证服务器证书-");
socket.startHandshake();
System.out.println();
logger.log(Level.INFO, "-握手结束,结束认证服务器证书-");
} catch (SSLException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public static SSLSocket createTrustCASocket(String host, int port, ConnectionConfiguration config)
throws Exception {
if (config == null) {
config = new ConnectionConfiguration();
}
KeyStore ks = getKeyStore(config);
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
CAX509TrustManager tm = new CAX509TrustManager(defaultTrustManager, ks, config);
context.init(null, new TrustManager[] { tm }, new SecureRandom());
SSLSocketFactory factory = context.getSocketFactory();
logger.log(Level.INFO, "开始连接: " + host + ":" + port + "...");
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
config.setServer(host);
config.setPort(port);
// config.setTrustKeyStore(ks);
X509Certificate certificate = (X509Certificate) ks.getCertificate(host + ":" + port);
if (certificate != null && isValid(certificate)) {
logger.log(Level.INFO, "-证书文件存在并且有效,无需进行握手-");
return socket;
}
if (!startHandshake(socket)) {
logger.log(Level.SEVERE, "-握手失败-");
return null;
}
X509Certificate[] chain = tm.chain;
if (chain == null || chain.length == 0) {
logger.log(Level.SEVERE, "-证书链为空,认证失败-");
return null;
}
if (config.isVerifyRootCAEnabled()) {
boolean isValidRootCA = checkX509CertificateRootCA(ks, chain, config.isSelfSignedCertificateEnabled());
if (!isValidRootCA) {
return null;
}
}
return socket;
}
/**
* 获取keystore,防治多次加载
*
* @param config
* @return
* @throws KeyStoreException
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws FileNotFoundException
*/
private static KeyStore getKeyStore(ConnectionConfiguration config) throws KeyStoreException, IOException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException {
KeyStore ks;
synchronized (stores) {
KeyStoreOptions options = new KeyStoreOptions(config.getTruststoreType(), config.getTruststorePath(),
config.getTruststorePassword());
if (stores.containsKey(options)) {
logger.log(Level.INFO, "从缓存中获取trustKeystore");
ks = stores.get(options);
} else {
File file = new File(config.getTruststorePath());
char[] password = config.getTruststorePassword().toCharArray();
logger.log(Level.INFO, "加载" + file + "证书文件");
ks = KeyStore.getInstance(KeyStore.getDefaultType());
if (!file.exists()) {
logger.log(Level.INFO, "证书文件不存在,选择自动创建");
ks.load(null, password);
} else {
logger.log(Level.INFO, "证书文件存在,开始加载");
InputStream in = new FileInputStream(file);
ks.load(in, password);
in.close();
}
stores.put(options, ks);
}
}
return ks;
}
public static SSLSocket createTrustCASocket(String host, int port) throws Exception {
return createTrustCASocket(host, port, null);
}
public static SSLSocket createTrustCASocket(Socket s, ConnectionConfiguration config) throws Exception {
if (config == null) {
config = new ConnectionConfiguration();
}
KeyStore ks = getKeyStore(config);
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
CAX509TrustManager tm = new CAX509TrustManager(defaultTrustManager, ks, config);
context.init(null, new TrustManager[] { tm }, new SecureRandom());
SSLSocketFactory factory = context.getSocketFactory();
String host = s.getInetAddress().getHostName();
int port = s.getPort();
logger.log(Level.INFO, "开始连接: " + host + ":" + port + "...");
SSLSocket socket = (SSLSocket) factory.createSocket(s, host, port, true);
socket.setSoTimeout(10000);
config.setServer(s.getInetAddress().getHostName());
config.setPort(s.getPort());
X509Certificate certificate = (X509Certificate) ks.getCertificate(host + ":" + s.getPort());
if (certificate != null && isValid(certificate)) {
logger.log(Level.INFO, "-证书文件存在并且有效,无需进行握手-");
return socket;
}
if (!startHandshake(socket)) {
return null;
}
X509Certificate[] chain = tm.chain;
if (chain == null || chain.length == 0) {
logger.log(Level.SEVERE, "-证书链为空,认证失败-");
return null;
}
if (config.isVerifyRootCAEnabled()) {
boolean isValidRootCA = checkX509CertificateRootCA(ks, chain, config.isSelfSignedCertificateEnabled());
if (!isValidRootCA) {
logger.log(Level.SEVERE, "根证书校验无效");
return null;
}
}
return socket;
}
public static SSLSocket createTrustCASocket(Socket s) throws Exception {
return createTrustCASocket(s, null);
}
public static class CAX509TrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
private KeyStore keyStore;
private ConnectionConfiguration config;
public MessageDigest sha1 = null;
public MessageDigest md5 = null;
public CAX509TrustManager(X509TrustManager tm, KeyStore ks, ConnectionConfiguration config)
throws NoSuchAlgorithmException {
this.tm = tm;
this.keyStore = ks;
sha1 = MessageDigest.getInstance("SHA1");
md5 = MessageDigest.getInstance("MD5");
this.config = config;
}
public X509Certificate[] getAcceptedIssuers() {
return tm.getAcceptedIssuers(); // 生成证书数组,用于存储新证书
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
tm.checkClientTrusted(chain, authType); // 检查客户端
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
if (this.chain == null) {
this.chain = getAcceptedIssuers();
}
if (chain != null && chain.length > 0) {
if (!checkX509CertificateValid(chain, config)) {
logger.log(Level.SEVERE, "证书校验未通过");
return;
}
for (int i = 0; i < chain.length; i++) {
X509Certificate certificate = chain[i];
if (i == 0) {
saveCAToKeyStore(certificate, config.getServer() + ":" + config.getPort());
} else {
saveCAToKeyStore(certificate, null);
}
}
}
}
public void saveCAToKeyStore(X509Certificate certificate, String aliasKey) throws CertificateEncodingException {
try {
X509Certificate cert = certificate;
System.out.println(" Subject " + cert.getSubjectDN());
System.out.println(" Issuer " + cert.getIssuerDN());
sha1.update(cert.getEncoded());
System.out.println(" sha1 " + toHexString(sha1.digest()));
md5.update(cert.getEncoded());
System.out.println(" md5 " + toHexString(md5.digest()));
String alias = keyStore.getCertificateAlias(cert);
if (alias == null || alias != null && !isValid(certificate)) {
if (aliasKey == null || aliasKey.length() == 0) {
alias = cert.getSubjectDN().getName();
} else {
alias = aliasKey;
logger.log(Level.INFO, "设定指定证书别名:" + alias);
}
keyStore.setCertificateEntry(alias, certificate);
OutputStream out = new FileOutputStream(config.getTruststorePath());
keyStore.store(out, config.getTruststorePassword().toCharArray());
out.close();
chain = Arrays.copyOf(chain, chain.length + 1);
chain[chain.length - 1] = certificate;
logger.fine(certificate.toString());
}
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static boolean isValid(X509Certificate cert) {
if (cert == null) {
return false;
}
try {
cert.checkValidity();
} catch (CertificateExpiredException e) {
e.printStackTrace();
return false;
} catch (CertificateNotYetValidException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 校验证书的有效性
*
* @param chain
* @param config
* @return
*/
private static boolean checkX509CertificateValid(X509Certificate[] chain, ConnectionConfiguration config) {
boolean result = true;
if (config.isExpiredCertificatesCheckEnabled()) {
result = result && checkX509CertificateExpired(chain);
}
if (config.isVerifyChainEnabled()) {
result = result && checkX509CertificateChain(chain);
}
if (config.isNotMatchingDomainCheckEnabled()) {
result = result && checkIsMatchDomain(chain, config.getServer());
}
return result;
}
/**
* 检查是否匹配域名
*
* @param x509Certificates
* @param server
* @return
*/
public static boolean checkIsMatchDomain(X509Certificate[] x509Certificates, String server) {
server = server.toLowerCase();
List<String> peerIdentities = getPeerIdentity(x509Certificates[0]);
if (peerIdentities.size() == 1 && peerIdentities.get(0).startsWith("*.")) {
String peerIdentity = peerIdentities.get(0).replace("*.", "");
if (!server.endsWith(peerIdentity)) {
return false;
}
} else {
for (int i = 0; i < peerIdentities.size(); i++) {
String peerIdentity = peerIdentities.get(i).replace("*.", "");
if (server.endsWith(peerIdentity)) {
return true;
}
}
}
return false;
}
/**
* 校验根证书
*
* @param trustStore
* @param x509Certificates
* @param isSelfSignedCertificate
* 是否自签名证书
* @return
*/
public static boolean checkX509CertificateRootCA(KeyStore trustStore, X509Certificate[] x509Certificates,
boolean isSelfSignedCertificate) {
List<String> peerIdentities = getPeerIdentity(x509Certificates[0]);
boolean trusted = false;
try {
int size = x509Certificates.length;
trusted = trustStore.getCertificateAlias(x509Certificates[size - 1]) != null;
if (!trusted && size == 1 && isSelfSignedCertificate) {
logger.log(Level.WARNING, "-强制认可自签名证书-");
trusted = true;
}
} catch (KeyStoreException e) {
e.printStackTrace();
}
if (!trusted) {
logger.log(Level.SEVERE, "-根证书签名的网站:" + peerIdentities + "不能被信任");
}
return trusted;
}
/**
* 检查证书是否过期
*
* @param x509Certificates
* @return
*/
public static boolean checkX509CertificateExpired(X509Certificate[] x509Certificates) {
Date date = new Date();
for (int i = 0; i < x509Certificates.length; i++) {
try {
x509Certificates[i].checkValidity(date);
} catch (GeneralSecurityException generalsecurityexception) {
logger.log(Level.SEVERE, "-证书已经过期-");
return false;
}
}
return true;
}
/**
* 校验证书链的完整性
*
* @param x509Certificates
* @return
*/
public static boolean checkX509CertificateChain(X509Certificate[] x509Certificates) {
Principal principalLast = null;
List<String> peerIdentities = getPeerIdentity(x509Certificates[0]);
for (int i = x509Certificates.length - 1; i >= 0; i--) {
X509Certificate x509certificate = x509Certificates[i];
Principal principalIssuer = x509certificate.getIssuerDN();
Principal principalSubject = x509certificate.getSubjectDN();
if (principalLast != null) {
if (principalIssuer.equals(principalLast)) {
try {
PublicKey publickey = x509Certificates[i + 1].getPublicKey();
x509Certificates[i].verify(publickey);
} catch (GeneralSecurityException generalsecurityexception) {
logger.log(Level.SEVERE, "-无效的证书签名-" + peerIdentities);
return false;
}
} else {
logger.log(Level.SEVERE, "-无效的证书签名-" + peerIdentities);
return false;
}
}
principalLast = principalSubject;
}
return true;
}
/**
* 返回所有可用的签名方式 键值对 如CN=VeriSignMPKI-2-6
*
* @param certificate
* @return
*/
private static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
List<String> identities = new ArrayList<String>();
try {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
if (altNames == null) {
return Collections.emptyList();
}
Iterator<List<?>> iterator = altNames.iterator();
do {
if (!iterator.hasNext())
break;
List<?> altName = iterator.next();
int size = altName.size();
if (size >= 2) {
identities.add((String) altName.get(1));
}
} while (true);
} catch (CertificateParsingException e) {
e.printStackTrace();
}
return identities;
}
/**
* 返回所有可用的签名方式的值
*
* @param certificate
* @return
*/
public static List<String> getPeerIdentity(X509Certificate x509Certificate) {
List<String> names = getSubjectAlternativeNames(x509Certificate);
if (names.isEmpty()) {
String name = x509Certificate.getSubjectDN().getName();
Matcher matcher = cnPattern.matcher(name);
if (matcher.find()) {
name = matcher.group(2);
}
names = new ArrayList<String>();
names.add(name);
}
return names;
}
} 三.测试代码 public class TestX509CertManager {
public static void main(String[] args) {
try {
SSLSocket baiduSocket = SSLX509CertificateManager.createTrustCASocket("www.baidu.com", 443);
SSLSocket taobaoSocket = SSLX509CertificateManager.createTrustCASocket("www.taobao.com", 443);
SSLSocket imququSocket = SSLX509CertificateManager.createTrustCASocket("imququ.com", 443);
} catch (Exception e) {
e.printStackTrace();
}
}
} 四.附加测试代码 我们这里附加一个工具类,专门来实现Server-Side与Client-Side的SSLSocket 连接,也可以用于测试我们的上述代码,只不过需要稍加改造。 package com.tianwt.rx.http;
public class SSLTrustManager implements javax.net.ssl.TrustManager,
javax.net.ssl.X509TrustManager ,HostnameVerifier {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
public boolean isServerTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public boolean verify(String urlHostName, SSLSession session) { //允许所有主机
return true;
}
/**
* 客户端使用
*/
public static HttpURLConnection connectTrustAllServer(String strUrl) throws Exception {
return connectTrustAllServer(strUrl,null);
}
/**
* 客户端使用
*
* @param strUrl 要访问的地址
* @param proxy 需要经过的代理
* @return
* @throws Exception
*/
public static HttpURLConnection connectTrustAllServer(String strUrl,Proxy proxy) throws Exception {
javax.net.ssl.TrustManager[] trustCertsmanager = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new SSLTrustManager();
trustCertsmanager[0] = tm;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
.getInstance("TLS");
sc.init(null, trustCertsmanager, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((HostnameVerifier) tm);
URL url = new URL(strUrl);
HttpURLConnection urlConn = null;
if(proxy==null)
{
urlConn = (HttpURLConnection) url.openConnection();
}else{
urlConn = (HttpURLConnection) url.openConnection(proxy);
}
urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36");
return urlConn;
}
/**
* 用于双向认证,客户端使用
*
* @param strUrl
* @param proxy
* @return
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws FileNotFoundException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public static HttpURLConnection connectProxyTrustCA(String strUrl,Proxy proxy) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException
{
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslsession) {
return true;
}
});
String clientKeyStoreFile = "D:/JDK8Home/tianwt/sslClientKeys";
String clientKeyStorePwd = "123456";
String catServerKeyPwd = "123456";
String serverTrustKeyStoreFile = "D:/JDK8Home/tianwt/sslClientTrust";
String serverTrustKeyStorePwd = "123456";
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream(clientKeyStoreFile), clientKeyStorePwd.toCharArray());
KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");
serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(serverKeyStore, catServerKeyPwd.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(serverTrustKeyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL(strUrl);
HttpURLConnection httpURLConnection = null;
if(proxy==null)
{
httpURLConnection = (HttpURLConnection) url.openConnection();
}else{
httpURLConnection = (HttpURLConnection) url.openConnection(proxy);
}
httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36");
return httpURLConnection;
}
/**
* 用于单向认证,客户端使用
*
* server侧只需要自己的keystore文件,不需要truststore文件
* client侧不需要自己的keystore文件,只需要truststore文件(其中包含server的公钥)。
* 此外server侧需要在创建SSLServerSocket之后设定不需要客户端证书:setNeedClientAuth(false)
* @param strUrl
* @param proxy
* @return
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws FileNotFoundException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public static HttpURLConnection connectProxyTrustCA2(String strUrl,Proxy proxy) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException
{
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslsession) {
return true;
}
});
String serverTrustKeyStoreFile = "D:/JDK8Home/tianwt/sslClientTrust";
String serverTrustKeyStorePwd = "123456";
KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");
serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(serverTrustKeyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL(strUrl);
HttpURLConnection httpURLConnection = null;
if(proxy==null)
{
httpURLConnection = (HttpURLConnection) url.openConnection();
}else{
httpURLConnection = (HttpURLConnection) url.openConnection(proxy);
}
httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36");
return httpURLConnection;
}
/**
* 用于双向认证
* @param socketClient 是否产生socket
* @return
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws FileNotFoundException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public SSLSocket createTlsConnect(Socket socketClient) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException
{
String protocol = "TLS";
String serverKey = "D:/JDK8Home/tianwt/sslServerKeys";
String serverTrust = "D:/JDK8Home/tianwt/sslServerTrust";
String serverKeyPwd = "123456"; //私钥密码
String serverTrustPwd = "123456"; //信任证书密码
String serverKeyStorePwd = "123456"; // keystore存储密码
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(serverKey),serverKeyPwd.toCharArray());
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream(serverTrust), serverTrustPwd.toCharArray());
KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
km.init(keyStore, serverKeyStorePwd.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(tks);
SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(km.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); //第一项是用来做服务器验证的
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket clientSSLSocket = (SSLSocket) sslSocketFactory.createSocket(socketClient,socketClient.getInetAddress().getHostAddress(),socketClient.getPort(), true);
clientSSLSocket.setNeedClientAuth(false);
clientSSLSocket.setUseClientMode(false);
return clientSSLSocket;
}
/**
* 用于单向认证
* server侧只需要自己的keystore文件,不需要truststore文件
* client侧不需要自己的keystore文件,只需要truststore文件(其中包含server的公钥)。
* 此外server侧需要在创建SSLServerSocket之后设定不需要客户端证书:setNeedClientAuth(false)
* @param socketClient
* @return
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws FileNotFoundException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public static SSLSocket createTlsConnect2(Socket socketClient) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException
{
String protocol = "TLS";
String serverKey = "D:/JDK8Home/tianwt/sslServerKeys";
String serverKeyPwd = "123456"; //私钥密码
String serverKeyStorePwd = "123456"; // keystore存储密码
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(serverKey),serverKeyPwd.toCharArray());
KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
km.init(keyStore, serverKeyStorePwd.toCharArray());
SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(km.getKeyManagers(), null, new SecureRandom()); //第一项是用来做服务器验证的
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket clientSSLSocket = (SSLSocket) sslSocketFactory.createSocket(socketClient,socketClient.getInetAddress().getHostAddress(),socketClient.getPort(), true);
clientSSLSocket.setNeedClientAuth(false);
clientSSLSocket.setUseClientMode(false);
return clientSSLSocket;
}
/**
* 将普通的socket转为sslsocket,客户端和服务端均可使用
*
* 服务端使用的时候是把普通的socket转为sslsocket,并且作为服务器套接字(注意:指的不是ServerSocket,当然ServerSocket的本质也是普通socket)
*
* @param remoteHost
* @param isClient
* @return
*/
public static SSLSocket getTlsTrustAllSocket(Socket remoteHost,boolean isClient)
{
SSLSocket remoteSSLSocket = null;
SSLContext context = SSLTrustManager.getTrustAllSSLContext(isClient);
try {
remoteSSLSocket = (SSLSocket) context.getSocketFactory().createSocket(remoteHost, remoteHost.getInetAddress().getHostName(),remoteHost.getPort(), true);
remoteSSLSocket.setTcpNoDelay(true);
remoteSSLSocket.setSoTimeout(5000);
remoteSSLSocket.setNeedClientAuth(false); //这里设置为true时会强制握手
remoteSSLSocket.setUseClientMode(isClient); //注意服务器和客户的角色选择
} catch (IOException e) {
e.printStackTrace();
}
return remoteSSLSocket;
}
/**
* 用于客户端,通过所有证书验证
* @param isClient 是否生成客户端SSLContext,否则生成服务端SSLContext
* @return
*/
public static SSLContext getTrustAllSSLContext(boolean isClient)
{
String protocol = "TLS";
javax.net.ssl.SSLContext sc = null;
try {
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new SSLTrustManager();
trustAllCerts[0] = tm;
sc = javax.net.ssl.SSLContext
.getInstance(protocol);
if(isClient)
{
sc.init(null, trustAllCerts, null); //作为客户端使用
}
else
{
String serverKeyPath = "D:/JDK8Home/tianwt/sslServerKeys";
String serverKeyPwd = "123456"; //私钥密码
String serverKeyStorePwd = "123456"; // keystore存储密码
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(serverKeyPath),serverKeyPwd.toCharArray());
KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
km.init(keyStore, serverKeyStorePwd.toCharArray());
KeyManager[] keyManagers = km.getKeyManagers();
keyManagers = Arrays.copyOf(keyManagers, keyManagers.length+1);
sc.init(keyManagers, null, new SecureRandom());
}
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sc;
}
} 看完上述内容,你们掌握Java实现自动安装校验TLS/SSL证书的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注天达云行业资讯频道,感谢各位的阅读!
|