細讀HTTPS -- SSL/TLS協議

細讀HTTPS – SSL/TLS協議

TLS的主規格說明書定義了四個核心子協議:握手協議(handshake protocol)、密鑰規格變更協議(change cipher spec protocol)、應用數據協議(application data protocol)和警報協議(alert protocol)。

握手協議

在使用中經常可以觀察到以下三種流程:

  • 對服務器進行身份驗證;
  • 恢復之前的會話採用的簡短握手;
  • 對客戶端和服務器都進行身份驗證的握手。

握手之對服務器進行身份驗證

每一個TLS連接都會以握手開始。如果客戶端此前並未與服務器建立會話,那麼雙方會執行一次完整的握手流程來協商TLS會話。握手過程中,客戶端和服務器將進行以下四個主要步驟:

  1. 交換各自支持的功能,對需要的連接參數達成一致。
  2. 驗證出示的證書,或使用其他方式進行身份驗證。
  3. 對將用於保護會話的共享主密鑰達成一致。
  4. 驗證握手消息並未被第三方團體修改。

具體流程如下圖:
wos1

  • ClientHello:客戶端開始新的握手,並將自身支持的功能提交給服務器。
    ch

    • Version:版本信息
    • Random:隨機數(random)字段包含32字節的數據,在握手時,客戶端和服務器都會提供隨機數。這種隨機性對每次握手都是獨一無二的,在身份驗證中起着舉足輕重的作用。它可以防止重放攻擊,並確認初始數據交換的完整性。
    • Session ID:在第一次連接時,會話ID(session ID)字段是空的,這表示客戶端並不希望恢復某個已存在的會話。在後續的連接中,這個字段可以保存會話的唯一標識。服務器可以藉助會話ID在自己的緩存中找到對應的會話狀態。典型的會話ID包含32字節隨機生成的數據,這些數據本身並沒有什麼價值。
    • Cipher Suites:密碼套件(cipher suite)塊是由客戶端支持的所有密碼套件組成的列表,該列表是按優先級順序排列的。
    • Compression:客戶端可以提交一個或多個支持壓縮的方法。默認的壓縮方法是null,代表沒有壓縮。
    • Extensions:擴展(extension)塊由任意數量的擴展組成。這些擴展會攜帶額外數據。
  • ServerHello
    ServerHello消息的意義是將服務器選擇的連接參數傳送回客戶端。這個消息的結構與ClientHello類似,只是每個字段只包含一個選項。服務器無需支持客戶端支持的最佳版本。如果服務器不支持與客戶端相同的版本,可以提供某個其他版本以期待客戶端能夠接受。
    是

  • Certificate
    典型的Certificate消息用於攜帶服務器X.509證書鏈。證書鏈是以ASN.1 DER編碼的一系列證書,一個接着一個組合而成。主證書必須第一個發送,中間證書按照正確的順序跟在主證書之後。根證書可以並且應該省略掉,因爲在這個場景中它沒有用處。
    服務器必須保證它發送的證書與選擇的算法套件一致。比方說,公鑰算法與套件中使用的必須匹配。除此以外,一些密鑰交換算法依賴嵌入證書的特定數據,而且要求證書必須以客戶端支持的算法簽名。所有這些都表明服務器需要配置多個證書(每個證書可能會配備不同的證書鏈)。
    Certificate消息是可選的,因爲並非所有套件都使用身份驗證,也並非所有身份驗證方法都需要證書。更進一步說,雖然消息默認使用X.509證書,但是也可以攜帶其他形式的標誌;一些套件就依賴PGP密鑰。

  • ServerKeyExchange
    ServerKeyExchange消息的目的是攜帶密鑰交換的額外數據。消息內容對於不同的協商算法套件都會存在差異。在某些場景中,服務器不需要發送任何內容,這意味着在這些場景中根本不會發送ServerKeyExchange消息。

  • ServerHelloDone
    ServerHelloDone消息表明服務器已經將所有預計的握手消息發送完畢。在此之後,服務器會等待客戶端發送消息。

  • ClientKeyExchange
    ClientKeyExchange消息攜帶客戶端爲密鑰交換提供的所有信息。這個消息受協商的密碼套件的影響,內容隨着不同協商密碼套件而不同。

  • ChangeCipherSpec
    ChangeCipherSpec消息表明發送端已取得用以生成連接參數的足夠信息,已生成加密密鑰,並且將切換到加密模式。客戶端和服務器在條件成熟時都會發送這個消息。

  • Finished
    Finished消息意味着握手已經完成。消息內容將加密,以便雙方可以安全地交換驗證整個握手完整性所需的數據。這個消息包含verify_data字段,它的值是握手過程中所有消息的散列值。

握手之客戶端身份驗證&服務器身份驗證

窩222
相比如對服務器的驗證,雙向驗證中多了CertificateRequest,CertificateVerify,Certificate.而Certificate與服務器驗證過程中的含義相同.所以主要來看下CertificateRequest,CertificateVerify的含義.

  • CertificateRequest
    服務器使用CertificateRequest消息請求對客戶端進行身份驗證,並將其接受的證書的公鑰和簽名算法傳送給客戶端。它也可以選擇發送一份自己接受的證書頒發機構列表,這些機構都用其可分辨名稱來表示:
    struct {
    ClientCertificateType certificate_types;
    SignatureAndHashAlgorithm supported_signature_algorithms;
    DistinguishedName certificate_authorities;
    } CertificateRequest;
    
  • CertificateVerify
    客戶端使用CertificateVerify消息證明自己擁有的私鑰與之前發送的客戶端證書中的公鑰相對應。消息中包含一條到這一步爲止的所有握手消息的簽名:
    struct {
    Signature handshake_messages_signature;
    } CertificateVerify;
    

握手之會話恢復

恢復早先會話的步驟如下:

  • 客戶端將適當的會話ID放入ClientHello消息,然後提交。
  • 服務器如果願意恢復會話,就將相同的會話ID放入ServerHello消息返回
  • 服務器接着使用之前協商的主密鑰生成一套新的密鑰,再切換到加密模式,發送Finished消息。
  • 客戶端收到會話已恢復的消息以後,也進行相同的操作。
    jianduan

密鑰交換

在TLS中,會話安全性取決於稱爲主密鑰(master secret)的48字節共享密鑰。密鑰交換的目的是計算另一個值,即預主密鑰(premaster secret)。這個值是組成主密鑰的來源。
實際使用的密鑰交換算法主要有以下4種:RSA,DHE_RSA,ECDHE_RSA和ECDHE_ECDSA.

RSA 密鑰交換

RSA密鑰交換的過程十分直截了當。客戶端生成預主密鑰(46字節隨機數),使用服務器公鑰對其加密,將其包含在ClientKeyExchange消息中,最後發送出去。服務器只需要解密這條消息就能取出預主密鑰。主密鑰如何生成後續會有介紹。

Diffie-Hellman 密鑰交換

Diffie-Hellman(DH)密鑰交換是一種密鑰協定的協議,它使兩個團體在不安全的信道上生成共享密鑰成爲可能。
DH的訣竅是使用了一種正向計算簡單逆向計算困難的數學函數,即使交換中某些因子已被知曉,情況也是一樣。
最恰當的類比示例是混色:如果有兩種顏色,那麼很容易將其混在一起得到第三種顏色;但是如果只有第三種顏色的話,就很難確定究竟它是由哪兩種顏色混合而成的。
DH密鑰交換需要6個參數:其中兩個(dh_p和dh_g)稱爲域參數,由服務器選取。協商過程中,客戶端和服務器各自生成另外兩個參數,相互發送其中一個參數(dh_Ys和dh_Yc)到對端,再經過計算,最終得到共享密鑰。
臨時Diffie-Hellman(ephemeral Diffie-Hellman,DHE)密鑰交換中沒有任何參數被重複使用。與之相對,在一些DH密鑰交換方式中,某些參數是靜態的,並被嵌入到服務器和客戶端的證書中。這樣的話,密鑰交換的結果是一直不變的共享密鑰,就無法具備前向保密的能力。

橢圓曲線Diffie-Hellman 密鑰交換

橢圓曲線Diffie-Hellman(elliptic curve Diffie-Hellman,ECDH)密鑰交換原理與DH相似,但它的核心使用了不同的數學基礎。正如名稱所示,ECDHE基於橢圓曲線(elliptic curve,EC)加密。ECDH密鑰交換髮生在一條由服務器定義的特定的橢圓曲線上。這條曲線代替了DH中域參數的角色。

身份驗證

在TLS中,爲了避免重複執行密碼操作造成巨大開銷,身份驗證與密鑰交換緊緊捆綁在一起。大多數場景中,身份驗證的基礎是證書支持的公鑰密碼(最常見的是RSA,有時也用ECDSA)。一旦證書驗證通過,客戶端就知道了使用的公鑰。在此之後,客戶端將公鑰交給指定的密鑰交換算法,並由它負責以某種方式使用公鑰驗證另一端。
身份驗證原理很清楚:只有擁有對應私鑰的服務器才能取得預主密鑰,構造正確的會話密鑰,並生成正確的Finished消息。

  • 在RSA密鑰交換的過程中,客戶端生成一個隨機值作爲預主密鑰,並以服務器公鑰加密後發送出去。擁有對應私鑰的服務器解碼消息得到預主密鑰。
  • 在DHE和ECDHE的交換過程中,服務器爲密鑰交換提供自己的參數,並使用自己的私鑰簽名。客戶端持有對應的公鑰(從已驗證的證書中獲得),可以驗證參數是否真正出自期望的服務器。

加密

TLS可以使用各種方法加密數據,比如使用3DES、AES、ARIA、CAMELLIA、RC4或者SEED等算法。目前使用最爲廣泛的加密算法是AES。TLS支持三種加密類型:序列密碼、分組密碼和已驗證的加密。

序列加密

  • 計算MAC值,範圍包含記錄序列號、標頭、明文。MAC包含標頭能確保未進行加密的標頭不會遭受篡改。MAC包括序列號,能確保消息不被重放
  • 加密明文和MAC,生成密文。
    xulie

分組加密

  • 計算序列號、標頭和明文的MAC。
  • 構造填充,確認加密前的數據長度是分組大小(通常16字節)的整數倍。
  • 生成一個長度與分組大小一致的不可預期的初始向量(initialization vector,IV)。IV能保證加密是不確定的。
  • 使用CBC分組模式加密明文、MAC和填充。
  • 將IV和密文一起發送。
    Tips:上述專有名詞可查看前一篇博客:密碼學基礎
    fenzu

已驗證的加密

已驗證的密碼將加密和完整性驗證合二爲一,全名是使用關聯數據的已驗證加密(authenticated encryption with associated data,AEAD)。表面上,它看起來是序列密碼和分組密碼的交叉。它不用填充②,也不用初始向量,而是使用一個特殊的值,稱爲nonce(在加密通信中僅使用一次的密鑰)。這個值必須唯一。加密過程比使用分組密碼要簡單一些:

  • 生成一個唯一的64位nonce。
  • 使用已驗證加密算法加密明文;同時也將序列號和記錄標頭作爲完整性驗證依據的額外數據交給算法。
  • 將nonce和密文一起發送。
    yiyanzheng

應用數據協議

應用數據協議攜帶着應用消息,只以TLS的角度考慮的話,這些就是數據緩衝區。記錄層使用當前連接安全參數對這些消息進行打包、碎片整理和加密。

警報協議

警報的目的是以簡單的通知機制告知對端通信出現異常狀況。它通常會攜帶close_notify異常,在連接關閉時使用,報告錯誤。警報非常簡單,只有兩個字段:

	struct {
	AlertLevel level;
	AlertDescription description;
	} Alert;

AlertLevel字段表示警報的嚴重程度,可取值warning或者fatal。AlertDescription直接表示警報代碼。不論這種設計是好是壞,警報都沒有表達任意信息的能力,比如實際的錯誤提示。
嚴重程度爲fatal的消息會立即終止當前連接並使會話失效(相同會話的其他正在進行的連接會繼續,但會話絕不可能恢復了)。發送警告通知的一端不會主動終止連接,而是交由接收端通過發送它自己的嚴重警報對該警告自行作出反應。

協議中的密碼操作

僞隨機函數

在TLS中,僞隨機函數(pseudorandom function,PRF)用於生成任意數量的僞隨機數據。
PRF使用一條祕密、一顆種子和一個唯一標籤。

主密鑰

密鑰交換過程的輸出是預主密鑰。對這個值進行進一步加工,就是使用PRF生成48字節(384位)主密鑰:
master_secret = PRF(pre_master_secret, “master secret”,ClientHello.random + ServerHello.random)
因爲使用不同的密鑰交換方法,得到的預主密鑰長度可能不同,所以需要執行這個步驟。同時,因爲客戶端和服務器的隨機字段被用作種子,所以主密鑰實際上也是隨機的,且與協商握手綁定。

祕鑰生成

連接所需的密鑰材料是用單一的PRF調用基於主密鑰和客戶端、服務器的隨機數生成的:
key_block = PRF(master_secret, “key expansion”,server_random + client_random)
密鑰塊的長度根據協商的參數而有所不同。密鑰塊分爲六個密鑰:兩個MAC密鑰、兩個加密密鑰和兩個初始向量(只在必要時生成;序列密碼不會使用IV)。

TLS中的密碼套件

TLS爲實現所需的安全屬性提供了非常大的靈活性。它是一個創造實際密碼協議的框架。雖然以往版本將某些加密基元硬編碼到了協議中,但TLS 1.2是完全可配置的。密碼套件是一組選定的加密基元和其他參數,它可以精確定義如何實現安全。套件大致由以下這些屬性定義。

  • 身份驗證方法
  • 密鑰交換方法
  • 加密算法
  • 加密蜜鑰大小
  • 密碼模式(可應用時)
  • MAC算法(可應用時)
  • PRF(只有TLS 1.2一定使用,其他版本取決於各自協議)
  • 用於Finished消息的散列函數(TLS 1.2)
  • verify_data結構的長度(TLS 1.2)
    密碼套件都傾向於使用較長的描述性名稱,並且相當一致:它們都由密鑰交換方法、身份驗證方法、密碼定義以及可選的MAC或PRF算法組合而成,如圖所示:
    taojian
    taojian2

TLS擴展

TLS擴展是一種通用目的的擴展機制,使用這種機制可以在不修改協議本身的條件下爲TLS協議增加功能。
擴展以擴展塊的形式加在ClientHello和ServerHello消息的末尾:

	Extension extensions;

擴展塊由所需數量的擴展一個個堆疊而成。每一個擴展標頭是2字節擴展類型(唯一標誌),
後接擴展數據:

	struct {
	ExtensionType extension_type;
	opaque extension_data;
	} Extension;

擴展的格式和期望的行爲由每個擴展自己決定。在實踐中,擴展通常用於通知支持某些新功能(因此改變了協議),以及用於在握手階段傳遞所需的額外數據。自從擴展被引入TLS,它就成爲了TLS演進的主要載體。
changyong

TLS擴展:證書透明度

證書透明度(certificate transparency)還是一個提案,目的是通過保持所有公開的服務器證書來改進互聯網PKI。它的基本想法是CA將每一張證書都提交給一組公開的日誌服務器,反過來,這些CA將收到提交的證明,稱爲已簽名證書時間戳(signed certificate timestamp,SCT),並中繼給最終用戶。有一些選項用來傳送SCT,其中之一就是新的TLS擴展signed_certificate_timestamp。

TLS擴展:簽名算法

signature_algoritms擴展是在TLS 1.2中定義的。它使客戶端可以通告自己支持的各種簽名和散列算法。TLS規格說明書中列出了RSA、DSA和ECDSA簽名算法,以及MD5、SHA1、SHA224、SHA256、SHA384和SHA512這些散列算法。使用signature_algorithms擴展,客戶端可以提交其支持的簽名—散列算法對。

發佈了26 篇原創文章 · 獲贊 0 · 訪問量 2846
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章