Java 安全套接字编程以及 keytool 使用最佳实践(二)

2014-11-24 07:42:52 · 作者: · 浏览: 1
est_server_trust.jks:该文件中存有信任客户端的证书,用于 SSL/TSL 通信的服务端;

4. test_client_cert.jks:该文件中存有 CA 签名的证书,用于 SSL/TSL 通信的客户端;

5. test_client_trust.jks:该文件中存有信任服务端的证书,用于 SSL/TSL 通信的客户端。

假定每个 jks 文件的密码都设定为“Testpassw0rd”,都存放在“D:”盘下。

通过系统属性指定证书库和信任库

这种编写方式比较简单直观,可以通过给 JVM 传递参数,或者在代码中使用 System.setProperty() 方法,来指定通信需要的 jks 文件。

服务端程序

要运行如清单 1 所示的程序,可以在命令行添加如下虚拟机参数,指定服务端程序要使用的证书库和密码:

-Djavax.net.ssl.keyStore="D:/test_server_cert.jks"

-Djavax.net.ssl.keyStorePassword="Testpassw0rd"

注意到程序中 setNeedClientAuth(false),表示不需要验证客户端身份。如果这里设置为 true,则我们这里还需要指定信任库和密码:

-Djavax.net.ssl.trustStore="D:/test_server_trust.jks"

-Djavax.net.ssl.trustStorePassword="Testpassw0rd"

清单 1. 简单的 SSL 通信服务端程序
 import java.io.BufferedReader; 
 import java.io.IOException; 
 import java.io.InputStreamReader; 
 import java.net.Socket; 

 import javax.net.ssl.SSLServerSocket; 
 import javax.net.ssl.SSLServerSocketFactory; 
 import javax.net.ssl.SSLSocket; 

  public class Simple_SSLServerSocket{ 
  // 定义了监听端口号
  private final static int LISTEN_PORT=54321;

   public static void main(String args[]) throws IOException{ 
    SSLServerSocket serverSocket=null; 
    SSLSocket clientSocket=null; 
    // 使用默认方式获取套接字工厂实例
    SSLServerSocketFactory ssf=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();

   try{ 
      serverSocket=(SSLServerSocket)ssf.createServerSocket(LISTEN_PORT); 
      // 设置不需要验证客户端身份
      serverSocket.setNeedClientAuth(false);
      System.out.println("SSLServer is listening on "+LISTEN_PORT+" port"); 
      // 循环监听端口,如果有客户端连入就新开一个线程与之通信
      while(true){ 
        // 接受新的客户端连接
        clientSocket=(SSLSocket)serverSocket.accept(); 
        ClientConnection clientConnection=new ClientConnection(clientSocket); 
        // 启动一个新的线程
        Thread clientThread=new Thread(clientConnection); 
        System.out.println("Client "+clientThread.getId()+" is connected"); 
        clientThread.run(); 
      } 
    }catch(IOException ioExp){ 
      ioExp.printStackTrace(); 
    }catch(Exception e){ 
      e.printStackTrace(); 
    }finally{ 
      serverSocket.close(); 
    } 
  } 
 } 

 class ClientConnection implements Runnable{ 
  private Socket clientSocket=null;
 
 public ClientConnection(SSLSocket sslsocket){ 
    clientSocket=sslsocket; 
  }

  public void run(){ 
    BufferedReader reader=null; 
    // 将接收到的来自客户端的文字打印出来
    try{ 
      reader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
      while(true){ 
        String line=reader.readLine(); 
        if(line==null){ 
          System.out.println("Communication end."); 
          break; 
        } 
        System.out.println("Receive message: "+line); 
      } 
      reader.close(); 
      clientSocket.close(); 
    }catch(IOException ioExp){ 
      ioExp.printStackTrace(); 
    }catch(Exception e){ 
      e.printStackTrace(); 
    } 
  } 
 }

客户端程序

对应于清单 1 所示的服务端程序,清单 2 是客户端程序,需要在命令行添加如下虚拟机参数,指定信任库和密码:

-Djavax.net.ssl.trustStore="D:/test_client_trust.jks"

-Djavax.net.ssl.trustStorePassword="Testpassw0rd"

如果服务端程序 setNeedClientAuth(true) 要求验证客户端身份,则我们还需要指定证书库和密码:

-Djavax.net.ssl.keyStore="D:/test_client_cert.jks"

-Djavax.net.ssl.keyStorePassword="Testpassw0rd"

清单 2. 简单的 SSL 通信客户端程序
 import java.io.BufferedReader; 
 import java.io.IOException; 
 import java.io.InputStreamReader; 
 import java.io.OutputStreamWriter; 
 import java.io.Writer; 
 import javax.net.ssl.SSLSocket; 
 import javax.net.ssl.SSLSocketFactory; 


 public class Simple_SSLSocket{ 
  // 定义要连接的服务器名和端口号