一、SSL概述
SSL連線分為兩個階段:握手和資料傳輸階段。握手階段對伺服器進行認證並確立用於保護資料傳輸的加密金鑰,必須在傳輸任何應用資料之前完成握手。一旦握手完成,資料就被分成一系列經過保護的記錄進行傳輸。
1.1.握手
SSL握手有三個目的:
客戶端與伺服器需要就一組用於保護資料的演算法達成一致;
他們需要確立一組由那些演算法所使用的加密金鑰;
握手可以選擇對客戶端進行認證。
整個工作過程如下圖:
(1)客戶端將它支援的演算法列表+用於金鑰產生過程的隨機數傳送給伺服器;
(2)伺服器從列表中的內容選擇一種加密演算法,並將其連同一份包含伺服器公用金鑰的證書發回給客戶端;(證書包含了用於認證目的的伺服器標識,同時,伺服器還提供了一個作為金鑰產生過程部分輸入的隨機數)
(3)客戶端對伺服器的證書進行驗證,並取出伺服器的公用金鑰(用於之後加密發給伺服器的資訊);然後產生一個稱為pre_master_secret的隨機密碼串,並使用伺服器的公用金鑰對其進行加密。最後,客戶端將加密後的資訊傳送給伺服器;
(4)客戶端與伺服器根據pre_master_secret以及客戶端與伺服器的隨機數獨立計算出加密和MAC金鑰;
(5)客戶端將所有握手資訊的MAC值傳送給伺服器;
(6)伺服器將所有握手資訊的MAC值傳送給客戶端。
通過上述過程,就已經達到了SSL握手三個目的中的前兩個目的了。其中,第一步和第二步實現了第一個目標(確立一種加密演算法);第二步和第三步實現了第二個目標,在第2步中,服務端向客戶端提供伺服器公用金鑰的證書,這樣就允許客戶端給伺服器傳送密碼。經過第三步後,兩端都知道了pre_master_secret(客戶端知道是因為這是它產生的,服務端知道是因為它利用私密金鑰解密得到的)。第四步,兩端採用相同的金鑰匯出函式(KDF)來產生master_secret,最後再次通過KDF使用master_secret來產生加密金鑰。最後兩步是防止握手本身遭到篡改。
對應著上一張圖和這一張圖,握手過程是通過一條或者多條訊息實現的。
第 1 步對應一條單一的握手訊息, ClientHello。
第 2 步對應一系列 SSL 握手訊息,伺服器傳送的第一條件訊息為 ServerHello,其中包含了它所選擇的演算法,接著再在 Certificate 訊息中傳送其證書。最後,伺服器傳送ServerHelloDone 訊息以表示這一握手階段的完成。需要 ServerHelloDone 的原因是一些更為複雜的握手變種還要在 Certificate 之後傳送其他一些訊息。 當客戶端接收到 ServerHelloDone訊息時,它就知道不會再有其他類似的訊息過來了,於是就可以繼續它這一方的握手。
第 3 步對應 ClientKeyExchange 訊息。
第 5 與第 6 步對應 Finished 訊息。 該訊息是第一條使用剛剛磋商過的演算法加以保護的訊息。為了防止握手過程遭到篡改,該訊息的內容是前一階段所有握手訊息的 MAC 值。然而,由於 Finished 訊息是以磋商好的演算法加以保護的,所以也要與新磋商的 MAC 金鑰一起計算訊息本身的 MAC 值。
二、SSL記錄協議
在SSL中,實際的資料傳輸是使用SSL記錄協議來實現的。SSL記錄協議時通過將資料流分割成一系列的片段並加以傳輸來工作的,其中對每個片段單獨進行保護和傳輸。在接收方對每條記錄單獨進行解密和驗證。
在傳輸片段之前,通過計算資料的MAC來提供完整性保護。MAC與片段一起傳輸,並由接收實現加以驗證。將MAC附加到片段的尾部,並對資料與MAC整合在一起的內容進行加密,以形成經過加密的負載。最後給負載裝上頭部資訊。頭資訊與經過加密的負載的聯結稱為記錄(Record),記錄就是實際傳輸的內容。
2.1.記錄頭資訊
記錄頭資訊的工作就是為接收實現提供對記錄進行解釋所需的資訊。在實際應用中是指三種資訊:內容型別、長度和SSL版本。
長度欄位:可讓接收方知道它要從線路上讀取多少直接才能對訊息進行處理;
版本號:確保每一方使用所磋商的版本的冗餘性檢查;
內容型別:標識訊息型別。
2.2.內容型別
SSL支援四種內容型別:application_data、alert、handshake和change_cipher_spec。
application_data:使用SSL軟體傳送和接收的所有資料都是以application_data型別來傳送的;
alert:主要用於報告各種型別的錯誤;
handshake:承載握手訊息;
change_cipher_spec:標識記錄加密以及認證的改變,一旦握手商定了一組新的金鑰,就傳送change_cipher_spec來指示此刻將啟用新的金鑰。
2.3.SSL規範語言
TLS和SSLv3都是使用同一種規範語言來描述他們各自的訊息的。規範使用五種基本型別:opaque、uint8、uint16、uint24和uint32,分別對應無符號的8-、16-、24-和32-位整數,並線上路上以1、2、3或4位元組序列加以表示。所有的數字都以“網路位元組順序”——高位在前來表示。
2.3.1.向量vector
向量是給定元素型別的元素序列,分為定長和變長向量。其中,定長向量用[]表示,變長向量用<>表示。長度以位元組而不是元素個數為單位,所以uint16 foo[4]是表示是指兩個16位整數,而不是4個!(長度為4位元組,uint16位16位整數,即兩位元組整數,因此4個位元組包含兩個16位整數)。這樣就允許解碼器具有分層的結構,它可以將結構當做不透明的字串(因為它知道它們的長度)來看待,並將其傳送給另一層加以解析。
此外,可以通過長度的上限與下限、或只指定上限來表示變長向量。
// A string of between 1 and 20 bytes
opaque stuff<1..20>
// Up to 4 32 bit integers
uint32 numbers<16>
2.3.2.列舉型別
列舉型別就是假定只有一系列特定值的欄位,且每個值都有名字。
enum{red(1),blue(2),green(3)}colors;
指定一個名為colors 的型別,他們可以接收值red、blue和green,線上路上用整數1、2和3來表示。當線上路上對列舉變數進行編碼時,用一個大到足以容納其最大值的整數型別來表示,因此用一個位元組的uint8來表示colors。也可以通過顯式包含一個未命名的值來為一個列舉變數顯式指定最大尺寸:
enum{warning(1),fatal(2),(255)}AlertLevel;
2.3.3.結構
使用struct來構造結構化型別(與C語言類似):
struct{
type1 field1,
type2 field2,
type3 field3,
……
}name;
2.3.4.變體型別
可以將結構定義成依賴外部資訊而變化的變體(Variant)型別,使用一種表面上看起來類似於C語言中的switch語句的結構來進行定義(類似於C語言中的union):
select(type){
case value1:Type1
case value2:Type2
……
}name;
2.4.握手訊息結構
頭資訊為4位元組長,包括一個位元組的型別欄位和3個位元組的長度欄位組成,長度欄位表示剩餘握手訊息的長度(不包括型別與長度欄位),餘下的訊息內容完全有賴於msg_type欄位。
struct{
HandshakeType msg_type;
uint24 length;
select(HandshakeType){
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
}body;
}Handshake;
enum{
hello_request(0),client_hello(1),server_hello(2),
certificate(11),server_key_exchange(12),certificate_request(13),
server_hello_done(14),certificate_verify(15),client_key_exchange(16),
finished(20),(255)
}HandshakeType;
---------------------
作者:馮Jungle
來源:CSDN
原文:https://blog.csdn.net/sinat_21107433/article/details/88366880
版權宣告:本文為博主原創文章,轉載請附上博文連結!