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{
// 定义要连接的服务器名和端口号