SSL通訊涉及兩方的參與者,通常採用的模型是Client/Server。如果我們開發Client端產品(比如瀏覽器),可能會和多方的Server產品對接。那麼問題來了,雙方是如何知道對方使用了國密演算法呢?這個問題非常重要,只有雙方採用同樣的加密標準,才能正常通訊。難道採用“天王蓋地虎,寶塔鎮河妖”的接頭暗號?
在揭開這個謎底之前,我們先了解一下OID(Object Identifier,物件標誌符),然後再聊一聊密碼套件(Cipher Suite),就可以慢慢理解SSL通訊雙方是如何接上頭的。當然,整個SSL通訊涉及到很多標準和協議,不是一篇文章能講完的,所以本文只是拋磚引玉,探討一些基本的概念。可能對於資深人士而言,不值得一提,但我初入門時,也是摸索了好久,才慢慢能深入到細節。
OIDOID是由ISO/IEC、ITU-T國際標準化組織上世紀80年代聯合提出的標識機制,其野心很大,為任何型別的物件(包括實體物件、虛擬物件和組合物件)進行全球唯一命名。透過唯一的編碼,我們就可以識別出物件。但要為所有物件進行唯一命名,其難度和工作量都很大,所以它採用了分層樹形結構。
OID對應於“OID樹”或層次結構中的一個節點,該節點是使用ITU的OID標準X.660正式定義的。樹的根包含以下三個起點:
0:ITU-T1:ISO2:ITU-T/ISO聯合釋出
樹中的每個節點都由一系列由句點分隔的整數表示。比如,表示英特爾公司的OID如下所示:
1.3.6.1.4.1.343
對應於OID樹中的含義:
1 ISO1.3 識別組織1.3.6 美國國防部1.3.6.1 網際網路1.3.6.1.4 私人1.3.6.1.4.1 IANA企業編號1.3.6.1.4.1.343 英特爾公司
這裡採用分而治之的策略,解決編碼重複問題。樹中的每個節點均由分配機構控制,該機構可以在該節點下定義子節點,併為子節點委託分配機構。
在上面的例子中,根節點“1”下的節點號由ISO分配,“1.3.6”下的節點由美國國防部分配,“1.3.6.1.4.1”下的節點由IANA分配,“1.3.6.1.4.1.343”下的節點由英特爾公司分配,依此類推。只要有需求,可以一直往下分配下去,也解決了編碼不夠的問題。
在實際應用中,ISO/IEC國際標準化機構維護頂層OID標籤,各個國家負責該國家分支下的OID分配、註冊和解析等工作,實現自我管理和維護。
相應的,針對國密,國家密碼局也定義了各類物件的識別符號:
國密相關OID定義
詳細可參考 GM/T 0006-2012 這份標準。
像"1.2.156.10197.1.100"這種字串,人讀起來比較直觀,但對於計算機處理而言,卻是大大的不方便,要知道字串處理的效率非常低,所以在程式程式碼中,對OID又進行了一次編碼。
在GmSSL原始碼中,原始的OIDs定義在objects.txt檔案中,在檔案的尾部,我們可以看到國密的相關定義:
# GM/Tmember-body 156 : ISO-CN : ISO CN Member BodyISO-CN 10197 : osccaoscca 1 : sm-schemesm-scheme 103 1 : SSF33-ECB : ssf33-ecbsm-scheme 103 2 : SSF33-CBC : ssf33-cbc!Cname ssf33-ofb128sm-scheme 103 3 : SSF33-OFB : ssf33-ofb!Cname ssf33-cfb128sm-scheme 103 4 : SSF33-CFB : ssf33-cfbsm-scheme 103 5 : SSF33-CFB1 : ssf33-cfb1sm-scheme 103 6 : SSF33-CFB8 : ssf33-cfb8sm-scheme 103 7 : SSF33-CBC-MAC : ssf33-cbc-macsm-scheme 102 1 : SM1-ECB : sm1-ecbsm-scheme 102 2 : SM1-CBC : sm1-cbc!Cname sm1-ofb128sm-scheme 102 3 : SM1-OFB : sm1-ofb!Cname sm1-cfb128sm-scheme 102 4 : SM1-CFB : sm1-cfbsm-scheme 102 5 : SM1-CFB1 : sm1-cfb1sm-scheme 102 6 : SM1-CFB8 : sm1-cfb8# SM2 OIDssm-scheme 301 : sm2p256v1sm-scheme 301 1 : sm2signsm-scheme 301 2 : sm2exchangesm-scheme 301 3 : sm2encrypt
透過 objects.pl 指令碼,生成 obj_data.h檔案,這個才是在程式碼中使用到的OID編碼。
boringssl也類似,不過其採用了 go 語言編寫的轉換指令碼。
密碼套件僅僅定義了OID還不夠,因為國密並不是一個單一的標準,包含了很多加密、解密、雜湊等演算法,可以形成很多種組合,不能簡單假定對方採用了國密就可以建立通訊。
在SSL通訊開始,雙方就需要進行協商,採用何種演算法進行通訊。這裡需要重點理解密碼套件(CipherSuite)的概念。
密碼套件是一系列密碼學演算法的組合,主要包含多個密碼學演算法:
身份驗證演算法。密碼協商演算法。加密演算法或者加密模式。HMAC演算法的加密基元。PRF演算法的加密基元,需要注意的是,不同的TLS/SSL協議版本、密碼套件,PRF演算法最終使用的加密基元和HMAC演算法使用的加密基元是不一樣的。密碼套件的構成如下圖所示:
密碼套件結構
密碼套件決定了本次連線採用哪一種加密演算法、金鑰協商演算法、HMAC演算法,協商的結果就是雙方都認可的密碼套件。
密碼套件協商過程有點類似於客戶採購物品的過程,客戶(客戶端)在向商家(伺服器端)買東西之前需要告知商家自己的需求、預算,商家瞭解使用者的需求後,根據使用者的具體情況(比如客戶願意接受的價格,客戶期望物品的使用年限)給使用者推薦商品,只有雙方都滿意了,交易才能完成。對於TLS/SSL協議來說,只有協商出密碼套件,才能進行下一步的工作。
除了現有國際上標準的密碼套件,國密還定義了一系列的密碼套件:
國密密碼套件列表
程式碼可以參考 gmtls.h 檔案,也可以使用GMSSL的命令檢視所支援的密碼套件:
openssl ciphers -V | column -t
與國密相關的密碼套件有:
0xE1,0x07 - ECDHE-SM2-WITH-SMS4-GCM-SM3 TLSv1.2 Kx=ECDH Au=SM2 Enc=SMS4GCM(128) Mac=AEAD0xE1,0x02 - ECDHE-SM2-WITH-SMS4-SM3 TLSv1.2 Kx=ECDH Au=SM2 Enc=SMS4(128) Mac=SM30xF1,0x20 - ECDHE-PSK-WITH-SMS4-CBC-SM3 TLSv1 Kx=ECDHEPSK Au=PSK Enc=SMS4(128) Mac=SM30xE0,0x17 - SM9-WITH-SMS4-SM3 GMTLSv1.1 Kx=SM9 Au=SM9 Enc=SMS4(128) Mac=SM30xE0,0x15 - SM9DHE-WITH-SMS4-SM3 GMTLSv1.1 Kx=SM9DHE Au=SM9 Enc=SMS4(128) Mac=SM30xE0,0x13 - SM2-WITH-SMS4-SM3 GMTLSv1.1 Kx=SM2 Au=SM2 Enc=SMS4(128) Mac=SM30xE0,0x11 - SM2DHE-WITH-SMS4-SM3 GMTLSv1.1 Kx=SM2DHE Au=SM2 Enc=SMS4(128) Mac=SM30xE0,0x1A - RSA-WITH-SMS4-SHA1 GMTLSv1.1 Kx=RSA Au=RSA Enc=SMS4(128) Mac=SHA10xE0,0x19 - RSA-WITH-SMS4-SM3 GMTLSv1.1 Kx=RSA Au=RSA Enc=SMS4(128) Mac=SM30xF1,0x01 - PSK-WITH-SMS4-CBC-SM3 SSLv3 Kx=PSK Au=PSK Enc=SMS4(128) Mac=SM3
第一列:數值代表密碼套件的編號,每個密碼套件的編號由IANA定義。第二列:代表密碼套件的名稱,雖然密碼套件編號是一致的,不同的TLS/SSL協議實現其使用的名稱可能是不一樣的。第三列:表示該密碼套件適用於哪個TLS/SSL版本的協議。第四列:表示金鑰協商演算法。第五列:表示身份驗證演算法。第六列:表示加密演算法、加密模式、金鑰長度。第七列:表示HMAC演算法。其中AEAD表示採用的是AEAD加密模式(比如AES128-GCM),無須HMAC演算法。值得注意的是,這裡的編碼又沒有采用OID,這也是開發過程中需要注意的,不同的地方使用了不同標準規範,需要在開發中翻閱相應的協議和規範。
可以看出,GmSSL並沒有實現所有的國密的密碼套件,但同時又擴充了幾個標準未定義的密碼套件,比如ECDHE-SM2-WITH-SMS4-GCM-SM3、ECDHE-SM2-WITH-SMS4-SM3等。這就體現出協商的重要性了,對雙方所支援的密碼套件取一個交集,從中選擇一個。如果不存在交集,協商也就不成功。注意,協商過程中伺服器端可能會禁用一些不太安全的密碼套件(比如歷史遺留的一些現今已不太安全的演算法),這時即使雙方都支援,也可能協商不成功。
我們可以測試伺服器是否支援某個特定的密碼套件:
openssl s_client -cipher "ECDHE-SM2-WITH-SMS4-SM3" -connect sm2test.ovssl.cn:443 -tls1_2 -servername sm2test.ovssl.cn
當然,如何協商出密碼套件,涉及到SSL通訊協議細節,如果開發中涉及到,就需要翻閱相應的RFC,這裡不做過多展開。
小結本文簡單介紹了OID和密碼套件的概念,這對於理解SSL通訊有很重要的幫助,如果從事SSL開發,開始面對一大堆的協議和標準,可能會懵圈,希望本文能給你一個探索國密的入口通道。在和第三方服務進行對接時,由於對這些概念理解不深,也是掉了很多坑,希望本文對你有所幫助。
出處:https://mp.weixin.qq.com/s/t82z0uKW2AZjtPop79wjvg