链接
完整程序源码下载,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> <Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/client/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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
客户端请求代码
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.doPost(path); } static { 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"); KeyStore tks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/client/kclient.keystore"), 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 myURL = new URL(path); 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); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
服务端代码
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(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
验证
启动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:80882016-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