儘管作過證書生成、雙向認證、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)),要求使用已有密鑰進行通訊。dom
若是不在,則返回Server Hello(Server Random+Cipher Suite+Certificate);其中,若是服務器選Cipher Suite使用RSA作密鑰交換那麼整個Server Hello以一個tcp包的形式返回,若是使用DH作密鑰交換那麼Certificate等都單獨用一個tcp包返回。ssh
第三步,客戶端接收到Server Hello。tcp
若是看到是要求使用已有密鑰進行通訊,則發送Change Cipher(Exist Key(Server Random));而後後續就直接發送http請求。學習
若是看到是要求密鑰協商,則查看證書是否有問題(好比格式、有效期、簽名者是不是受信任CA),沒問題則取出服務器選中的加密套件;若是是RSA類,再生成一個隨機數使用公鑰加密(即PreMaster)發往服務器,客戶端則按選好的套件加件計算出對稱密鑰。若是是DH類,則客戶端生成一對DH密鑰,將公鑰(明文)直接發往服務器,客戶端使用證書中的公鑰和本身DH的私鑰計算出對稱密鑰。ui
第四步,服務端接收到客戶端響應。編碼
若是是Change Cipher,那麼就切換至加密模式,等侯客戶端請求。加密
若是是密鑰協商,且原先選的是RSA,則使用私鑰解密PreMaster獲取原隨機數,而後按選好的加密套件加三個隨機數生成對稱密鑰。若是原先選的是DH,則取出公鑰結合本身的私鑰計算出對稱密鑰。
咱們追路tcp流來看一下ssl的通訊過程,以下圖所示:先是通過了三次握手創建tcp鏈接,而後再進行ssl的密鑰協商過程,而後傳輸應用層內容,最後還是tcp四次揮手。
因此總的關係就是:原先是「tcp+http」如今是「tcp+ssl+http」;https不是一個純粹的協議,而是「ssl+http」;只要你願意你能夠在任意「tcp+xxx」中間插入ssl造成xxxs,如ftps。
我剛開始聽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庫,因此這事也不歸通常的應用開發人員管。
DH密鑰協商過程是比較好理解的,對方的公鑰的本身私鑰次方等於本身的公鑰的對方公鑰次方,這個值便是公鑰(固然是離散對數運行不是直接的數據運算);RSA怎麼完成密鑰協商呢?
我的猜想,在密鑰交換中RSA僅僅用於第三個隨機數的公鑰加密私鑰解密,最終的對稱祕鑰和RSA不要緊,多是SHA(Client Random+Server Random+New Random)這種形式生成的。
但若是是這樣的話,就不太明白爲何說RSA是惟一可於簽名和密鑰交換的算法,ECC有什麼區別?
從原理上講,使用某個版本的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級的加密強度最好
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公鑰,並表示已準備好可切換至加密模式;
第七步,客戶端回覆確認將進入加密模式;
第八步,後邊就是加密通訊,包括用戶名密碼認證等步驟。