Netty應(yīng)用示例(二)SSL/TLS應(yīng)用示例

1、SSL/TLS簡介

協(xié)議是Web瀏覽器與Web服務(wù)器之間安全交換信息的協(xié)議,提供兩個基本的安全服務(wù):鑒別與保密。

1.1、作用

不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文傳播,帶來了三大風(fēng)險。

  • 竊聽風(fēng)險(eavesdropping):第三方可以獲知通信內(nèi)容。
  • 篡改風(fēng)險(tampering):第三方可以修改通信內(nèi)容。
  • 冒充風(fēng)險(pretending):第三方可以冒充他人身份參與通信。

SSL/TLS協(xié)議是為了解決這三大風(fēng)險而設(shè)計的,希望達(dá)到:

  • 保密:在握手協(xié)議中定義了會話密鑰后,所有的消息都被加密。
  • 鑒別:可選的客戶端認(rèn)證,和強制的服務(wù)器端認(rèn)證。
  • 完整性:傳送的消息包括消息完整性檢查(使用MAC)。

1.2、工作原理

1.2.1、基本概念

  • Key:Key 是一個比特(bit)字符串,用來加密解密數(shù)據(jù)的,就像是一把開鎖的鑰匙。

  • 對稱算法(symmetric cryptography):就是需要雙方使用一樣的 key 來加密解密消息算法,常用密鑰算法有 Data Encryption Standard(DES)、triple-strength DES(3DES)、Rivest Cipher 2 (RC2)和 Rivest Cipher 4(RC4)。因為對稱算法效率相對較高,因此 SSL 會話中的敏感數(shù)據(jù)都用通過密鑰算法加密。

  • 非對稱算法(asymmetric cryptography):就是 key 的組成是公鑰私鑰對 (key-pair),公鑰傳遞給對方私鑰自己保留。公鑰私鑰算法是互逆的,一個用來加密,另一個可以解密。常用的算法有 Rivest Shamir Adleman(RSA)、Diffie-Hellman(DH)。非對稱算法計算量大比較慢,因此僅適用于少量數(shù)據(jù)加密,如對密鑰加密,而不適合大量數(shù)據(jù)的通訊加密。

  • 公鑰證書(public key certificate):公鑰證書類似數(shù)字護照,由受信機構(gòu)頒發(fā)。受信組織的公鑰證書就是 certificate authority(CA)。多證書可以連接成證書串,第一個是發(fā)送人,下一個是給其頒發(fā)證書實體,往上到根證書是世界范圍受信組織,包括 VeriSign, Entrust, 和 GTE CyberTrust。公鑰證書讓非對稱算法的公鑰傳遞更安全,可以避免身份偽造,比如 C 創(chuàng)建了公鑰私鑰,對并冒充 A 將公鑰傳遞給 B,這樣 C 與 B 之間進行的通訊會讓 B 誤認(rèn)是 A 與 B 之間通訊。

  • 加密哈希功能(Cryptographic Hash Functions):加密哈希功能與 checksum 功能相似。不同之處在于,checksum 用來偵測意外的數(shù)據(jù)變化而前者用來偵測故意的數(shù)據(jù)篡改。數(shù)據(jù)被哈希后產(chǎn)生一小串比特字符串,微小的數(shù)據(jù)改變將導(dǎo)致哈希串的變化。發(fā)送加密數(shù)據(jù)時,SSL 會使用加密哈希功能來確保數(shù)據(jù)一致性,用來阻止第三方破壞通訊數(shù)據(jù)完整性。SSL 常用的哈希算法有 Message Digest 5(MD5)和 Secure Hash Algorithm(SHA)。

  • 消息認(rèn)證碼(Message Authentication Code):消息認(rèn)證碼與加密哈希功能相似,除了它需要基于密鑰。密鑰信息與加密哈希功能產(chǎn)生的數(shù)據(jù)結(jié)合就是哈希消息認(rèn)證碼(HMAC)。如果 A 要確保給 B 發(fā)的消息不被 C 篡改,他要按如下步驟做 --A 首先要計算出一個 HMAC 值,將其添加到原始消息后面。用 A 與 B 之間通訊的密鑰加密消息體,然后發(fā)送給 B。B 收到消息后用密鑰解密,然后重新計算出一個 HMAC,來判斷消息是否在傳輸中被篡改。SSL 用 HMAC 來保證數(shù)據(jù)傳輸?shù)陌踩?/p>

  • 數(shù)字簽名(Digital Signature):一個消息的加密哈希被創(chuàng)建后,哈希值用發(fā)送者的私鑰加密,加密的結(jié)果就是叫做數(shù)字簽名。

1.2.2、認(rèn)證類型:

  • 單向認(rèn)證:就是用戶到服務(wù)器之間只存在單方面的認(rèn)證,即客戶端會認(rèn)證服務(wù)器端身份,而服務(wù)器端不會去對客戶端身份進行驗證。首先,客戶端發(fā)起握手請求,服務(wù)器收到握手請求后,會選擇適合雙方的協(xié)議版本和加密方式。然后,再將協(xié)商的結(jié)果和服務(wù)器端的公鑰一起發(fā)送給客戶端??蛻舳死梅?wù)器端的公鑰,對要發(fā)送的數(shù)據(jù)進行加密,并發(fā)送給服務(wù)器端。服務(wù)器端收到后,會用本地私鑰對收到的客戶端加密數(shù)據(jù)進行解密。然后,通訊雙方都會使用這些數(shù)據(jù)來產(chǎn)生雙方之間通訊的加密密鑰。接下來,雙方就可以開始安全通訊過程了。
  • 雙向認(rèn)證:就是雙方都會互相認(rèn)證,也就是兩者之間將會交換證書?;镜倪^程和單向認(rèn)證完全一樣,只是在協(xié)商階段多了幾個步驟。在服務(wù)器端將協(xié)商的結(jié)果和服務(wù)器端的公鑰一起發(fā)送給客戶端后,會請求客戶端的證書,客戶端則會將證書發(fā)送給服務(wù)器端。然后,在客戶端給服務(wù)器端發(fā)送加密數(shù)據(jù)后,客戶端會將私鑰生成的數(shù)字簽名發(fā)送給服務(wù)器端。而服務(wù)器端則會用客戶端證書中的公鑰來驗證數(shù)字簽名的合法性。建立握手之后過程則和單向通訊完全保持一致。

1.2.3、握手協(xié)議(Handshake protocol)

握手流程:

握手流程.png

步驟 1:ClientHello – 客戶端發(fā)送所支持的 SSL/TLS 最高協(xié)議版本號和所支持的加密算法集合及壓縮方法集合等信息給服務(wù)器端。
步驟 2.:ServerHello – 服務(wù)器端收到客戶端信息后,選定雙方都能夠支持的 SSL/TLS 協(xié)議版本和加密方法及壓縮方法,返回給客戶端。
步驟 3.:SendCertificate(可選) – 服務(wù)器端發(fā)送服務(wù)端證書給客戶端。
步驟 4: RequestCertificate(可選) – 如果選擇雙向驗證,服務(wù)器端向客戶端請求客戶端證書。
步驟 5.:ServerHelloDone – 服務(wù)器端通知客戶端初始協(xié)商結(jié)束。
步驟 6.:ResponseCertificate(可選) – 如果選擇雙向驗證,客戶端向服務(wù)器端發(fā)送客戶端證書。
步驟 7.:ClientKeyExchange – 客戶端使用服務(wù)器端的公鑰,對客戶端公鑰和密鑰種子進行加密,再發(fā)送給服務(wù)器端。
步驟 8:CertificateVerify(可選) – 如果選擇雙向驗證,客戶端用本地私鑰生成數(shù)字簽名,并發(fā)送給服務(wù)器端,讓其通過收到的客戶端公鑰進行身份驗證。
步驟 9: CreateSecretKey – 通訊雙方基于密鑰種子等信息生成通訊密鑰。
步驟 10: ChangeCipherSpec – 客戶端通知服務(wù)器端已將通訊方式切換到加密模式。
步驟 11:Finished – 客戶端做好加密通訊的準(zhǔn)備。
步驟 12:ChangeCipherSpec – 服務(wù)器端通知客戶端已將通訊方式切換到加密模式。
步驟 13:Finished – 服務(wù)器做好加密通訊的準(zhǔn)備。
步驟 14:Encrypted/DecryptedData – 雙方使用客戶端密鑰,通過對稱加密算法對通訊內(nèi)容進行加密。
步驟 15:ClosedConnection – 通訊結(jié)束后,任何一方發(fā)出斷開 SSL 連接的消息。

1.2.4、記錄協(xié)議(Record protocol)

記錄協(xié)議在客戶機和服務(wù)器握手成功后使用,即客戶機和服務(wù)器鑒別對方和確定安全信息交換使用的算法后,進入SSL記錄協(xié)議,記錄協(xié)議向SSL連接提供兩個服務(wù):

  • 保密性:使用握手協(xié)議定義的秘密密鑰實現(xiàn)
  • 完整性:握手協(xié)議定義了MAC,用于保證消息完整性

記錄協(xié)議的過程:

記錄協(xié)議的過程.png

1.2.5、報警協(xié)議(Alert protocol)

客戶機和服務(wù)器發(fā)現(xiàn)錯誤時,向?qū)Ψ桨l(fā)送一個警報消息。如果是致命錯誤,則算法立即關(guān)閉SSL連接,雙方還會先刪除相關(guān)的會話號,秘密和密鑰。每個警報消息共2個字節(jié),第1個字節(jié)表示錯誤類型,如果是警報,則值為1,如果是致命錯誤,則值為2;第2個字節(jié)制定實際錯誤類型。

1.2.6、秘鑰生成過程

這樣握手協(xié)議完成,下面看下什么是預(yù)備主密鑰,主密鑰是怎么生成的。為了保證信息的完整性和機密性,SSL需要有六個加密秘密:四個密鑰和兩個IV。為了信息的可信性,客戶端需要一個密鑰(HMAC),為了加密要有一個密鑰,為了分組加密要一個IV,服務(wù)也是如此。SSL需要的密鑰是單向的,不同于那些在其他方向的密鑰。如果在一個方向上有攻擊,這種攻擊在其他方向是沒影響的。生成過程如下:

從預(yù)備主秘鑰計算主秘鑰.png
從主秘鑰計算秘鑰材料.png

從秘鑰材料提取加密秘鑰.png

參考博客:

http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
https://segmentfault.com/a/1190000002554673
https://www.ibm.com/developerworks/cn/java/j-lo-ssltls/index.html
https://www.cnblogs.com/zhuqil/archive/2012/10/06/ssl_detail.html
https://www.cnblogs.com/zhuqil/archive/2012/10/06/ssl_detail.html

2、keytool簡介

Java自帶的keytool工具是個密鑰和證書管理工具。它使用戶能夠管理自己的公鑰/私鑰對及相關(guān)證書,用于(通過數(shù)字簽名)自我認(rèn)證(用戶向別的用戶/服務(wù)認(rèn)證自己)或數(shù)據(jù)完整性以及認(rèn)證服務(wù)。它還允許用戶儲存他們的通信對等者的公鑰(以證書形式)。 keytool 將密鑰和證書儲存在一個所謂的密鑰倉庫(keystore)中。缺省的密鑰倉庫實現(xiàn)將密鑰倉庫實現(xiàn)為一個文件。它用口令來保護私鑰。

2.1、Java KeyStore的類型

  • JKS和JCEKS是Java密鑰庫(KeyStore)的兩種比較常見類型(我所知道的共有5種,JKS, JCEKS, PKCS12, BKS,UBER)。
  • JKS的Provider是SUN,在每個版本的JDK中都有,JCEKS的Provider是SUNJCE,1.4后我們都能夠直接使用它。
  • JCEKS在安全級別上要比JKS強,使用的Provider是JCEKS(推薦),尤其在保護KeyStore中的私鑰上(使用TripleDes)。
  • PKCS#12是公鑰加密標(biāo)準(zhǔn),它規(guī)定了可包含所有私鑰、公鑰和證書。其以二進制格式存儲,也稱為 PFX 文件,在windows中可以直接導(dǎo)入到密鑰區(qū),注意,PKCS#12的密鑰庫保護密碼同時也用于保護Key。
  • BKS 來自BouncyCastle Provider,它使用的也是TripleDES來保護密鑰庫中的Key,它能夠防止證書庫被不小心修改(Keystore的keyentry改掉1個 bit都會產(chǎn)生錯誤),BKS能夠跟JKS互操作,讀者可以用Keytool去TryTry。
  • UBER比較特別,當(dāng)密碼是通過命令行提供的時候,它只能跟keytool交互。整個keystore是通過PBE/SHA1/Twofish加密,因此keystore能夠防止被誤改、察看以及校驗。以前,Sun JDK(提供者為SUN)允許你在不提供密碼的情況下直接加載一個Keystore,類似cacerts,UBER不允許這種情況。

2.2、keytool的命令

  • -genkey:在用戶主目錄中創(chuàng)建一個默認(rèn)文件".keystore",還會產(chǎn)生一個mykey的別名,mykey中包含用戶的公鑰、私鑰和證書,(默認(rèn)情況下,keystore會存在用戶系統(tǒng)默認(rèn)目錄,如:win系統(tǒng),會生成在C:\Documents and Settings\用戶名\文件名為“.keystore”);
  • -keystore:指定密鑰庫的名稱(產(chǎn)生的各類信息將不在.keystore文件中);
  • -keyalg:指定密鑰的算法 (如RSA、DSA,default:DSA);
  • -validity:指定創(chuàng)建的證書有效期多少天(default:90);
  • -keysize:指定密鑰長度(default:1024,范圍:512 ~ 2048);
  • -storepass:指定密鑰庫的密碼(獲取keystore信息所需的密碼);
  • -keypass:指定別名條目的密碼(私鑰的密碼);
  • -dname:指定證書擁有者信息。例如: "CN=名字與姓氏,OU=組織單位名稱,O=組織名稱,L=城市或區(qū)域名稱,ST=州或省份名稱,C=單位的兩字母國家代碼";
  • -list:顯示密鑰庫中的證書信息。keytool -list -v -keystore 指定keystore -storepass 密碼 -v 顯示密鑰庫中的證書詳細(xì)信息;
  • -export:將別名指定的證書導(dǎo)出到文件。keytool -export -alias 需要導(dǎo)出的別名 -keystore 指定keystore -file 指定導(dǎo)出的證書位置及證書名稱 -storepass 密碼;
  • -delete:刪除密鑰庫中某條目。keytool -delete -alias 指定需刪除的keystore別名 -keystore 指定keystore -storepass 密碼;
  • -printcert:查看導(dǎo)出的證書信息。keytool -printcert -file yushan.crt;
  • -keypasswd:修改密鑰庫中指定條目口令。keytool -keypasswd -alias 需修改的別名 -keypass 舊密碼 -new 新密碼 -storepass keystore密碼 -keystore sage;
  • -storepasswd:修改keystore口令。keytool -storepasswd -keystore e:\yushan.keystore(需修改口令的keystore) -storepass 123456(原始密碼) -new yushan(新密碼);
  • -import:將已簽名數(shù)字證書導(dǎo)入密鑰庫。keytool -import -alias 別名 -keystore指定keystore -file需導(dǎo)入的證書;

2.3、keytool使用示例

2.3.1、keystone的生成

分階段生成:

命令:

keytool -genkey -alias zhaozhou -keypass zhaozhou -keyalg RSA -keysize 1024 -validity 365 -keystore testStore.keystore -storepass 666666

您的名字與姓氏是什么?
[Unknown]: zhaozhou
您的組織單位名稱是什么?
[Unknown]: jd
您的組織名稱是什么?
[Unknown]: jd
您所在的城市或區(qū)域名稱是什么?
[Unknown]: beijing
您所在的省/市/自治區(qū)名稱是什么?
[Unknown]: beijing
該單位的雙字母國家/地區(qū)代碼是什么?
[Unknown]: ch
CN=zhaozhou, OU=jd, O=jd, L=beijing, ST=beijing, C=ch是否正確?
[否]: y

一次性生成:
命令:

keytool -genkey -alias zhaozhou -keypass zhaozhou -keyalg RSA -keysize 1024 -validity 365 -keystore testStore.keystore -storepass 666666 -dname "CN=zhaozhou, OU=jd, O=jd, L=beijing, ST=beijing, C=ch"

2.3.2、keystore信息的查看

命令:

keytool -list -v -keystore testStore.keystore -storepass 666666

輸出:

密鑰庫類型: JKS
密鑰庫提供方: SUN

您的密鑰庫包含 1 個條目

別名: zhaozhou
創(chuàng)建日期: 2019-1-5
條目類型: PrivateKeyEntry
證書鏈長度: 1
證書[1]:
所有者: CN=zhaozhou, OU=jd, O=jd, L=beijing, ST=beijing, C=ch
發(fā)布者: CN=zhaozhou, OU=jd, O=jd, L=beijing, ST=beijing, C=ch
序列號: ab89854
有效期開始日期: Sat Jan 05 14:59:54 CST 2019, 截止日期: Sun Jan 05 14:59:54 CST
2020
證書指紋:
         MD5: 9D:F0:98:56:3F:F7:9C:38:58:FC:30:3C:2B:28:24:2E
         SHA1: AC:74:9E:A5:41:AD:D6:F7:E1:6E:5E:F9:FD:96:49:FD:E4:E0:D9:C5
         SHA256: CE:77:51:60:00:CB:DF:D5:AE:EA:5D:4F:5C:85:47:14:D9:5A:56:72:66:
F1:A8:E8:8D:1D:E9:50:CC:3B:81:1A
         簽名算法名稱: SHA256withRSA
         版本: 3

擴展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 19 0A A6 EB 67 E9 B8 5B   F5 58 03 2D B9 5D E8 93  ....g..[.X.-.]..
0010: CD 4B B1 98                                        .K..
]
]



*******************************************
*******************************************

2.3.3、證書導(dǎo)出

命令:

keytool -export -alias zhaozhou -keystore testStore.keystore -storepass 666666 -file testStore.cer

輸出:

存儲在文件 <testStore.cer> 中的證書

2.3.4、證書確認(rèn)

命令:

keytool -printcert -file testStore.cer

輸出:

所有者: CN=zhaozhou, OU=jd, O=jd, L=beijing, ST=beijing, C=ch
發(fā)布者: CN=zhaozhou, OU=jd, O=jd, L=beijing, ST=beijing, C=ch
序列號: ab89854
有效期開始日期: Sat Jan 05 14:59:54 CST 2019, 截止日期: Sun Jan 05 14:59:54 CST
2020
證書指紋:
         MD5: 9D:F0:98:56:3F:F7:9C:38:58:FC:30:3C:2B:28:24:2E
         SHA1: AC:74:9E:A5:41:AD:D6:F7:E1:6E:5E:F9:FD:96:49:FD:E4:E0:D9:C5
         SHA256: CE:77:51:60:00:CB:DF:D5:AE:EA:5D:4F:5C:85:47:14:D9:5A:56:72:66:
F1:A8:E8:8D:1D:E9:50:CC:3B:81:1A
         簽名算法名稱: SHA256withRSA
         版本: 3

擴展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 19 0A A6 EB 67 E9 B8 5B   F5 58 03 2D B9 5D E8 93  ....g..[.X.-.]..
0010: CD 4B B1 98                                        .K..
]
]

2.3.5、證書導(dǎo)入

命令:

keytool -import -alias client -file client.cer -keystore testStore.keystore -storepass 666666 -keypass 666666

輸出:

所有者: CN=localhost
發(fā)布者: CN=localhost
序列號: 5b1bd334
有效期開始日期: Fri Jan 04 20:26:42 CST 2019, 截止日期: Sat Jan 04 20:26:42 CST
2020
證書指紋:
         MD5: A1:F3:B4:96:42:E9:62:2B:8C:FB:83:3B:E2:EE:A3:29
         SHA1: 33:01:EA:A6:12:EF:E3:8E:4C:CA:11:EF:D9:4D:DF:3D:85:93:7D:29
         SHA256: 1F:EE:BF:D3:15:78:E2:34:F5:53:0E:49:43:58:0E:BB:3E:A5:EE:22:0E:
D1:82:42:95:CD:19:FA:B1:03:7D:74
         簽名算法名稱: SHA256withRSA
         版本: 3

擴展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 23 9D 32 A9 0F C6 C1 1B   95 57 16 88 20 3E B7 0C  #.2......W.. >..
0010: 2B 8D 21 59                                        +.!Y
]
]

是否信任此證書? [否]:  y
證書已添加到密鑰庫中

2.3.6、刪除證書

命令:

keytool -delete -alias zhaozhou -keystore testStore.keystore -storepass 666666

輸出:

參考博客:

http://tutorials.jenkov.com/java-cryptography/keystore.html
https://www.cnblogs.com/littleatp/p/5922362.html
https://czj4451.iteye.com/blog/1487684
https://my.oschina.net/suyewanwan/blog/164108
https://my.oschina.net/u/2502527/blog/596425
https://my.oschina.net/xinxingegeya/blog/264635
https://www.chinassl.net/ssltools/keytool-commands.html
http://www.cnblogs.com/xdp-gacl/p/3750965.html
https://blog.csdn.net/liumiaocn/article/details/61921014

3、Netty+TLS的加密通信

3.1、單向認(rèn)證

3.1.1、秘鑰及簽名證書生成

(1)生成Netty服務(wù)器公鑰、私鑰和證書倉庫:

keytool -genkey -alias server -keysize 2048 -validity 3650 -keyalg RSA -dname "CN=localhost" -keypass nettyDemo -storepass nettyDemo -keystore serverStore.jks

說明:
-alias server:服務(wù)器證書倉庫關(guān)聯(lián)的別名為
-keypass nettyDemo:服務(wù)器私鑰密碼
-storepass nettyDemo:服務(wù)器秘鑰庫密碼
-keystore serverStore.jks:服務(wù)器秘鑰庫的文件名(默認(rèn)放在用戶主目錄下)

(2)導(dǎo)出Netty服務(wù)端簽名證書:

keytool -export -alias server -keystore serverStore.jks -storepass nettyDemo -file server.cer

(3)生成Netty客戶端的公鑰、私鑰和證書倉庫:

keytool -genkey -alias client -keysize 2048 -validity 3650 -keyalg RSA -dname "CN=localhost" -keypass nettyDemo -storepass nettyDemo -keystore clientStore.jks

說明:

-alias client:客戶端證書倉庫關(guān)聯(lián)的別名;

-keypass nettyDemo:客戶端私鑰密碼;

-storepass nettyDemo:客戶端秘鑰庫密碼

-keystore clientStore.jks:客戶端秘鑰庫的文件名(默認(rèn)放在用戶主目錄下)

(4)將Netty服務(wù)端的證書導(dǎo)入到客戶端的證書倉庫中:

keytool -import -trustcacerts -alias server -file server.cer -storepass nettyDemo -keystore clientStore.jks

最終生成文件:

  • conf/oneway/clientStore.jks:客戶端的證書倉庫(包含公鑰、私鑰、信任的證書倉庫(服務(wù)端的證書))
  • conf/oneway/serverStore.jks:服務(wù)端的證書倉庫(包含公鑰、私鑰、信任的證書倉庫(無證書))
  • conf/oneway/server.cer:服務(wù)端字簽名證書的導(dǎo)出文件

3.1.2、源碼示例

(1)、代碼目錄

源碼目錄.png

clientStore.jks為客戶端的秘鑰庫,serverStore.jks為服務(wù)端的秘鑰庫,server.cer為服務(wù)端的公鑰;

單向認(rèn)證示例源碼:https://github.com/zhaozhou11/netty-demo.git

(2)、服務(wù)端SSLContext生成

public static SSLContext getServerContext(String pkPath){
   if(SERVER_CONTEXT!=null) return SERVER_CONTEXT;
   InputStream in =null;
   
   try{
      //密鑰管理器
      KeyManagerFactory kmf = null;
      if(pkPath!=null){
         //密鑰庫KeyStore
         KeyStore ks = KeyStore.getInstance("JKS");
         //加載服務(wù)端證書
         in = new FileInputStream(pkPath);
         //加載服務(wù)端的KeyStore  ;sNetty是生成倉庫時設(shè)置的密碼,用于檢查密鑰庫完整性的密碼
         ks.load(in, "nettyDemo".toCharArray());
         
         kmf = KeyManagerFactory.getInstance("SunX509");
         //初始化密鑰管理器
         kmf.init(ks, "nettyDemo".toCharArray());
      }
      //獲取安全套接字協(xié)議(TLS協(xié)議)的對象
      SERVER_CONTEXT= SSLContext.getInstance(PROTOCOL);
      //初始化此上下文
      //參數(shù)一:認(rèn)證的密鑰      參數(shù)二:對等信任認(rèn)證  參數(shù)三:偽隨機數(shù)生成器 。 由于單向認(rèn)證,服務(wù)端不用驗證客戶端,所以第二個參數(shù)為null
      SERVER_CONTEXT.init(kmf.getKeyManagers(), null, null);
      
   }catch(Exception e){
      throw new Error("Failed to initialize the server-side SSLContext", e);
   }finally{
      if(in !=null){
         try {
            in.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      
   }
   return SERVER_CONTEXT;
 }

(3)、客戶端SSLContext生成:

public static SSLContext getClientContext(String caPath){
 if(CLIENT_CONTEXT!=null) return CLIENT_CONTEXT;
 
 InputStream tIN = null;
 try{
    //信任庫 
   TrustManagerFactory tf = null;
   if (caPath != null) {
      //密鑰庫KeyStore
       KeyStore tks = KeyStore.getInstance("JKS");
       //加載客戶端證書
       tIN = new FileInputStream(caPath);
       tks.load(tIN, "nettyDemo".toCharArray());
       tf = TrustManagerFactory.getInstance("SunX509");
       // 初始化信任庫  
       tf.init(tks);
   }
    
    CLIENT_CONTEXT = SSLContext.getInstance(PROTOCOL);
    //設(shè)置信任證書
    CLIENT_CONTEXT.init(null,tf == null ? null : tf.getTrustManagers(), null);
    
 }catch(Exception e){
    throw new Error("Failed to initialize the client-side SSLContext");
 }finally{
    if(tIN !=null){
         try {
            tIN.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
 }
 
 return CLIENT_CONTEXT;
}

(4)服務(wù)端ChannelHandler初始化:

ChannelPipeline pipeline = sc.pipeline();
String sChatPath = (System.getProperty("user.dir")+ "/src/main/java/com/zhaozhou/netty/demo/ssl/conf/oneway/serverStore.jks");

SSLEngine engine = SslOneWayContextFactory.getServerContext(sChatPath).createSSLEngine();
engine.setUseClientMode(false);//設(shè)置為服務(wù)器模式
//engine.setNeedClientAuth(false);//不需要客戶端認(rèn)證,默認(rèn)為false,故不需要寫這行。

pipeline.addLast("ssl", new SslHandler(engine));

// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new LineBasedFrameDecoder(1024, false, false));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());

// and then business logic.
pipeline.addLast("handler", new SslOneWayServerHandler());

(5)、服務(wù)端ChannelHandler初始化:

ChannelPipeline pipeline = ch.pipeline();
String cChatPath =  System.getProperty("user.dir")+"/src/main/java/com/zhaozhou/netty/demo/ssl/conf/oneway/clientStore.jks";

SSLEngine engine = SslOneWayContextFactory.getClientContext(cChatPath)
      .createSSLEngine();//創(chuàng)建SSLEngine
engine.setUseClientMode(true);//客戶方模式
pipeline.addLast("ssl", new SslHandler(engine));

// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new LineBasedFrameDecoder(1024, false, false));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());

// and then business logic.
pipeline.addLast("handler", new SslOneWayClientHandler());

(6)、測試輸出

服務(wù)端輸出:

單向服務(wù)端輸出.png

客戶端輸出:

單向客戶端輸出.png

3.2、雙向認(rèn)證

3.2.1、秘鑰及簽名證書生成

雙向認(rèn)證的前面4步和單向認(rèn)證的一樣,雙向認(rèn)證多兩步,需導(dǎo)出客戶端公鑰并將客戶端公鑰導(dǎo)入服務(wù)端的證書倉庫:

(5)、導(dǎo)出Netty的客戶端的自簽名證書:

keytool -export -alias client -keystore clientStore.jks -storepass nettyDemo -file client.cer

(6)、將客戶端的自簽名證書導(dǎo)入到服務(wù)器的證書倉庫中:

keytool -import -trustcacerts -alias client -file client.cer -storepass nettyDemo -keystore serverStore.jks

3.2.2、源碼示例

雙向認(rèn)證的源碼示例與單向認(rèn)證基本相同,在此不多贅述。

雙向認(rèn)證示例源碼:https://github.com/zhaozhou11/netty-demo.git

3.2.3、測試輸出

服務(wù)端輸出:

雙向服務(wù)端輸出.png

客戶端輸出:

雙向客戶端輸出.png

參考博客:

https://blog.csdn.net/zhixinhuacom/article/details/79097737
https://blog.csdn.net/zhixinhuacom/article/details/79126274
https://my.oschina.net/xinxingegeya/blog/267804
https://www.cnblogs.com/liuroy/p/7435356.html
https://dwj147258.iteye.com/blog/2339934
https://dwj147258.iteye.com/blog/2360535
https://blog.csdn.net/virgilli/article/details/42836063
https://waylau.gitbooks.io/essential-netty-in-action/CORE%20FUNCTIONS/Securing%20Netty%20applications%20with%20SSLTLS.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容