SSL和TLS-SSL Handshake Protocol
SSL和TLS-SSL Handshake Protocol
- HelloRequest
- ClientHello
- ServerHello
- Certificate
- ServerKeyExchange
- CertificateRequest
- ServerHelloDone
- ClientKeyExchange
- CertificateVerify
- Finished
SSL握手協議位於SSL記錄協議之上。它允許客戶端和伺服器互相認證,協商cipher suites和壓縮方法。
上圖中的方括號裡的訊息是可選的,不總是被髮送。ChangeCipherSpec實際上不是SSL握手協議的訊息。SSL握手協議包含四組訊息-叫flights-在客戶端和伺服器之間交換。一個flight的所有訊息可以在一個TCP段內傳輸。也可能包含一個叫做HelloRequest的第五個flight(type值是0x00),它可能從伺服器傳送給客戶端,初始化一個SSL握手。很少使用這個訊息。訊息必須以這樣的順序傳送,否則返回致命錯誤。
- ClientHello:從客戶端發給伺服器(type值是0x01)
- 第二個flight包含2-5個訊息,從伺服器發給客戶端
- ServerHello:響應ClientHello訊息(type值是0x02)
- Certificate:如果伺服器需要證明自己,就傳送(type值是0x0B)
- ServerKeyExchange:某些情況下,需要傳送(type值是0x0C)
- CertificateRequest:如果伺服器需要客戶端使用公鑰證書證明自己(type值是0x0D)
- ServerHelloDone:最後傳送(type值是0x0E)
交換完ClientHello和ServerHello,客戶端和伺服器協商好協議版本、session ID、cipher suite和壓縮方法。此外,已經生成了ClientHello.random和ServerHello.random。
- 第三個flight包含2-5個訊息,從客戶端發給伺服器
- Certificate:如果伺服器傳送了CertificateRequest,客戶端傳送(type值是0x0B)
- ClientKeyExchange:這是協議的主要步驟。此訊息的內容取決於key交換演算法(type值是0x10)
- CertificateVerify:如果客戶端傳送了Certificate訊息,就必須傳送CertificateVerify。此訊息使用與客戶端證書的公鑰對應的私鑰進行數字簽名。(type值是0x0F)
- ChangeCipherSpec:使用SSL change cipher spec協議傳送該訊息。它的pending write狀態變成current write狀態
- Finished:這是第一個使用cipher spec加密保護的訊息(type值是0x14)
- 最後一個flight包含2個訊息,從伺服器發給客戶端
- ChangeCipherSpec:
- Finished:
這樣,握手完成了。客戶端和伺服器開始使用SSL application data protocol交換應用層資料。
大多數SSL session從握手開始,交換一次應用資料,等一會就結束了。如果需要交換更多資料(同一個客戶端和伺服器之間),有兩種可能行:或者是一個全的握手協商一個新的session,或者是一個簡單的握手繼續一箇舊的(先前建立的)session。
SSL協議允許客戶端在任何時間簡單地傳送一個ClientHello訊息,請求session重新協商。如果伺服器想重新協商,就傳送HelloRequest訊息。
比如,一個web伺服器的大部分文件都可以匿名請求,但是有一部分資源需要基於證書的客戶端認證,伺服器就可以重新協商一個連線。
如果順序號太大,也可以重新協商。
客戶端傳送一個帶有session ID的ClientHello訊息,伺服器就在它的session快取裡查詢,如果找到了,伺服器就重新建立連線,返回包含該session ID的ServerHello。如果找不到,就需要完整的握手。
SSL握手的每一個訊息,使用一個位元組的type屬性開始,3個位元組的length屬性說明訊息的長度。多個握手訊息可以放在一個SSL記錄裡。SSL記錄的前五個位元組是頭。頭的第一個位元組是22,表示握手協議,下來的兩個位元組是版本,最後兩個位元組是整個SSL記錄的剩餘部分的長度。
HelloRequest
該訊息允許伺服器要求客戶端初始化新的SSL握手。一般不用。
ClientHello
SSL握手的時候,客戶端發給伺服器的第一個訊息。一般,它是SSL握手的開始。它開始於通用的5位元組的SSL記錄頭,type屬性是1,3位元組的length屬性。
它的訊息體是:
- length屬性後面是client_version,客戶端支援的SSL最高版本
- 接下來的32個位元組是random,客戶端生成的隨機數,由兩部分組成:
- 4位元組的日期+時間值,單位是秒。1970年以來的UTC時間
- 28個位元組的隨機數
- 然後是session ID的長度。如果值是0,表示沒有可繼續的舊session,或者客戶端想生成新的安全引數,伺服器選擇恰當的session ID。否則,如果session ID長不為0,後面就是ID
- 如果session ID長度大於0,就有session_id屬性。session ID的最大長度是32個位元組。注意,此時還不能加密,所以不要在session ID裡存放任何資訊
- 下來的2個位元組是客戶端支援的cipher suites數量。
- 客戶端支援的每個cipher suites使用2個位元組表示。SSL裡,第一個位元組總是0
- 下來的2個位元組是客戶端支援的壓縮方法的數量
- 接下來是壓縮方法,每個方法有一個唯一的編碼。SSL 3.0只定義了null壓縮,它的長度是1,接下來的位元組是0
為了向前相容,compression_methods後面可以跟隨其他屬性。這些資料必須包含在握手hash裡,否則被忽略。
ServerHello
收到ClientHello訊息,伺服器開始處理和驗證,返回ServerHello。
ServerHello的結構和ClientHello類似,伺服器只返回一個cipher suite和一個壓縮方法。伺服器只能從客戶端的選項中選一個,放到session裡使用。
Certificate
大多數key交換方法都不是匿名的,這意味著伺服器必須使用公鑰證書向客戶端認證自己(除了DH anon)。因此,伺服器向客戶端傳送完ServerHello訊息,馬上傳送Certificate訊息(在同一個flight內)。同樣,在SSL握手的時候,當伺服器傳送CertificateRequest訊息,客戶端就要回復Certificate訊息。不論如何,Certificate訊息傳送公鑰證書,或者是公鑰證書鏈(certificate_list)。公鑰證書鏈以傳送者的證書開始,然後是一系列的CA證書,向上一直到根CA證書。證書型別必須適合使用的key交換演算法。一般是X.509證書。
Certificate訊息以SSL記錄頭開始,然後是type屬性,3位元組的length屬性和實際的證書鏈。
每個證書也以3位元組的length開始。Certificate訊息可能很長。
ServerKeyExchange
如果使用RSA key交換,客戶端可以從伺服器證書裡檢索公鑰,以及使用這個公鑰加密pre master secret。類似地,如果使用fixed Diffie-Hellman key交換,客戶端可以從伺服器證書裡檢索Diffie-Hellman引數。採用這些引數執行Diffie-Hellman key交換,把結果當作pre master secret。
這兩種情況下,伺服器的Certificate訊息足夠(不需要附加資訊)客戶端安全地把re master secret發給伺服器。特別是,不需要ServerKeyExchange訊息。
其他時候,客戶端需要附加資訊,必須由伺服器傳送ServerKeyExchange。
key交換演算法不同,ServerKeyExchange訊息格式也不一樣。
- 如果使用ephemeral或者anonymous Diffie-Hellman,ServerKeyExchange訊息的剩餘部分是素數模p,生成器g和公共指數Ys。這些引數的都是變長的
- 如果使用RSA,伺服器有RSA key的簽名,客戶端不能使用伺服器的公鑰傳送加密的pre master secret。伺服器必須增加一個臨時的RSA公鑰對,使用ServerKeyExchange訊息把公鑰發給客戶端。訊息包含兩個引數:模和指數。這些引數必須經過數字簽名。引數也是變長的
- 如果使用FORTEZZA,ServerKeyExchange訊息只包含FORTEZZA KEA需要的伺服器的rs,長度是128位元組。不需要數字簽名
前兩種情況,ServerKeyExchange可以包含簽名部分。如果伺服器認證不是SSL session的一部分,就不需要簽名部分,ServerKeyExchange訊息以Diffie-Hellman引數或者RSA引數結束。如果伺服器不是匿名的,已經發送了Certificate訊息,簽名的引數格式依賴伺服器證書裡的簽名演算法(RSA或者DSA)
- 如果伺服器證書使用RSA簽名,簽名的引數由兩個hash值連線而成:一個MD5 hash值和一個SHA-1 hash值
- 如果使用DSA簽名,簽名的引數只有SHA-1 hash值
hash函式的輸入是ClientHello.random、ServerHello.random和上面提到的伺服器key引數。
CertificateRequest
非匿名的伺服器可以要求客戶端認證。這個訊息不只是要求客戶端傳送證書,還包括客戶端證書型別的資訊。
CertificateRequest訊息包含可接受的證書型別列表,還包含伺服器可接受的CA列表。
該訊息可能很長。
ServerHelloDone
訊息體為空。
ClientKeyExchange
客戶端傳送的訊息。提供了客戶端側加密材料,讓伺服器在後來的安全通訊中使用。訊息體和使用的key交換演算法相關。
- 如果使用RSA或者FORTEZZA,ClientKeyExchange訊息包含加密的48個位元組的pre_master_secret。前兩個位元組是客戶端支援的最新版本。伺服器應該檢查這個值和ClientHello裡的值
- 對於RSA,pre_master_secret使用伺服器的RSA公鑰或者ServerKeyExchange裡的臨時RSA key
- 對於FORTEZZA,使用KEA派生TEK,使用TEK加密pre_master_secret和其他加密引數。FORTEZZA key材料實際上由10個值組成
- 如果使用ephemeral或者anonymous Diffie-Hellman,訊息包含客戶端的公開的Diffie-Hellman引數Yc。如果是fixed Diffie-Hellman,客戶端的公開的Diffie-Hellman引數已經在Certificate訊息裡了,不需要ClientKeyExchange。
如果伺服器收到ClientKeyExchange訊息,它使用私鑰解密pre_master_secret,或者使用自己的Diffie-Hellman引數計算pre_master_secret。
CertificateVerify
如果客戶端提供的Certificate訊息裡有帶簽名的證書,它必須證明自己擁有相應的私鑰(證書不能證明客戶端的身份,因為證書可以被竊聽和重播)。客戶端傳送CertificateVerify訊息,該訊息包含的數字簽名由客戶端的私鑰生成。
- 如果客戶端的證書是RSA的,包含MD5 hash值和SHA-1 hash值
- 如果證書是DSA的,只有SHA-1 hash值
hash值是這樣計算的:
h(k || opad || h(handshake messages || k || ipad))
h是指MD5或者SHA-1,k是master secret。
Finished
Finished訊息總是在ChangeCipherSpec訊息之後馬上傳送。該訊息用來驗證key交換和認證過程勝利結束。它是使用新的協商演算法和key保護的第一個訊息。不需要確認,之後可以立刻傳送加密資料。
Finished訊息的訊息體是加密保護的,由type、length、16位元組的MD5 哈是值、20位元組的SHA-1 hash值,16或者20位元組的MAC。MD5和SHA-1 hash值依賴key和實際的MAC。這裡的MAC和SSL記錄裡計算的MAC不同,附加在訊息裡。
MD5和hash值這樣計算:
h(k || opad || h(handshake messages || sender || k || ipad))
其中,sender是傳送訊息的實體。如果是客戶端傳送的,值是0x434C4E54,否則是0x53525652。