PKI学习之路(四)-----------------------SSL双向认证

项目地址:https://github.com/gongxianshengjiadexiaohuihui/PKI/tree/master/ssl

上一篇 我们讲了如何用java自带的keytool工具生成数字证书,我们需要准备两个证书,一个是server的一个是client的

keytool -import -file  client_pub_cer.cer -keystore server.keystore -storepass 123456

把 client的证书导入到server的证书仓库中,并且信任

同样把server的证书导入到client的证书仓库中,并且信任

然后就开始代码编写

服务端代码

package com.ggp.server;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;

/**
 * @ClassName SSLServer
 * @Description TODO
 * @Author Mr.G
 * @Date 2018/11/29 16:44
 * @Version 1.0
 */
public class SSLServer extends Thread {

    private Socket socket;
    private ServerSocket serverSocket;
    public SSLServer(ServerSocket serverSocket)throws Exception{
        this.serverSocket = serverSocket;
    }

    @Override
    public void run() {

        while (this.isAlive()) {
            try {
                socket = serverSocket.accept();
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter writer = new PrintWriter(socket.getOutputStream());
                String data = reader.readLine();
                writer.println(data);
                writer.close();
                socket.close();
            } catch (IOException e) {

            }
        }
    }
    public static void main(String[] args) throws Exception{
        /**
         * KeyStore的位置路径
         */
       String serverKeyStore = "C:\\Users\\14747\\server.keystore";
        /**
         * KeyStore的密码
         */
       String serverKeyStorePassword = "123456";
        /**
         * 指定trustStore
         */
       System.setProperty("javax.net.ssl.trustStore",serverKeyStore);
        /**
         * 定义并初始化一个keyStore
         */
       KeyStore server_KeyStore = KeyStore.getInstance("JKS");
       server_KeyStore.load(new FileInputStream(serverKeyStore),null);
        /**
         * 选用一个安全套接字协议
         */
       SSLContext context = SSLContext.getInstance("TLSv1");

        /**
         * 初始化一个keyManager工厂
         */
       KeyManagerFactory  keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
       keyManagerFactory.init(server_KeyStore,serverKeyStorePassword.toCharArray());
        /**
         * 初始化SSLcontext
         */
       context.init(keyManagerFactory.getKeyManagers(),null,null);
        /**
         * 得到ServerSocket工厂
         */
       ServerSocketFactory factory = context.getServerSocketFactory();
       ServerSocket serverSocket = factory.createServerSocket(28888);
        /**
         * 决定服务端是否验证客户端的身份 即选择单向认证还是双向认证
         */
        ((SSLServerSocket)serverSocket).setNeedClientAuth(true);
       new SSLServer(serverSocket).start();
    }
}

客户端代码

package com.ggp.client;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.security.KeyStore;

/**
 * @ClassName SSLClient
 * @Description TODO
 * @Author Mr.G
 * @Date 2018/11/30 9:17
 * @Version 1.0
 */
public class SSLClient {
    public static void main(String[] args)throws Exception{
        String clientKeyStore = "D:\\client.keystore";
        String clientKeyStorePassword = "123456";

        System.setProperty("javax.net.ssl.trustStore",clientKeyStore);
        System.setProperty("javax.net.debug","ssl,handshake");
        KeyStore client_keyStore = KeyStore.getInstance("JKS");
        client_keyStore.load(new FileInputStream(clientKeyStore),null);
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(client_keyStore,clientKeyStorePassword.toCharArray());
        SSLContext context = SSLContext.getInstance("TLSv1");
        context.init(keyManagerFactory.getKeyManagers(),null,null);

        SSLSocketFactory factory = context.getSocketFactory();
        Socket socket =factory.createSocket("localhost",28888);

        PrintWriter writer = new PrintWriter(socket.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        writer.println("hello");
        writer.flush();
        System.out.println(reader.readLine());
        socket.close();

    }
}

服务端的代码,注释很详细,客户端的代码基本配置和服务端大致相同

然后我们讨论里面出现的几个名词

System.setProperty("javax.net.ssl.trustStore",serverKeyStore);

如果是要发起SSL请求,这个时候通常是需要指定trustStore的

一种方式是通过启动参数指定

java -Djavax.net.ssl.trustStore=yourTruststore -Djavax.net.ssl.trustStorePassword=yourpassword yourApp

还有一种方式,就是通过程序中指定Properties参数进行加载,不过一定要在请求发出前进行加载。就是我们所用的方式

 SSLContext context = SSLContext.getInstance("TLSv1");

首先给出一张图

(1)SSLContext: 此类的实例表示安全套接字协议的实现, 它是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工厂。

(2)SSLSocket: 扩展自Socket

(3)SSLServerSocket: 扩展自ServerSocket

(4)SSLSocketFactory: 抽象类,扩展自SocketFactory, SSLSocket的工厂

(5)SSLServerSocketFactory: 抽象类,扩展自ServerSocketFactory, SSLServerSocket的工厂

(6)KeyStore: 表示密钥和证书的存储设施

(7)KeyManager: 接口,JSSE密钥管理器

(8)TrustManager: 接口,信任管理器

(9)X590TrustedManager: TrustManager的子接口,管理X509证书,验证远程安全套接字

几种SSLContext Algorithms

SL - Supports some version of SSL; may support other versions 
SSLv2 - Supports SSL version 2 or later; may support other versions 
SSLv3 - Supports SSL version 3; may support other versions 
TLS - Supports some version of TLS; may support other versions 
TLSv1 - Supports RFC 2246: TLS version 1.0 ; may support other versions 
TLSv1.1 - Supports RFC 4346: TLS version 1.1 ; may support other versions 
TLSv1.2 - Supports RFC 5246: TLS version 1.2 ; may support other versions 
 

猜你喜欢

转载自blog.csdn.net/qq_33543634/article/details/84634881