Java SSLSocket客户端认证配置

在学校Java网络编程的时候,都会接触到Socket,Socket是基于TCP的数据传输方式,但Socket是没有证书认证的,它无法建立带证书认证的连接。还好,Java中提供了带证书认证的SSLsocket。
最近需要做一个客户端认证的需求,我需要在客户端配置自己的证书,然后向服务器发送数据,本文主要用于记录。
Java SSLSocket客户端认证配置_第1张图片

一、证书类型

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);

你可能感兴趣的:(Java,java,https,网络)