模擬Java Https雙向驗證

Https服務端代碼:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;

/**
 * https服務端測試類
 * 生成服務端Jks文件的命令:
 * keytool -genkey -keyalg RSA -alias serverkeystore -keystore keystore.jks -storepass crab123456 -validity 360 -keysize 2048
 */
public class HttpsServerTest {
    //服務端的jks文件
    private static final String KEYSTORE_PATH = "/home/user/test/java/keystore.jks";
    //客戶端的jks文件
    private static final String KEYSTORE_PATH_CLIENT = "/home/user/test/java/clientkeystore.jks";
    //jks文件密碼
    private static final char[] password = "crab123456".toCharArray();

    /**
     * 當前時間精確到毫秒以字符串形式輸出
     *
     * @return 當前時間的字符串
     */
    public static String getCurrentTimeForMillis() {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss:SSS");
        return formatter.format(new Date(System.currentTimeMillis()));
    }

    public static void main(String[] args) {
        SSLContext sslContext = null;
        //標記SSLContext是否初始化成功
        boolean sslContextSuccess = false;
        try {
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(KEYSTORE_PATH), password);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);
            KeyManager[] km = kmf.getKeyManagers();

            ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(KEYSTORE_PATH_CLIENT), password);
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);
            TrustManager[] tm = tmf.getTrustManagers();
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(new KeyManager[]{new HttpsServerTest.MyKeyManger(km)}, new TrustManager[]{new MyTrustManger(tm)}, new SecureRandom());
            sslContextSuccess = true;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (CertificateException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (KeyStoreException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (IOException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (KeyManagementException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        }
        System.out.println("sslContextSuccess=" + sslContextSuccess);
        if (sslContextSuccess) {
            SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory();
            SSLServerSocket ss = null;
            try {
                ss = (SSLServerSocket) serverSocketFactory.createServerSocket(8000);
                //是否需要驗證客戶端,true開啓客戶端驗證,即https雙向驗證
                ss.setNeedClientAuth(true);
                Socket s = ss.accept();
                System.out.println("server receive a client connect " + getCurrentTimeForMillis());
                InputStream is = s.getInputStream();
                int clientMsg = is.read();
                System.out.println("serve receive the client message:" + (char)clientMsg + " " + getCurrentTimeForMillis());
                OutputStream os = s.getOutputStream();
                //write the char of 'C" to client
                os.write(67);
                os.flush();
                System.out.println("server send message to client " + getCurrentTimeForMillis());
                System.out.println("server ok");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (ss != null) {
                    try {
                        ss.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static class MyTrustManger implements X509TrustManager {
        private X509TrustManager mManger;

        public MyTrustManger(TrustManager[] trustManagers) {
            if (trustManagers[0] instanceof X509TrustManager) {
                mManger = (X509TrustManager) trustManagers[0];
            }
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            System.out.println("server checkClientTrusted " + getCurrentTimeForMillis());
            mManger.checkClientTrusted(chain, authType);
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            System.out.println("server checkServerTrusted " + getCurrentTimeForMillis());
            mManger.checkServerTrusted(chain, authType);
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            System.out.println("server getAcceptedIssuers " + getCurrentTimeForMillis());
            X509Certificate[] certificates = mManger.getAcceptedIssuers();
//            if(certificates!=null){
//                for(X509Certificate certificate:certificates){
//                    System.out.println("server getAcceptedIssuers certificate="+certificate+" "+getCurrentTimeForMillis());
//                }
//            }
            return certificates;
        }
    }

    public static class MyKeyManger implements X509KeyManager {
        private X509KeyManager mKeyManager;

        public MyKeyManger(KeyManager[] keyManagers) {
            if (keyManagers[0] instanceof X509KeyManager) {
                mKeyManager = (X509KeyManager) keyManagers[0];
            }
        }

        @Override
        public String[] getClientAliases(String keyType, Principal[] issuers) {
            System.out.println("server getClientAliases keyType=" + keyType + " " + getCurrentTimeForMillis());
            return mKeyManager.getClientAliases(keyType, issuers);
        }

        @Override
        public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
            System.out.println("server chooseClientAlias keyType=" + Arrays.toString(keyType) + " " + getCurrentTimeForMillis());
            return mKeyManager.chooseClientAlias(keyType, issuers, socket);
        }

        @Override
        public String[] getServerAliases(String keyType, Principal[] issuers) {
            System.out.println("server getServerAliases keyType=" + keyType + " " + getCurrentTimeForMillis());
            return mKeyManager.getServerAliases(keyType, issuers);
        }

        @Override
        public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
            System.out.println("server chooseServerAlias keyType=" + keyType + " " + getCurrentTimeForMillis());
            return mKeyManager.chooseServerAlias(keyType, issuers, socket);
        }

        @Override
        public X509Certificate[] getCertificateChain(String alias) {
            System.out.println("server getCertificateChain alias=" + alias + " " + getCurrentTimeForMillis());
            return mKeyManager.getCertificateChain(alias);
        }

        @Override
        public PrivateKey getPrivateKey(String alias) {
            System.out.println("server getPrivateKey alias=" + alias + " " + getCurrentTimeForMillis());
            return mKeyManager.getPrivateKey(alias);
        }
    }
}

Https客戶端代碼:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;

/**
 * https客戶端測試類
 * 生成客戶端Jks文件的命令:
 * keytool -genkey -keyalg RSA -alias clientkeystore -keystore clientkeystore.jks -storepass crab123456 -validity 360 -keysize 2048
 */
public class HttpsClientTest {
    public static final String KEYSTORE_PATH = "/home/user/test/java/keystore.jks";
    public static final String KEYSTORE_PATH_CLIENT = "/home/user/test/java/clientkeystore.jks";
    public static final char[] password = "crab123456".toCharArray();
    public static void main(String[] args){
        connectForSocket();
    }

    /**
     * 當前時間精確到毫秒以字符串形式輸出
     * @return 當前時間的字符串
     */
    public static String getCurrentTimeForMillis(){
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss:SSS");
        return formatter.format(new Date(System.currentTimeMillis()));
    }
    public static void connectForSocket(){
        SSLContext sslContext = null;
        //標記SSLContext是否初始化成功
        boolean sslContextSuccess = false;
        try {
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(KEYSTORE_PATH_CLIENT), password);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);
            KeyManager[] km = kmf.getKeyManagers();

            ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(KEYSTORE_PATH), password);
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);
            TrustManager [] tm = tmf.getTrustManagers();

            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(new KeyManager[]{new MyKeyManger(km)}, new TrustManager[]{new MyTrustManger(tm)}, new SecureRandom());
            sslContextSuccess = true;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (CertificateException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (KeyStoreException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (IOException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        } catch (KeyManagementException e) {
            e.printStackTrace();
            sslContextSuccess = false;
        }
        System.out.println("sslContextSuccess=" + sslContextSuccess);
        if(sslContextSuccess){
            Socket socket = null;
            try {
                SSLSocketFactory factory = sslContext.getSocketFactory();
                //客戶端socket對象
                socket = new Socket();
                InetSocketAddress address = new InetSocketAddress("127.0.0.1",8000);
                socket.connect(address,10000);
                SSLSocket ss = (SSLSocket) factory.createSocket(socket,"127.0.0.1", 8000,true);
                System.out.println("client hand shake start"+" "+getCurrentTimeForMillis());
                ss.startHandshake();
                System.out.println("client hand shake End"+" "+getCurrentTimeForMillis());
                OutputStream os = ss.getOutputStream();
                //write the char of 'B' to server
                os.write(66);
                os.flush();
                InputStream is = ss.getInputStream();
                int serverMsg = is.read();
                System.out.println("client receive the server message:" + (char)serverMsg + " " + getCurrentTimeForMillis());
                System.out.println("client ok");
            } catch (IOException e1) {
                e1.printStackTrace();
            }finally {
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public static class MyTrustManger implements X509TrustManager{
        private X509TrustManager mManger;
        public MyTrustManger(TrustManager[] trustManagers){
            if(trustManagers[0] instanceof X509TrustManager){
                mManger = (X509TrustManager) trustManagers[0];
            }
        }
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            System.out.println("client checkClientTrusted "+ getCurrentTimeForMillis());
            mManger.checkClientTrusted(chain,authType);
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            System.out.println("client checkServerTrusted "+ getCurrentTimeForMillis());
            mManger.checkServerTrusted(chain,authType);
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            System.out.println("client getAcceptedIssuers "+ getCurrentTimeForMillis());
            X509Certificate[] certificates = mManger.getAcceptedIssuers();
//            if(certificates!=null){
//                for(X509Certificate certificate:certificates){
//                    System.out.println("client getAcceptedIssuers certificate="+certificate+" "+getCurrentTimeForMillis());
//                }
//            }
            return certificates;
        }
    }
    public static class MyKeyManger implements X509KeyManager {
        private X509KeyManager mKeyManager;

        public MyKeyManger(KeyManager[] keyManagers) {
            if (keyManagers[0] instanceof X509KeyManager) {
                mKeyManager = (X509KeyManager) keyManagers[0];
            }
        }

        @Override
        public String[] getClientAliases(String keyType, Principal[] issuers) {
            System.out.println("client getClientAliases keyType=" + keyType+" "+ getCurrentTimeForMillis());
            return mKeyManager.getClientAliases(keyType, issuers);
        }

        @Override
        public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
            System.out.println("client chooseClientAlias keyType=" + Arrays.toString(keyType)+" "+ getCurrentTimeForMillis());
            return mKeyManager.chooseClientAlias(keyType, issuers, socket);
        }

        @Override
        public String[] getServerAliases(String keyType, Principal[] issuers) {
            System.out.println("client getServerAliases keyType=" + keyType+" "+ getCurrentTimeForMillis());
            return mKeyManager.getServerAliases(keyType, issuers);
        }

        @Override
        public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
            System.out.println("client chooseServerAlias keyType=" + keyType+" "+ getCurrentTimeForMillis());
            return mKeyManager.chooseServerAlias(keyType, issuers, socket);
        }

        @Override
        public X509Certificate[] getCertificateChain(String alias) {
            System.out.println("client getCertificateChain alias=" + alias+" "+ getCurrentTimeForMillis());
            return mKeyManager.getCertificateChain(alias);
        }

        @Override
        public PrivateKey getPrivateKey(String alias) {
            System.out.println("client getPrivateKey alias=" + alias+" "+ getCurrentTimeForMillis());
            return mKeyManager.getPrivateKey(alias);
        }
    }
}

運行結果如下:

sslContextSuccess=true
server receive a client connect 25-Jul-2019 09:30:30:036
sslContextSuccess=true
client hand shake start 25-Jul-2019 09:30:30:038
server chooseServerAlias keyType=EC 25-Jul-2019 09:30:30:062
server chooseServerAlias keyType=RSA 25-Jul-2019 09:30:30:062
server getPrivateKey alias=serverkeystore 25-Jul-2019 09:30:30:062
server getCertificateChain alias=serverkeystore 25-Jul-2019 09:30:30:063
server getAcceptedIssuers 25-Jul-2019 09:30:30:101
client checkServerTrusted 25-Jul-2019 09:30:30:107
client getAcceptedIssuers 25-Jul-2019 09:30:30:307
client chooseClientAlias keyType=[RSA, DSA, EC] 25-Jul-2019 09:30:30:314
client getCertificateChain alias=clientkeystore 25-Jul-2019 09:30:30:314
client getPrivateKey alias=clientkeystore 25-Jul-2019 09:30:30:315
server checkClientTrusted 25-Jul-2019 09:30:30:316
server getAcceptedIssuers 25-Jul-2019 09:30:30:410
client hand shake End 25-Jul-2019 09:30:30:434
serve receive the client message:B 25-Jul-2019 09:30:30:435
server send message to client 25-Jul-2019 09:30:30:435
client receive the server message:C 25-Jul-2019 09:30:30:436
client ok
server ok
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章