傳輸層安全訪問是經過身份驗證和加密傳輸的過程。JDK的JSSE提供了傳輸層安全訪問的實現。本文旨在經過一個完整的TLS通信實例,辨析一個廣泛的誤導。
網絡上停留在理論的簡單實例一般存在一個誤導。在雙向信任的狀況下,雙方都須要信任對方的證書。這樣的例子不少,廣泛拷貝並簡述過程。
其實,在實踐中發現,雙方都信任一個權威的CA,並持有該CA根證書和該CA簽發的證書,便可以信任對方,實現通信,不須要對方證書。這樣作的好處是,鏈接方發生變更後,若是新的接入方也是CA簽發認證的,便可認爲可信。還有一個好處是,減小一個文件的部署(若是該通信被重用在其餘項目,或許這不是小事)。
〇 Scenario
ICM和UCGW是雙向信任的兩方,經過TLS通信。CA是內部公信簽證機構。
一 Certificate
簽證流程:
html
0.CA自簽證書做爲其餘設備的根證書
1.ICM和UCGW(兩方流程一致,如下簡稱ICM)自簽證書
2.向CA發送簽發請求
這一步能夠是發送一個CSR將公鑰信息傳遞給CA
本例是將證書直接發給CA
3.CA爲請求者簽發證書
4.CA發送根證書和CA簽發的證書給請求者
5.ICM將CA根證書導入信任列表
6.ICM將CA簽發的證書替換本身簽發的證書
實現代碼:
java
0.CA自簽證書做爲其餘設備的根證書
CertInfo certInfo
=
new
CertInfo();
SelfSign selfs
=
new
SelfSign();
certInfo.setKeystore(CA_KEYSTORE);
certInfo.setAlias(CA_ALIAS);
certInfo.setCommonName(
"
mars_ca
"
);
selfs.sign(certInfo, CA_CER);
keytool -genkey -dname "CN=mars_ca, OU=rv, O=rcd, L=ZB, ST=bj, C=China" -alias root -keyalg RSA -keystore ca--ca.keystore -keypass 111111 -storepass 111111 -validity 60
keytool -export -alias root -keystore ca--ca.keystore -storepass 111111 -rfc -file ca--ca.cer
Certificate stored in file <ca--ca.cer>
keytool -list -keystore ca--ca.keystore -storepass 111111
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
root, May 24, 2011, PrivateKeyEntry,
Certificate fingerprint (MD5):
24:48:A3:4D:9F:EE:39:DE:8C:E7:51:60:7E:94:7A:76
1.ICM和UCGW(兩方流程一致,如下簡稱ICM)自簽證書
//
CertInfo certInfo = new CertInfo();
//
SelfSign selfs = new SelfSign();
certInfo.setKeystore(ICM_KEYSTORE);
certInfo.setAlias(ICM_ALIAS);
certInfo.setCommonName(
"
mars_icm
"
);
selfs.sign(certInfo, ICM_CER);
//
SelfSign selfs = new SelfSign();
//
CertInfo certInfo = new CertInfo();
certInfo.setKeystore(UCGW_KEYSTORE);
certInfo.setAlias(UCGW_ALIAS);
certInfo.setCommonName(
"
mars_UCGW
"
);
selfs.sign(certInfo, UCGW_CER);
keytool -genkey -dname "CN=mars_icm, OU=rv, O=rcd, L=ZB, ST=bj, C=China" -alias icm -keyalg RSA -keystore iview.keystore -keypass 111111 -storepass 111111 -validity 60
keytool -export -alias icm -keystore iview.keystore -storepass 111111 -rfc -file icm--icm.cer
Certificate stored in file <icm--icm.cer>
keytool -genkey -dname "CN=mars_UCGW, OU=rv, O=rcd, L=ZB, ST=bj, C=China" -alias ucgw -keyalg RSA -keystore ucgw.keystore -keypass 111111 -storepass 111111 -validity 60
keytool -export -alias ucgw -keystore ucgw.keystore -storepass 111111 -rfc -file ucgw--ucgw.cer
Certificate stored in file <ucgw--ucgw.cer>
keytool -export -alias ca_signed -keystore ca--ca_sign.keystore -storepass 111111 -rfc -file ca--icm.signed.cer
Certificate stored in file <ca--icm.signed.cer>
keytool -export -alias ca_signed -keystore ca--ca_sign.keystore -storepass 111111 -rfc -file ca--ucgw.signed.cer
Certificate stored in file <ca--ucgw.signed.cer>
keytool -list -keystore iview.keystore -storepass 111111
Keystore type: JKS
Keystore provider: SUN
Your keystore contains
1
entry
icm
, May
24
,
2011
, PrivateKeyEntry,
Certificate fingerprint (MD5):
78
:5C:AA:1B:
27
:9D:FB:3E:BE:1A:BD:6E:C5:A5:
25
:BD
keytool
-list -keystore ucgw.keystore -storepass 111111
Keystore type: JKS
Keystore provider: SUN
Your keystore contains
1
entry
ucgw
, May
24
,
2011
, PrivateKeyEntry,
Certificate fingerprint (MD5): 7B:
88
:
44
:
27
:
88
:
66
:2D:6B:
64
:E3:D5:
34
:4A:
03
:DA:8F
2.向CA發送簽發請求
3.CA爲請求者簽發證書
CASign cas
=
new
CASign();
cas.sign(ICM_CER, ICM_SIGN_CER, CASIGN_KEYSTORE);
cas.sign(UCGW_CER, UCGW_SIGN_CER, CASIGN_KEYSTORE);
5.ICM將CA根證書導入信任列表
6.ICM將CA簽發的證書替換本身簽發的證書
CertImport im
=
new CertImport();
im.importCA(ICM_KEYSTORE);
im.importSign(ICM_ALIAS, ICM_SIGN_CER, ICM_KEYSTORE);
im.importCA(UCGW_KEYSTORE);
im.importSign(UCGW_ALIAS, UCGW_SIGN_CER, UCGW_KEYSTORE);
keytool -importcert -noprompt -alias root -file ca--ca.cer -keystore iview.keystore -storepass 111111
Certificate was added to keystore
keytool -importcert -noprompt -trustcacerts -alias icm -file ca--icm.signed.cer -keystore iview.keystore -storepass 111111 -keypass 111111
Certificate reply was installed in keystore
keytool -importcert -noprompt -alias root -file ca--ca.cer -keystore ucgw.keystore -storepass 111111
Certificate was added to keystore
keytool -importcert -noprompt -trustcacerts -alias ucgw -file ca--ucgw.signed.cer -keystore ucgw.keystore -storepass 111111 -keypass 111111
Certificate reply was installed in keystore
keytool -list -keystore iview.keystore -storepass 111111
Keystore type: JKS
Keystore provider: SUN
Your keystore contains
2
entries
root
, May
24
,
2011
, trustedCertEntry,
Certificate fingerprint (MD5):
24
:
48
:A3:4D:9F:EE:
39
:DE:8C:E7:
51
:
60
:7E:
94
:7A:
76
icm
, May
24
,
2011
, PrivateKeyEntry,
Certificate fingerprint (MD5):
18
:D9:
40
:BD:
65
:6C:4D:B9:F3:
87
:2B:
09
:
63
:CD:F0:7A
keytool
-list -keystore ucgw.keystore -storepass 111111
Keystore type: JKS
Keystore provider: SUN
Your keystore contains
2
entries
root
, May
24
,
2011
, trustedCertEntry,
Certificate fingerprint (MD5):
24
:
48
:A3:4D:9F:EE:
39
:DE:8C:E7:
51
:
60
:7E:
94
:7A:
76
ucgw
, May
24
,
2011
, PrivateKeyEntry,
Certificate fingerprint (MD5): 2A:3D:3F:A6:E3:2F:
36
:B9:
71
:CD:AB:1D:9F:
19
:8A:
49
二 TLS
這裏以ICM做爲服務器端,UCGW做爲客戶端。
方式一:加載keystore到環境變量,啓用默認工廠SSL-Server-Socket-Factory
安全
public
class
SSLServer {
public
static
void
main(String args[])
throws
Exception {
System.setProperty(
"
javax.net.ssl.keyStore
"
, TLSParameter.ICM_KEYSTORE);
System.setProperty(
"
javax.net.ssl.keyStorePassword
"
, TLSParameter.S_KEY_PASS);
SSLServerSocketFactory ssf
=
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss
=
ssf.createServerSocket(TLSParameter.SSLPORT);
System.out.println(
"
SSL Server is started.
"
);
while
(
true
) {
Socket s
=
ss.accept();
PrintStream out
=
new
PrintStream(s.getOutputStream());
out.println(
"
ICM say Hello to UCGW!
"
);
out.close();
s.close();
}
}
}
public
class
SSLClient {
public
static
void
main(String args[])
throws
Exception {
System.setProperty(
"
javax.net.ssl.trustStore
"
, TLSParameter.UCGW_KEYSTORE);
SSLSocketFactory ssf
=
(SSLSocketFactory) SSLSocketFactory.getDefault();
Socket s
=
ssf.createSocket(TLSParameter.IP, TLSParameter.SSLPORT);
BufferedReader in
=
new
BufferedReader(
new
InputStreamReader(s.getInputStream()));
String x
=
in.readLine();
System.out.println(x);
in.close();
}
}
方式二:設置SSLContext,經過上下文實例啓用SSL-Server-Socket-Factory
服務器
public
class
SSLServer1 {
public
static
void
main(String args[])
throws
Exception {
SSLContext sslContext
=
SSLContext.getInstance(PROTOCOL);
KeyManager[] km
=
TLSSocket.createKeyManagers(keyStoreType, ICM_KEYSTORE);
TrustManager[] tm
=
TLSSocket.createTrustManagers(keyStoreType, ICM_KEYSTORE);
SecureRandom random
=
SecureRandom.getInstance(SHA1PRNG);
sslContext.init(km, tm, random);
SSLServerSocketFactory factory
=
sslContext.getServerSocketFactory();
ServerSocket ss
=
(SSLServerSocket) factory.createServerSocket(SSLPORT);
System.out.println(
"
SSL Server is started.
"
);
while
(
true
) {
Socket s
=
ss.accept();
PrintStream out
=
new
PrintStream(s.getOutputStream());
out.println(
"
ICM say Hello to UCGW!
"
);
out.close();
s.close();
}
}
}
public
class
SSLClient1 {
public
static
void
main(String args[])
throws
Exception {
SSLContext sslContext
=
SSLContext.getInstance(PROTOCOL);
KeyManager[] km
=
TLSSocket.createKeyManagers(keyStoreType, UCGW_KEYSTORE);
TrustManager[] tm
=
TLSSocket.createTrustManagers(keyStoreType, UCGW_KEYSTORE);
SecureRandom random
=
SecureRandom.getInstance(SHA1PRNG);
sslContext.init(km, tm, random);
SSLSocketFactory factory
=
sslContext.getSocketFactory();
System.out.println(
"
TLS Client, Connecting to server
"
+
IP
+
"
:
"
+
SSLPORT);
SSLSocket socket
=
(SSLSocket) factory.createSocket(IP, SSLPORT);
socket.setUseClientMode(
true
);
BufferedReader in
=
new
BufferedReader(
new
InputStreamReader(socket.getInputStream()));
String x
=
in.readLine();
System.out.println(x);
in.close();
}
}
三 Summary
ICM和UCGW共同信任CA,各自持有CA根證書和CA簽發的自身證書,經過TLS協議實現傳輸層的安全通信。
雙向信任的兩方無需持有對方證書。
四 EasterEgg
運行結果:
服務器端:
網絡
SSL Server is started.
client端:
ICM say Hello to UCGW!
網絡包分析(工具:Wireshark)
1.抓取本地通訊:route add 192.168.225.166 mask 255.255.255.255 192.168.225.254 metric 1
iview
Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . :
192.168.225.166
Subnet Mask . . . . . . . . . . . : 255.255.255.0
IP Address. . . . . . . . . . . . : fe80::225:64ff:feb3:88dc%4
Default Gateway . . . . . . . . . :
192.168.225.254
2.設置過濾器
Filter:
ip.addr==192.168.225.166
Decode As:
transport = SSL
Filter:
ip.addr==192.168.225.166&&ssl
3.結果和分析
測試完畢 請刪除本地IP:(reference: http://hi.baidu.com/btb368/blog/item/098d36acfbc837014b36d6cd.html)
route delete 192.168.225.166
Export File:
No. Time Source Destination Protocol Info
217
12.022322
192.168
.
225.166
192.168
.
225.166
SSLv2 Client Hello
Transmission Control Protocol,
Src Port: prp (
2091
), Dst Port:
9527
(
9527
)
, Seq:
1
, Ack:
1
, Len:
103
Secure Socket Layer
SSLv2 Record Layer: Client Hello
No. Time Source Destination Protocol Info
219
12.024335
192.168
.
225.166
192.168
.
225.166
TLSv1 Server Hello, Certificate, Server Hello Done
Transmission Control Protocol,
Src Port:
9527
(
9527
), Dst Port: prp (
2091
)
, Seq:
1
, Ack:
104
, Len:
1210
Secure Socket Layer
TLSv1 Record Layer: Handshake Protocol: Multiple Handshake Messages
No. Time Source Destination Protocol Info
221
12.036842
192.168
.
225.166
192.168
.
225.166
TLSv1 Client Key Exchange
Transmission Control Protocol,
Src Port: prp (
2091
), Dst Port:
9527
(
9527
)
, Seq:
104
, Ack:
1211
, Len:
139
Secure Socket Layer
TLSv1 Record Layer: Handshake Protocol: Client Key Exchange
No. Time Source Destination Protocol Info
225
12.161312
192.168
.
225.166
192.168
.
225.166
TLSv1 Change Cipher Spec, Encrypted Handshake Message
Transmission Control Protocol,
Src Port: prp (
2091
), Dst Port:
9527
(
9527
)
, Seq:
243
, Ack:
1211
, Len:
43
Secure Socket Layer
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message
No. Time Source Destination Protocol Info
227
12.165380
192.168
.
225.166
192.168
.
225.166
TLSv1 Change Cipher Spec
Transmission Control Protocol,
Src Port:
9527
(
9527
), Dst Port: prp (
2091
)
, Seq:
1211
, Ack:
286
, Len:
6
Secure Socket Layer
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
No. Time Source Destination Protocol Info
229
12.165965
192.168
.
225.166
192.168
.
225.166
TLSv1 Encrypted Handshake Message, Application Data, Application Data, Encrypted Alert
Transmission Control Protocol,
Src Port:
9527
(
9527
), Dst Port: prp (
2091
)
, Seq:
1217
, Ack:
286
, Len:
126
Secure Socket Layer
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message
TLSv1 Record Layer: Application Data Protocol: Application Data
TLSv1 Record Layer: Application Data Protocol: Application Data
TLSv1 Record Layer: Encrypted Alert
No. Time Source Destination Protocol Info
233
12.166930
192.168
.
225.166
192.168
.
225.166
TLSv1 Encrypted Alert
Transmission Control Protocol,
Src Port: prp (
2091
), Dst Port:
9527
(
9527
)
, Seq:
286
, Ack:
1344
, Len:
23
Secure Socket Layer
TLSv1 Record Layer: Encrypted Alert