• SSLSocket实现服务端和客户端双向认证的例子


    首先创建服务器端私有密钥和公共密钥
    1, keytool -genkey -alias serverkey -keystore kserver.ks
        密码: serverpass
    2, keytool -export -alias serverkey -keystore kserver.ks -file server.crt
    3, keytool -import -alias serverkey -file server.crt -keystore tclient.ks
        密码: clientpublicpass

    下面创建客户器端私有密钥和公共密钥
    1, keytool -genkey -alias clientkey -keystore kclient.ks
        密码: clientpass
    2, keytool -export -alias clientkey -keystore kclient.ks -file client.crt
    3, keytool -import -alias clientkey -file client.crt -keystore tserver.ks
        密码: serverpublicpass

    把服务器端产生的公共密钥放到客户端, 同样把客户端创建的公共密钥放到服务器端.

    下面是服务器端代码:
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.security.KeyStore;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.TrustManagerFactory;

    public class SSLTestServer {

        public static void main(String[] args) throws Exception {
            SSLContext ctx = SSLContext.getInstance("SSL");

            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

            KeyStore ks = KeyStore.getInstance("JKS");
            KeyStore tks = KeyStore.getInstance("JKS");

            ks.load(new FileInputStream("cert/kserver.ks"), "serverpass".toCharArray());
            tks.load(new FileInputStream("cert/tserver.ks"), "serverpublicpass".toCharArray());

            kmf.init(ks, "serverpass".toCharArray());
            tmf.init(tks);

            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            SSLServerSocket serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(8443);
            serverSocket.setNeedClientAuth(true);

            while (true) {
                try {
                    Socket s = serverSocket.accept();
                    InputStream input = s.getInputStream();
                    OutputStream utput = s.getOutputStream();

                    BufferedInputStream bis = new BufferedInputStream(input);
                    BufferedOutputStream bos = new BufferedOutputStream(output);

                    byte[] buffer = new byte[20];
                    int length = bis.read(buffer);
                    System.out.println("Receive: " + new String(buffer, 0, length).toString());

                    bos.write("Hello".getBytes());
                    bos.flush();

                    s.close();
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }
    }

    下面是客户端代码:
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.security.KeyStore;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.TrustManagerFactory;

    public class SSLTestClient {

        public static void main(String[] args) throws Exception {
            SSLContext ctx = SSLContext.getInstance("SSL");

            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

            KeyStore ks = KeyStore.getInstance("JKS");
            KeyStore tks = KeyStore.getInstance("JKS");

            ks.load(new FileInputStream("cert/kclient.ks"), "clientpass".toCharArray());
            tks.load(new FileInputStream("cert/tclient.ks"), "clientpublicpass".toCharArray());

            kmf.init(ks, "clientpass".toCharArray());
            tmf.init(tks);

            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            SSLSocket sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket("localhost", 8443);
            InputStream input = sslSocket.getInputStream();
            OutputStream utput = sslSocket.getOutputStream();

            BufferedInputStream bis = new BufferedInputStream(input);
            BufferedOutputStream bos = new BufferedOutputStream(output);

            bos.write("Hello".getBytes());
            bos.flush();

            byte[] buffer = new byte[20];
            int length = bis.read(buffer);
            System.out.println(new String(buffer, 0, length));

            sslSocket.close();   
        }

    }

    常见的HTTPS传输, 不需要进行客户端认证, 也就是单向认证. 这时也就不需要创建客户端的私钥和公钥. 服务器端也只要配置一下服务器端的私钥即可, 当客户端浏览器访问时会生成一个证书文件,类似于上面创建的crt文件. 如果需要程序访问,可以通过这个crt文件生成一个keystore. 然后是用这个keystore作为trust keystore即可.

    目前我用keytool.exe生成的keystore和证书用于双向认证是没有问题的,但是使用ejbca系统生成的由某CA机构颁发的证书以及生成的keystore用来做双向认证就会报错。

    javax.net.ssl.SSLHandshakeException: null cert chain

    这个问题还需要进一步跟踪解决。

  • 相关阅读:
    ionic3-ng4学习见闻--(aot方式打包问题解决方案)
    ionic3-ng4学习见闻--(轮播图完美方案)
    ionic3-ng4学习见闻--(多语言方案)
    死也要上npm 而不是cnpm苟且偷生
    2017埙箫简谱清单分享(附音频Demo)
    《好久不见》(Cover 陈奕迅)箫声远 洞箫
    React-onsenui之RouterNavigator组件解读
    基于3ds Max的游戏建模方案
    重拾SQL——从无到有
    重拾SQL——表中索值
  • 原文地址:https://www.cnblogs.com/franson-2016/p/5557259.html
Copyright © 2020-2023  润新知