SSL:(Secure Socket Layer,安全套接字層),位于可靠的面向連接配接的網絡層協定和應用層協定之間的一種協定層。SSL通過互相認證、使用數字簽名確定完整性、使用加密確定私密性,以實作用戶端和伺服器之間的安全通訊。該協定由兩層組成:SSL記錄協定和SSL握手協定。
TLS:(Transport Layer Security,傳輸層安全協定),用于兩個應用程式之間提供保密性和資料完整性。該協定由兩層組成:TLS記錄協定和TLS握手協定。
TLS是在SSL的基礎上标準化的産物,目前SSL3.0與TLS1.0保持一緻的,二者是并列關系,隻是大家習慣稱呼SSL。注明的web服務nginx預設支援的就是TLS1.0、TLS1.1、TLS1.2協定。
說明了SSL和TLS的差別後,我們通過wireshark對TLS的每一個byte進行分析。先來一張握手圖:

對應的wireshake中的握手記錄
1. Client Hello
會話從client說“hello”開始, client提供以下資料:
- 協定版本
- 用戶端随機數(之後會在握手中使用到)
- 一個用來恢複的可選session id
- 密碼套件清單
- 壓縮方法清單
- 擴充清單
1.1 Record Header
16 03 01 02 00
16 - 表示ContentType訓示SSL通信處于握手(handshake)階段
03 01 - 表示TLS的版本是 TLS1.0
02 00 - 表示512位元組的握手消息
1.2 Handshake Header
每個握手消息都以類型和長度開始。
01 00 01 fc
01 - 表示握手消息的類型為 client hello
00 01 fc - 表示握手消息的長度
1.3 用戶端TLS版本
給出了協定版本“3,3”(即TLS 1.2)。不尋常的版本号(“3,3”表示TLS 1.2)是由于TLS 1.0是SSL 3.0協定的一個小修訂。是以,TLS 1.0用“3,1”表示,TLS 1.1用“3,2”表示,依此類推。
03 03
可見上圖
1.4 用戶端随機數
74 ac 35 84 e3 0b d2 a4 63 75 1e a9 94 d2 43 94
6b bf 67 ab f9 a6 8e c7 0b e6 cb ab f0 91 bc db
用戶端提供32位元組的随機資料。在本例中,我們将随機資料設定為可預測的字元串。TLS 1.2規範說,前4個位元組應該是目前時間.
在握手時,用戶端和伺服器都會提供随機數。這種随機性對每次握手都是獨一無二的,在身份驗證中騎着舉足輕重的作用。它可以防止重播攻擊,并确認初始資料交換的完整性。
1.5 會話ID
在第一次連接配接時,會話ID(Session ID)字段是空的,這表示用戶端并不希望恢複某個已存在的會話。在後續的連接配接中,這個字段可以保持會話的唯一辨別。伺服器可以借助會話ID在自己的緩存中找到對應的會話狀态。典型的會話ID包含32自己随機生成的資料,這些資料本身沒有什麼價值。
1.6 加密套件
用戶端提供一個有序的清單,其中列出了它将支援的密鑰交換、密鑰加密和消息身份驗證的加密方法。該清單是按優先級順序排列的。
1.7 壓縮方法
用戶端可以送出一個或多個支援壓縮的方法。預設的壓縮是null,代表沒有壓縮。這種壓縮将在加密之前應用(因為加密的資料通常是不可壓縮的)。壓縮具有削弱加密資料安全性的特征(參見CRIME)。是以,這個特性已經從未來的TLS協定中删除。
- 01 - 壓縮方法的長度
- 00 - 使用的哪種壓縮方法, 00代表未使用任何壓縮方式
1.8 Extensions長度
Extensions是由任意數量的擴充組成。這些擴充會攜帶額外資料。
* 00 58 - the extensions will take 0x58 (88) bytes of data
每個擴充都以兩個位元組開始,表示它是哪個擴充,然後是一個雙位元組内容長度字段,然後是擴充的内容。
1.9 Extension - Server Name
用戶端提供了它所聯系的伺服器的名稱,也稱為SNI(伺服器名稱訓示)。
如果沒有這個擴充,HTTPS伺服器将無法為單個IP位址(虛拟主機)上的多個主機名提供服務,因為它無法知道要發送哪個主機名的證書,直到經過TLS會話協商并發出HTTP請求之後才知道.
* 00 00 - 這個值表示擴充名為‘Server Name’
* 00 13 - Extension Length
* 00 11 - Server Name list length
* 00 - list entry is type 0x00 "DNS hostname"
* 00 0e - Server Name Length
* 65 78 61 ... 6e 65 74 - 表示伺服器名
1.10 Extension - Status Request
用戶端為伺服器提供在其響應中提供OCSP資訊的權限。OCSP可用于檢查證書是否已被撤銷。用戶端發送空擴充的這種形式是必要的,因為伺服器使用用戶端首先沒有提供的擴充進行應答是一個緻命錯誤。是以,用戶端發送一個空形式的擴充,而伺服器用填充了資料的擴充進行應答。
00 05 00 05 01 00 00 00 00
- 00 05 - 表示該extension為 "status request"
- 00 05 - 表示該擴充的長度
- 01 - 表示certificate status type: OCSP
- 00 00 - 表示Responder ID list length
- 00 00 - 表示Request Extensions Length
1.11 Extension - Supported Groups
用戶端表示支援4條曲線的橢圓曲線加密。這個擴充最初被命名為“橢圓曲線”,但現在被重命名為“受支援的組”,以便與其他加密類型通用。
- 00 0a - assigned value for extension "supported groups"
- 00 0a - 0xA (10) bytes of "supported groups" extension data follows
- 00 08 - 0x8 (8) bytes of data are in the curves list
- 00 1d - assigned value for the curve "x25519"
- 00 17 - assigned value for the curve "secp256r1"
- 00 18 - assigned value for the curve "secp384r1"
- 00 19 - assigned value for the curve "secp521r1"
1.12 Extension - EC Point Formats
在橢圓曲線(EC)加密期間,客戶機和伺服器将以壓縮或未壓縮的形式交換所選點上的資訊。這個擴充表明客戶機隻能解析來自伺服器的未壓縮資訊。在下一版本的TLS中,不存在協商點的能力(而是為每個曲線預先選擇了一個點),是以不會發送此擴充。
- 00 0b - assigned value for extension "EC points format"
- 00 02 - 0x2 (2) bytes of "EC points format" extension data follows
- 01 - 0x1 (1) bytes of data are in the supported formats list
- 00 - assigned value for uncompressed form
1.13 Extension - Signature Algorithms
随着TLS的發展,有必要支援更強大的簽名算法,如SHA-256,同時仍然支援使用MD5和SHA1的早期實作。此擴充訓示客戶機能夠了解哪些簽名算法,并可能影響伺服器發送給客戶機的證書的選擇。
- 00 0d - assigned value for extension "Signature Algorithms"
- 00 12 - 0x12 (18) bytes of "Signature Algorithms" extension data follows
- 00 10 - 0x10 (16) bytes of data are in the following list of algorithms
- 04 01 - assigned value for RSA/PKCS1/SHA256
- 04 03 - assigned value for ECDSA/SECP256r1/SHA256
- 05 01 - assigned value for RSA/PKCS1/SHA386
- 05 03 - assigned value for ECDSA/SECP384r1/SHA384
- 06 01 - assigned value for RSA/PKCS1/SHA512
- 06 03 - assigned value for ECDSA/SECP521r1/SHA512
- 02 01 - assigned value for RSA/PKCS1/SHA1
- 02 03 - assigned value for ECDSA/SHA1
1.14 Extension - Renegotiation Info
該擴充的存在防止了使用TLS重新協商執行的攻擊類型。重新協商連接配接的能力已經從該協定的下一個版本(TLS 1.3)中移除,是以将來不再需要這個擴充。
- ff 01 - assigned value for extension "Renegotiation Info"
- 00 01 - 0x1 (1) bytes of "Renegotiation Info" extension data follows
- 00 - 重新協商資料的長度為零,因為這是一個新連接配接
1.15 Extension - SCT
用戶端為伺服器提供傳回簽名證書時間戳的權限。用戶端發送空擴充的這種形式是必要的,因為伺服器使用用戶端首先沒有提供的擴充進行應答是一個緻命錯誤。是以,用戶端發送一個空形式的擴充,伺服器使用填充了資料的擴充進行響應,或者根據發送擴充的用戶端更改行為。
- 00 12 - assigned value for extension "signed certificate timestamp"
- 00 00 - 0x0 (0) bytes of "signed certificate timestamp" extension data follows
2. Server Hello
伺服器回以“你好”。伺服器提供以下資訊:
- 選擇的協定版本
- 伺服器随機資料(稍後在握手中使用)
- 會話id
- 標明的密碼套件
- 選擇的壓縮方法
- 擴充清單
2.1 Record Header
TLS會話被分解為“記錄”的發送和接收,“記錄”是具有類型、協定版本和長度的資料塊。
- 16 -類型是0x16(握手記錄)
- 03 03 -協定版本是“3,3”(TLS 1.2)
- 00 31 - 0x31(49)位元組的握手消息
2.2 Handshake Header
每個握手消息都以類型和長度開始。
- 02 -握手消息類型0x02(伺服器你好)
- 00 00 2d - 接下來是伺服器hello資料的0x2D(45)位元組
2.3 伺服器TLS版本
給出了協定版本“3,3”(TLS 1.2)。不尋常的版本号(“3,3”表示TLS 1.2)是由于TLS 1.0是SSL 3.0協定的一個小修訂。
03 03 - TLS Version = 1.2
2.4 伺服器随機數
伺服器提供32位元組的随機資料。在本例中,我們将随機資料設定為可預測的字元串。
2.5 會話ID
伺服器可以為這個會話提供一個ID,客戶機可以在以後的會話協商中提供這個ID,以便重用關鍵資料并跳過大多數TLS協商過程。為了使其工作,伺服器和用戶端都将來自前一個連接配接的密鑰資訊存儲在記憶體中。恢複連接配接可以節省大量的計算和網絡往返時間,是以隻要有可能就會執行連接配接。
- 00 - length of zero (沒有選擇任何會話ID)
2.6 伺服器選擇的加密方式
伺服器從客戶機提供的選項清單中選擇了密碼套件0xC02F (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)。
其中SHA256就是用戶端和服務端使用的HMAC算法
2.7 伺服器選擇的壓縮方式
伺服器從客戶機提供的選項清單中選擇了壓縮方法0x00(“Null”,它不執行壓縮)。
2.8 Extension長度
伺服器向用戶端傳回了一個擴充清單。由于禁止伺服器使用客戶機沒有發送其hello消息的擴充進行應答,是以伺服器知道客戶機将支援列出的所有擴充。
- 00 05 -擴充将占用0x5(5)位元組的資料
2.9 Extension - Renegotiation Info
該擴充的存在防止了使用TLS重新協商執行的攻擊類型。重新協商連接配接的能力已經從該協定的下一個版本(TLS 1.3)中移除,是以将來不再需要這個擴充。
- ff 01 -為擴充配置設定值“重新協商資訊”
- 00 01 - 0x1(1)位元組的“重協商資訊”
- 00 00 - 擴充資料如下重新協商資料的長度為零,因為這是一個新的連接配接
2.10 Extended Master Secret
無“Extended Master Secret”
master_secret = PRF(pre_master_secret, "主秘鑰", ClientHello.random + ServerHello.random)[0..47]
具有“Extended Master Secret”
master_secret = PRF(pre_master_secret,“擴充的主密鑰”,session_hash)[0..47];
session_hash = hash(handshake_message)
3. Server Certificate
伺服器提供一個包含以下内容的證書:
- 伺服器的主機名
- 此伺服器使用的公鑰
- 來自可信第三方的證據,證明此主機名的所有者持有此公鑰的私鑰
這裡先介紹下證書認證的過程:
1). 伺服器發送給浏覽器端的證書隻有public key, 伺服器端儲存着private key。
2). client随機生成一串數,用server這裡的public key加密,發給server
3). server用private key解密後傳回給client
4). client與原文比較,如果一緻,則說明server擁有private key,也就說明與client通信的正是證書的擁有者,因為public key加密的資料,隻有private key才能解密
3.1 Record Heade
TLS會話被分解為“記錄”的發送和接收,“記錄”是具有類型、協定版本和長度的資料塊。
- 16 -類型是0x16(握手記錄)
- 03 03 -協定版本是“3,3”(TLS 1.2)
- 03 2f - 0x31(49)位元組的握手消息
3.2 Handshaker Heade
每個握手消息都以類型和長度開始。
- 02 -握手消息類型0x02(伺服器你好)
- 00 00 2d - 接下來是伺服器hello資料的0x2D(45)位元組
3.3 Certificate Length
證書消息以随後的所有證書資料的長度開始。
* 00 03 28 - 0x328 (808) bytes of certificate list follows
3.4 Certificate
證書采用ASN.1 DER二進制編碼。這種編碼由以下序列中的記錄組成:類型标記、長度、資料。
type标簽包含以下資訊:
type class (2 bits):通用的、應用程式的、特定于上下文的或私有的
constructed (1 bit):如果記錄由更小的記錄組成,則設定
type (5 bits):如果類型類是通用類型,那麼類型表示整數、ASCII字元串、對象ID等。
https://tls.ulfheim.net/certificate.html
4. Server Key Exchange
伺服器提供了密鑰交換資訊。作為密鑰交換過程的一部分,用戶端需要擁有一組公鑰+私鑰,公鑰用于加密發送的資料, 私鑰用于解密伺服器發送過來的資料。并且将互相發送對方的公鑰。然後,将使用各方的私鑰和另一方的公鑰的組合生成共享加密密鑰。
雙方同意使用ECDHE密碼套件,這意味着密鑰對将基于選擇的橢圓曲線,diffie - hellman,密鑰對都是暫時的(為每個連接配接生成),而不是使用的公鑰/私鑰證書。
4.1 Record Header && HandShaker Header
略
4.2 Curve info
伺服器選擇橢圓曲線, 橢圓曲線上的所有點。
- 03 - assigned value for "named_curve": 曲線類型
- 00 1d - curve 0x001d ("curve x25519")
4.3 Public Key
伺服器端提供的公鑰來自于之前的步驟 "Server Key Exchange Generation".
- 20 - length of 0x20 (32) bytes
- 9f d7 ... b6 15 - public key
4.4 Signature
因為伺服器正在生成臨時密鑰,是以它沒有使用伺服器證書中提供的公鑰。為了證明伺服器擁有伺服器證書(在TLS會話中提供證書有效性),它使用證書的私鑰簽署臨時公鑰。可以使用證書的公鑰驗證此簽名。
- 04 01 - reserved value for RSA signature with SHA256 hash
- 01 00 - length of signature (0x100 or 256 bytes)
- 04 02 b6 ... ac 41 fb - the computed signature for SHA256(client_hello_random + server_hello_random + curve_info + public_key)
我們可以自己計算簽名使用伺服器的私鑰.