Java SSLSocket客户端认证配置
时间:2022-09-15 03:30:00
在学校Java网络编程时,会接触到Socket,Socket是基于TCP但是Socket没有证书认证,不能与证书认证建立联系。幸运的是,Java提供证书认证SSLsocket。
最近需要做一个客户端认证的需求,我需要在客户端配置自己的证书,然后向服务器发送数据,本文主要用于记录。
一、证书类型
SSL证书的格式有很多种,包括.p12证书,.crt .key证书,还有.jks网上大部分案例都是基于证书的.jks如果你的证书类型是证书认证,.p12证书或者是crt你可以手动拿证书p12证书转换成jks如果你是,证书crt下面将提供证书crt证书转换成jks证书的方法。
public class KeyStoreUtils {
public void generateKeyStore(String privatePath, String certPath, String ksPath, String password) throws Exception {
KeyStore var17 = KeyStore.getInstance("PKCS12"); var17.load((InputStream) null, (char[]) null); byte[] bytes = null; PrivateKey key = getPrivateKeyFromPem(privatePath); Certificate certificate = readCert(certPath); var17.setKeyEntry("Eric's Key", key, (char[]) null, new Certificate[]{
certificate}); ///加载证书链所有证书 var17.setKeyEntry("Eric's Key", key, (char[]) null, certificates);
FileOutputStream var18 = new FileOutputStream(ksPath);
var17.store(var18, password.toCharArray());
var18.flush();
}
// 获取私匙
public static PrivateKey getPrivateKeyFromPem(String privateFile) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(new File(privateFile)));
String s = br.readLine();
String str = "";
s = br.readLine();
while (s.charAt(0) != '-') {
str += s + "\r";
s = br.readLine();
}
BASE64Decoder base64decoder = new BASE64Decoder();
byte[] b = base64decoder.decodeBuffer(str);
// 生成私匙
KeyFactory kf = KeyFactory.getInstance(PropertiesReader.getKey("cert_encryption"));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(b);
PrivateKey privateKey = kf.generatePrivate(keySpec);
return privateKey;
}
public static Certificate readCert(String certPath) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream in1 = new FileInputStream(certPath);
Collection<? extends Certificate> certificates = cf.generateCertificates(in1);
Iterator<? extends Certificate> iterator = certificates.iterator();
Certificate next = iterator.next();
return next;
}
public static void main(String[] args) throws Exception{
KeyStoreUtils keyStoreUtils = new KeyStoreUtils();
keyStoreUtils.generateKeyStore("./certificate/client_dev.key","./certificate/client_dev.crt","./certificate/client_dev.jks","123456");
}
}
SSLSocket相关类介绍
SSLContext:SSLContext类可以创建SSLSocket实例,在这个类中配置自己的证书和自己所信任的证书。
KeyManagerFactory:加载自己的证书文件,并且生成KeyManager[]数据,配置到SSLContext。
TrustManagerFactory:加载自己信任的客户端证书,双向认证的时候配置自己信任哪些服务端证书。
KeyStore:加载证书的类。
TrustManager[]:信任的证书信任的Manager数组。
Manager[]:自己的证书的Manager数组。
二、配置双向认证
代码如下,通过KeyStore去加载证书,这里我客户端证书和信任的服务器证书读的同一个,真实情况肯定是两个不一样的证书。
代码:
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream("C://"), "password".toCharArray());
kmf.init(ks, new char[0]);
kmf.init(ks, "passworld".toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
log.info("创建sslsocket连接中。。。。。。");
sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket("121.0.0.1", 8000);
三、取消验证服务器证书
如果只需要配置客户端证书,客户端信任所有服务器方的证书,可以这样配置。
把TrustManager通过如下方式生成,定义一个类继续TrustManager,X509TrustManager类。
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
static class miTM implements TrustManager,X509TrustManager {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
ctx.init(kmf.getKeyManagers(), trustAllCerts, null);