链接
完整程序源码下载,csdn还没验证通过
1. 包含https和socket两种ssl测试代码
2. 所有密码均为123456
环境准备
- eclipse中安装run-jetty-run插件 csdn下载资源
- java环境支持,需要使用keytool命令
开始
生成服务器证书
- keytool -genkey -alias serverkey -keyalg RSA -keystore kserver.keystore
- keytool -export -alias serverkey -keystore kserver.keystore -rfc -file server.crt
- keytool -import -alias serverkey -file server.crt -keystore tclient.keystore
其中:kserver.keystore就是服务使用的keystore,server.crt是证书,tclient.keystore是给客户端使用的信任keystore
特别说明:这里我们使用自己的keystore直接导出证书,仅在自己的内部系统可用,如果希望在公网可用,应生成crs向ca申请证书
生成客户端证书
JKS方式
- keytool -genkey -alias clientKey -keystore kclient.keystore
- keytool -export -alias clientKey -keystore kclient.keystore -file client.crt
- keytool -import -alias clientKey -file client.crt -keystore tserver.keystore
PKCS12方式
- keytool -genkeypair -alias clientkey -keyalg RSA -storetype PKCS12 -keystore client.p12
- keytool -export -alias clientKey -keystore client.p12 -storetype PKCS12 -rfc -file client.crt
- keytool -import -alias clientKey -file client.crt -keystore tserver.keystore
配置Jetty环境
特别说明:这里单独配置了jetty.xml文件,因为无法确认jetty在做双向验证时候的可信证书从哪里找的,所以通过jetty.xml文件来指定位置。如果使用单向验证,那么可以直接使用jetty的ssl配置即可。
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
<Arg>
<New class="org.eclipse.jetty.http.ssl.SslContextFactory">
<Set name="keyStore">D:/workspace/SSLServer/src/ssl/keystore/server/kserver.keystore</Set>
<Set name="keyStorePassword">123456</Set>
<Set name="keyManagerPassword">123456</Set>
<!-- JSK -->
<Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/client/tserver.keystore</Set>
<!-- PKCS12 -->
<!--<Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/pk12/tserver.keystore</Set>-->
<Set name="trustStorePassword">123456</Set>
<Set name="needClientAuth">true</Set>
</New>
</Arg>
<Set name="port">8443</Set>
<Set name="maxIdleTime">30000</Set>
</New>
</Arg>
</Call>
</Configure>
客户端请求代码
package ssl.https;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
public class SSLSayClient {
private static final String CLIENT_KEY_STORE_PASSWORD = "123456";
private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";
private SSLSocketFactory ssLSocketFactory;
public static void main(String[] args) throws Exception {
String path = "https://192.168.1.83:8443/SSLServer/say";
SSLSayClient client = new SSLSayClient();
client.init();// 双向验证
// client.initOneWay();// 单向验证
client.doPost(path);
}
static {
// 默认ip地址校验通过
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
/**
* 双向验证
*/
public void init() {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");// JKS
// KeyStore ks = KeyStore.getInstance("PKCS12");// PKCS12
KeyStore tks = KeyStore.getInstance("JKS");
// JSK
ks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/client/kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
// PKCS12
// ks.load(new
// FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/pk12/client.p12"),
// CLIENT_KEY_STORE_PASSWORD.toCharArray());
tks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/server/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
ssLSocketFactory = ctx.getSocketFactory();
} catch (Exception e) {
System.out.println(e);
}
}
/**
* 单向验证
*/
public void initOneWay() {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/server/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(null, tmf.getTrustManagers(), new SecureRandom());
ssLSocketFactory = ctx.getSocketFactory();
} catch (Exception e) {
System.out.println(e);
}
}
/**
* POST
*/
public void doPost(String path) throws Exception {
if (ssLSocketFactory == null) {
System.out.println("ERROR");
return;
}
// 创建URL对象
URL myURL = new URL(path);
// 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
HttpsURLConnection httpsConn = (HttpsURLConnection) myURL.openConnection();
httpsConn.setSSLSocketFactory(ssLSocketFactory);
String encoding = "UTF-8";
byte[] data = "Hello Server".getBytes(encoding);
httpsConn.setRequestMethod("POST");
httpsConn.setDoOutput(true);
httpsConn.setRequestProperty("Content-Type", "application/json; charset=" + encoding);
httpsConn.setRequestProperty("Content-Length", String.valueOf(data.length));
OutputStream outStream = httpsConn.getOutputStream();
outStream.write(data);
outStream.flush();
outStream.close();
BufferedReader a = new BufferedReader(new InputStreamReader(httpsConn.getInputStream(), "UTF-8"));
String line = null;
while ((line = a.readLine()) != null) {
System.out.println(line);
}
}
}
服务端代码
package ssl.https;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Say extends HttpServlet {
private static final long serialVersionUID = -840442603737824400L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Server Get");
String encoding = "UTF-8";
response.setContentType("application/json; charset=" + encoding);
OutputStream outStream = response.getOutputStream();
outStream.write("Hello Client Get".getBytes(encoding));
outStream.flush();
outStream.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Server Post");
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
String encoding = "UTF-8";
response.setContentType("application/json; charset=" + encoding);
OutputStream outStream = response.getOutputStream();
outStream.write("Hello Client Post".getBytes(encoding));
outStream.flush();
outStream.close();
}
}
验证
启动jetty服务器
提示以下信息,证明服务器启动正常
2016-02-23 10:38:52.628:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/SSLServer,[file:/D:/workspace/SSLServer/WebContent/]}
2016-02-23 10:38:52.710:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8088
2016-02-23 10:38:52.896:INFO:oejus.SslContextFactory:Enabled Protocols [SSLv2Hello, SSLv3, TLSv1] of [SSLv2Hello, SSLv3, TLSv1]
2016-02-23 10:38:52.899:INFO:oejs.AbstractConnector:Started SslSelectChannelConnector@0.0.0.0:8443
执行客户端ssl双向请求
如果请求成功,将出现如下信息:
客户端提示:
Hello Client Post
服务端提示:
Server Post
Hello Server