一、說明
盡管做過證書生成、雙向認證、SSL通信編程等事情,但一直不清楚SSL如何完成密鑰交換。看網上的資料則眾說紛紜,最近和朋友學習時聊到了這個問題,然后正巧上周處理客戶反饋SSL版本過低時領導也想弄清SSL的密鑰交換過程,所以來研究一番。
二、密鑰交換過程
第一步,客戶端向服務端,Client Hello(Client Random+Session ID+Cipher Suites);Cipher Suites是客戶端支持的加密套件列表。
第二步,服務端接收到Client Hello后,取出Session ID看該Session ID是否在自己認識的列表中。
如果在,則返回Server Hello(Server Random+Session ID+Cipher Suite+Exist Key(Client Random)),要求使用已有密鑰進行通信。
如果不在,則返回Server Hello(Server Random+Cipher Suite+Certificate);其中,如果服務器選Cipher Suite使用RSA做密鑰交換那么整個Server Hello以一個tcp包的形式返回,如果使用DH做密鑰交換那么Certificate等都單獨用一個tcp包返回。
第三步,客戶端接收到Server Hello。
如果看到是要求使用已有密鑰進行通信,則發送Change Cipher(Exist Key(Server Random));然后后續就直接發送http請求。
如果看到是要求密鑰協商,則查看證書是否有問題(比如格式、有效期、簽名者是否是受信任CA),沒問題則取出服務器選中的加密套件;如果是RSA類,再生成一個隨機數使用公鑰加密(即PreMaster)發往服務器,客戶端則按選好的套件加件計算出對稱密鑰。如果是DH類,則客戶端生成一對DH密鑰,將公鑰(明文)直接發往服務器,客戶端使用證書中的公鑰和自己DH的私鑰計算出對稱密鑰。
第四步,服務端接收到客戶端響應。
如果是Change Cipher,那么就切換至加密模式,等侯客戶端請求。
如果是密鑰協商,且原先選的是RSA,則使用私鑰解密PreMaster獲取原隨機數,然后按選好的加密套件加三個隨機數生成對稱密鑰。如果原先選的是DH,則取出公鑰結合自己的私鑰計算出對稱密鑰。
三、密鑰交換過程數據流
3.1 使用DH協商密鑰
3.2 使用RSA協商密鑰
3.3 使用已有密鑰
四、密鑰交換過程的幾點說明
4.1 TCP/SSL/HTTPS相互之間是什么關系
我們追路tcp流來看一下ssl的通信過程,如下圖所示:先是經過了三次握手建立tcp連接,然后再進行ssl的密鑰協商過程,然后傳輸應用層內容,最后仍是tcp四次揮手。
所以總的關系就是:原先是“tcp+http”現在是“tcp+ssl+http”;https不是一個純粹的協議,而是“ssl+http”;只要你願意你可以在任意“tcp+xxx”中間插入ssl形成xxxs,如ftps。
4.2 SSL中的Session ID怎么理解
我剛開始聽Session ID沒什么感覺,然后分析使用已有密鑰Client Hello時還和領導反饋說,為什么這個新建的tcp連接中的Session ID和前面的Session ID一樣,然后領導又經常性地一語驚醒夢中人:當然一樣Session ID就是用來超越tcp連接的。
也就是說,前面說的使用已有密鑰模式,其中的Random、Session ID、Cipher Suite都是之前的tcp三次握手和四次揮手使用過的;從編碼角度看,如果原先已協商過密鑰,那可以保存Random、Session ID、Cipher Suite后續在Session ID有效期內建立SSL連接,只要進行使用已有密鑰過程即可,不需要進行密鑰協商過程;但一般來說,我們都不是自己實現SSL過程而都是直接調用SSL庫,所以這事也不歸一般的應用開發人員管。
4.3 RSA在密鑰協商中的作用是什么
DH密鑰協商過程是比較好理解的,對方的公鑰的自己私鑰次方等於自己的公鑰的對方公鑰次方,這個值即是公鑰(當然是離散對數運行不是直接的數據運算);RSA怎么完成密鑰協商呢?
個人猜測,在密鑰交換中RSA僅僅用於第三個隨機數的公鑰加密私鑰解密,最終的對稱秘鑰和RSA沒關系,可能是SHA(Client Random+Server Random+New Random)這種形式生成的。
但如果是這樣的話,就不太明白為什么說RSA是唯一可於簽名和密鑰交換的算法,ECC有什么區別?
4.4 怎么探測服務端支持哪些SSL版本和加密套件
從原理上講,使用某個版本的SSL發送Client Hello,如果服務器不支持該版本則會使用其支持的版本回Server Hello;對於加密套件,則可能是客戶端聲稱其只支持某個加密套件,如果返回Server Hello則表明服務端支持該加密套件,如果返回Alert(Handshake Failure)則表明服務器不支持該加密套件。
如果要測服務端支不支持某個SSL版本或者某個加密套件,那么推薦使用openssl:
# -ssl3指定只使用ssl v3版本 # -cipher指定加密套,可使用openssl ciphers查看所有加密套件 # -ssl3和-cipher兩個選項不是強相關的,可只指定其中一個 # 另外要注意有些加密套件可能只持部分SSL版本,注意看清到底報什么錯 openssl s_client -ssl3 -cipher DH-RSA-DES-CBC3-SHA -host 192.168.220.128 -port 443
如果要探測服務端支持的所有SSL版本和所有加密套件,推薦使用nmap:
# -p是端口 nmap -p 443 --script ssl-enum-ciphers 192.168.220.128 # 可以用以下命令來查看幫助說明 # nmap -p 443 --script-help ssl-enum-ciphers
結果如下圖所示,各套件末尾的A/D這種表示該加密套件的加密強度級別,A級的加密強度最好
4.5 SSL和SSH有沒有關系
SSL是Netscape公司提出的,OpenSSL是OpenSSL管理管員會維護的一個SSL實現,其他括SSL協議庫、應用程序(openssl可執行程序)以及密碼算法庫(包括各類主流加密算法)三部分。
OpenSSH是OpenBSD維護的一個項目,最開始使用OpenSSL的密碼算法庫,由於“心臟出血(heartbleed)”漏洞,OpenSSH已從OpenSSL轉向自己開發的分支LibreSSL。
總而言之,SSH和SSL都是非對稱算法協商對稱密鑰最后使用對稱加密,過程很相似但他們的具體有差別;至於SSH為什么不直接使用SSL的設計,可能是SSH和SSL基本同時延生然后SSH的設計者覺得沒必要換吧。
一個SSH密鑰交換過程如下:
第一步,客戶端向服務端發送自己的客戶端信息(SSH版本+實現軟件+軟件版本,實現軟件和軟件版本並沒有多大意義服務端后續步驟不會因為客戶端的不同而不同);
第二步,服務端向客戶端發送自己的服務端信息(SSH版本+實現軟件+軟件版本,實現軟件和軟件版本並沒有多大意義客戶端后續步驟不會因為服務端的不同而不同);
第三步,客戶端向服務端發送自己支持的算法列表;
第四步,服務端向客戶端發送自己支持的算法列表(這設計與SSL相比就顯得多余?);
第五步,客戶端發送選擇的密鑰計算方法+自己的DH公鑰;
第六步,服務端回復確認使用的密鑰計算方法+自己的DH公鑰,並表示已准備好可切換至加密模式;
第七步,客戶端回復確認將進入加密模式;
第八步,后邊就是加密通信,包括用戶名密碼認證等步驟。