tls1.2 rfc5246

注:本文省略了部分開發協議才涉及到的內容,如字段類型的定義以及字段長度的運算,主要聚焦理解tls協議的運做方式,用於問題定位html

tls協議包含2層協議:TLS Record 協議和TLS Handshake協議,底層採用可靠傳輸協議(如TCP),TLS Record協議經過以下方式實現數據的安全傳輸:linux

鏈路是私有的,使用對稱加密方式對應用數據進行加密。對每條鏈路來講,對稱加密使用的key是各自獨立的(經過TLS Handshake協議協商獲得)。Record協議也能夠用於非加密場景;git

鏈路是可靠的。使用MAC來對消息完整性進行校驗,MAC使用哈希函數(如SHA-1)進行運算。Record 協議能夠不使用MAC,但一般僅限於使用Record做爲底層協議來傳輸協商使用的安全參數。算法

TLS Record 協議用於封裝多種上層協議,如Handshake協議,用於在傳輸/接收應用數據前進行相互認證,並協商出加密算法以及使用的密鑰。Handshake使用以下三種方式提供數據的安全傳輸:apache

對端身份能夠經過非對稱算法或公鑰,加密(如RSA,DSA)等進行認證。該認證是可選的,但一般要求至少經過一種認證方式對對端進行認證;segmentfault

協商的共享密鑰的過程是安全的:竊聽者沒法獲取協商的密鑰;緩存

協商是可靠的:攻擊者沒法在不被鏈路探測到的狀況下修改協商報文。安全

使用TLS的好處是它與應用層協議是相互獨立的,上層協議運行在TLS協議之上。TLS協議沒有指出如何添加協議來對鏈路進行安全加固。如何初始化TLS握手以及如何使用認證的證書,這些交由TLS之上的協議設計者來實現。網絡

5. HMAC and the Pseudorandom Functionsession

TLS使用MAC來保證消息的合法性。本協議使用的cipher suites使用了HMAC,它的實現基於hash函數,其餘cipher suites可能使用其餘形式的MAC。

除此以外,還須要一種在生成或校驗key時將密鑰擴展爲數據塊的方式。PRF(pseudorandom function)能夠經過輸入密鑰,種子和認證的標籤以後給出任意長度的輸出。PRF基於HMAC。本文檔全部cipher suites使用的的PRF均採用SHA-256的哈希函數。新的cipher suites必須明確規定PRF,並使用SHA-256或更健壯的hash函數。

cipher spec規定了如何使用PRF生成key material,塊加密算法(AES null等)以及MAC算法(HMAC-SHA1)。

使用PRF首先須要定義一個擴展密鑰的函數,P_hash(secret, data),該函數用於擴展密鑰長度

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
                     HMAC_hash(secret, A(2) + seed) +
                     HMAC_hash(secret, A(3) + seed) + ...

A()定義以下:

A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))

P_hash能夠迭代屢次來生成所須要的數據。如使用p_SHA256來生成80字節的數據,則須要迭代3次(32bytes*3=96bytes)來生成96字節的數據,保留前面80字節,後16字節的數據會被丟棄。

使用P_hash生成PRF的方式以下:

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

label是ASCII字符串,如字符串"slithy toves"使用時應該爲ASCII:

73 6C 69 74 68 79 20 74 6F 76 65 73

6. The TLS Record Protocol

TLS Record 協議是一個層級協議,每一層消息可能包括length,description和content字段。Record協議負責將須要傳輸的數據分佈到管理的block中,可能會對數據進行壓縮,在使用MAC和加密後傳輸結果。接收端接收到消息以後須要進行解密,校驗和解壓縮操做,而後傳遞到上層業務。當接收到未知的Record 類型後,必須發送unexpected_message alert。

本文檔定義了4種使用record協議的協議,handshake協議,alert 協議,change cipher spec協議以及application data協議。

6.1. Connection States

TLS Record協議使用TLS connection state做爲運行環境,connection state指定了壓縮算法,加密算法以及MAC算法,且擁有MAC key和bulk encryption keys相關的參數。Record協議始終保持4個connection state:current read,current write以及pending read和pending write。全部的records都在current read和current write state下處理。pending state能夠被TLS Handshake協議修改,而ChangeCipherSpec消息能夠選擇性地將pending state變爲current state,此時pending state初始化爲empty state。給未初始化的state配置參數並使之變爲current state的方式是非法的。初始的current state沒有使用加密,壓縮以及MAC。

connection states用於跟蹤加密狀態。write key用來發送數據,read key用來接收數據。pending state用來保存新的加密key(能夠由Handshake協議生成)以及初始向量,而current state則表示當前使用的key,當接受到ChangeCipherSpec消息時,會將pending state的key覆蓋current state的key,這樣就會使用更新的key進行數據的收發。當更多關於connection states的介紹能夠參考:What are read state and write state in SSL connections

 TLS Connection read 和write state的安全參數以下:

connection end:接入的實體是」client「仍是」server「

PRF算法:該算法經過master secret生成keys

bulk encryption 算法:用於塊加密

MAC 算法:用於消息認證

compression算法:用於數據壓縮

master secret:鏈路兩端共享48字節的密鑰

client random:client提供的32字節的隨機數

server random:server提供的32字節的隨機數

Record層使用安全參數來生成以下6項內容:

server write MAC key
client write encryption key
server write encryption key
client write IV
server write IV

使用PRF生成以下的key_block,key_block最終分割爲以上key

key_block = PRF(SecurityParameters.master_secret,"key expansion",SecurityParameters.server_random + SecurityParameters.client_random);

server在接收和處理record的時候使用client write參數,反之亦然。

一旦設定安全參數並生成key以後,就能夠經過將狀態變爲current state來實例化connection state。這些current state必須同時更新到每一個被處理的record層。每一個connection state包含以下元素:

compression state:current state的壓縮算法

cipher state:current state的加密算法,包含了該connection須要調度的key

MAC key:connection的MAC key

sequence number:每一個connection state都包含一個序列號,且分別由read和write state維護。當一個connection state變爲active state時必須置爲0。序列號會在每一個record中遞增。

6.2. Record Layer

6.2.1. Fragmentation

Record層將消息塊分割爲TLSPlaintext結構(長度<=2^14),相同ContentType的client消息可能合併到一個TLSPlaintext record中,一個client消息也可能分佈到多個record中。
enum {
  change_cipher_spec(20), alert(21), handshake(22),
  application_data(23), (255)
} ContentType;

struct {
  ContentType type;
  ProtocolVersion version;
  uint16 length;
  opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

type:上層協議的類型,用於處理封裝fragment

version:協議採用的版本,本文檔值爲{ 3, 3 }

length:TLSPlaintext.fragment的長度,不能大於2^14

fragment:應用數據。由上層協議處理的特定類型的數據塊

不能發送0長度的Handshake fragments,alert或ChangeCipherSpec數據。但能夠發送0長度的應用數據(可能用於鏈路探測)。在TLS Record協議中,應用數據處理的優先級很低,通常在上層協議(Handshake)處理完成後發送。

6.2.2. Record Compression and Decompression

全部的record都使用current state中定義的壓縮算法進行壓縮。初始的壓縮算法爲CompressionMethod.null(任什麼時候候都有一個激活的壓縮算法)。壓縮算法將TLSPlaintext結構轉換爲TLSCompressed結構。當connection state變爲激活態時,壓縮算法會使用默認的state信息進行初始化。壓縮算法不能形成數據丟失,且內容長度不能超過1024字節,當解壓縮函數解壓縮TLSCompressed.fragment時,若是數據大於2^14字節,必須返回解壓縮失敗的錯誤。

struct {
  ContentType type;       /* same as TLSPlaintext.type */
  ProtocolVersion version;/* same as TLSPlaintext.version */
  uint16 length;
  opaque fragment[TLSCompressed.length];
} TLSCompressed;

length:TLSCompressed.fragment的長度,不能大於2^14+1024字節

fragment:壓縮TLSPlaintext.fragment以後的數據類型,以下handshake protocol做爲Record協議的數據部分

解壓縮函數必須保證不能形成buffer溢出

實際使用中通常禁用壓縮

 6.2.3. Record Payload Protection

加密和MAC函數會將TLSCompressed結構轉化爲TLSCiphertext結構,解密函數則反轉上述過程。record的MAC包含序列號,所以可以探測到重複,多餘,缺失消息的場景。

TLSCiphertext中定義了流加密塊加密,以及AEAD加密方式。流加密和塊加密的簡單理解能夠參考對稱加密&加密模式

struct {
  ContentType type;
  ProtocolVersion version;
  uint16 length;
  select (SecurityParameters.cipher_type) {
      case stream: GenericStreamCipher;
      case block:  GenericBlockCipher;
      case aead:   GenericAEADCipher;
  } fragment;
} TLSCiphertext;

 type:和TLSCompressed.type相同

version:和TLSCompressed.version相同

length:TLSCiphertext.fragment的長度,不能超過2^14+1024

fragment:加密TLSCompressed.fragment後的類型(含MAC)

6.2.3.1. Null or Standard Stream Cipher

 Stream ciphers將TLSCompressed.fragment結構轉換爲TLSCiphertext.fragment的stream結構,以下: 

stream-ciphered struct {
  opaque content[TLSCompressed.length];
  opaque MAC[SecurityParameters.mac_length];
} GenericStreamCipher;

 MAC的生成方式以下:

MAC(MAC_write_key, seq_num +TLSCompressed.type +TLSCompressed.version +TLSCompressed.length +TLSCompressed.fragment);

seq_num:record的序列號

MAC:SecurityParameters.mac_algorithm指定的MAC算法

MAC必須在被加密前計算出來,stream cipher用於加密整個數據塊(含MAC)。若是cipher suite爲TLS_NULL_WITH_NULL_NULL,加密方式則由操做類型組成(如數據沒有被加密,MAC爲0--即NULL的定義)。對於null和stream ciphers來講,TLSCiphertext.length =  TLSCompressed.length + SecurityParameters.mac_length

6.2.3.2. CBC Block Cipher

block cipher(如3DES或AES)使用加密和MAC函數將TLSCompressed.fragment結構轉換爲TLSCiphertext.fragment的block結構,以下:

struct {
  opaque IV[SecurityParameters.record_iv_length];
  block-ciphered struct {
      opaque content[TLSCompressed.length];
      opaque MAC[SecurityParameters.mac_length];
      uint8 padding[GenericBlockCipher.padding_length];
      uint8 padding_length;
  };
} GenericBlockCipher;

MAC生成方式與stream cipher相同

IV:IV(Initialization Vector)爲隨機數且必須爲不可預測。

padding:將plantext擴展到完整的(多個)cipher block的長度,長度最大能夠爲255字節。padding機制能夠防止基於報文長度分析進行的攻擊。接收端必須檢驗該padding,並在校驗失敗時返回bad_alert_mac_alert錯誤。

padding_lenght:padding length必須使GenericBlockCipher 結構的長度和多個cipher block的長度相同。該長度不包括padding_length自己。

CBC(Cipher Block Chaining)模式下必須知道全部record的明文內容,不然可能遭受CBCTT攻擊。

6.2.3.3. AEAD Ciphers

AEAD cipher(如CCM或GCM)函數將TLSCompressed.fragment結構轉換爲TLSCiphertext.fragment的AEAD結構,以下:

struct {
 opaque nonce_explicit[SecurityParameters.record_iv_length];
 aead-ciphered struct {
     opaque content[TLSCompressed.length];
 };
} GenericAEADCipher;

AEAD使用key,nonce(隨機數),plaintest和"additional data"做爲輸入進行身份認證。key能夠是client_write_key或server_write_key,沒有用到MAC key。paintext爲TLSCompressed.fragment。額外的認證數據也被稱爲additional_data,定義以下:

additional_data = seq_num + TLSCompressed.type +TLSCompressed.version + TLSCompressed.length

aead_output輸出包括AEAD加密操做的密文,其長度一般大於TLSCompressed.length,但會隨着AEAD cipher變化。因爲ciphers可能會包含padding,數量可能會隨着TLSCompressed.length的不一樣而不一樣。每一個AEAD cipher的輸出不能大於1024字節。

AEADEncrypted = AEAD-Encrypt(write_key, nonce, plaintext,additional_data)

爲了加密和驗證,AEAD cipher會採用key,nonce和"additional_data"以及AEADEncrypted值。輸出爲明文或錯誤信息,沒有完整性校驗。若是解密失敗,則發出bad_record_mac alert

TLSCompressed.fragment = AEAD-Decrypt(write_key, nonce,AEADEncrypted,additional_data)

6.3. Key Calculation

Record協議使用算法結合handshake協議提供的安全參數來生成current state須要的keys。master secret被分割爲client write MAC key,server write MAC key,client write encryption key和server write encryption key,這4個key按照字節順序分割,未使用的值爲空。一些AEAD ciphers會使用到client write IV和server write IV。

當keys和MAC keys生成後,master secret做爲熵。此處使用PRF生成key

key_block = PRF(SecurityParameters.master_secret,
              "key expansion",
              SecurityParameters.server_random +
              SecurityParameters.client_random);

key_block劃分以下:

client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]

當前client_write_IV 和server_write_IV僅用於AEAD(3.2.1章節)

master secret算法以下:

master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) [0..47];

Record協議使用connection state來維護加密狀態,它使用handshake協議來獲取安全參數並生成相應的key,最後對數據進行加密傳輸。

7. The TLS Handshaking Protocols

TLS有3個子協議用於爲record層提供安全參數,進行相互認證,初始化協商以及報告錯誤。

handshake用來協商session,包含如下項目:

session identifier:server端選擇的隨機序列號,用於標記激活的或是重用的session

peer certificates:對端的X509v3證書。

compression method:加密前使用的壓縮算法

cipher spec:指定用於生成key的PRF,塊加密算法(null,AES等)和MAC算法(如HMAC-SHA1)。

master secret:client和server的48字節的共享密鑰

is resumable:用於標記該session是否能被重用

這些參數用來生成安全參數。能夠經過Handshake協議的重用特性,使用相同的session來初始化連接。

7.1. Change Cipher Spec Protocol

change cipher spec協議主要用來發送改變加密策略的信號。該協議僅包含一個消息(使用current connection state壓縮並加密)。消息內容包含一個字節的內容

struct {
  enum { change_cipher_spec(1), (255) } type;
} ChangeCipherSpec;

client或server經過發送ChangeCipherSpec消息來通知對端後續records將使用新協商的CipherSpec和keys加密保護。接收端接收到該消息後,會通知Record層將read pending state中的內容拷貝到read current state中。在發送完該消息以後,發送端必須將write pending state中的內容拷貝到write active state中。

協商好的安全參數會保存在write pending state中,當一端須要使用新的加密算法時,會發送ChangeCipherSpec消息,並當即將write pending state中的內容覆蓋到write current state中,接收端則修改read state的內容。

ChangeCipherSpec 在握手過程當中且在兩端都協商好安全參數後(Finished消息前)發送。

若是在數據傳輸過程當中出現了重握手,雙方仍然可使用舊的CipherSpec。可是當收到ChangeCipherSpec消息時,必須使用新的CipherSpec。發送ChangeCipherSpec的一段並不知道對端是否已經計算出了新的keys,所以在接收端可能須要一小段時間來緩存接收到的數據。

7.2. Alert Protocol

 alert表達了該消息的嚴重性(warning或fatal)並描述了該alert。fatal級別的alert會致使直接斷開鏈路,在這種狀況下,該session的其餘鏈路可能會繼續鏈接,但該session id會被標記爲不可用,用來防止重建連接。跟其餘消息同樣,alert也會被壓縮並加密。

struct {
  AlertLevel level;
  AlertDescription description;
} Alert;

7.2.1. Closure Alerts

client和server必須共享鏈路的終止狀態,用來防止截斷攻擊。任何一方均可以發出初始化發送closure消息,接收到closure消息以後的全部數據都會被忽略。

close_notify:

該消息用於提示接收者,發送者後續不會在該連接上發送任何消息。除非發生fatal錯誤,鏈路的兩端都應該在中止關閉鏈路前發送close_notify alert消息,並丟棄pending writes。

更多參見rfc2818

7.2.2. Error Alerts

 TLS Handshake協議處理錯誤的方式很簡單,當一方發現錯誤時,會將該消息發往對端。當發送或接收該消息時,兩端必須當即斷開連接,並刪除全部與連接相關的session信息(keys secrets等)。任何被fatal alert關閉的連接都不能重用。

當遇到沒法斷定的alert級別的錯誤,發送端可能會選擇將其做爲fatal級別的錯誤處理。若是實現中發送alert的目的是爲了關閉連接,則必須發送fatal級別的alert。

當接收到warning級別的alert,一般能夠繼續保持連接。做爲發送端,因爲一般沒法判斷接收端接收到warning級別的alert的動做,所以一般warning的alert做用不大。已經定義的alert參見Error Alert

7.3. Handshake Protocol Overview

TLS Handshake協商產生session state所須要的加密參數。當clent和server開始通訊時,會協商產生版本號,加密算法(可能會進行相互認證),以及使用公鑰生成共享密鑰。TLS Handshake包含以下步驟:

經過交換hello消息肯定加密算法,交換隨機數並檢查session 是否重用

交換加密參數,來容許肯定client和server使用的premaster secret

交換證書和加密信息來對client和server進行認證

使用premaster secret生成master secret並交換隨機數

給Record層提供安全參數

client和server校驗對端經過handshake計算出的安全參數

須要注意的是上層協議不能假設TLS能夠始終提供健壯的安全連接。實際上有不少中間人攻擊能夠致使兩端切換到它們所支持的最低級別的安全方法。TLS協議用來最小化攻擊,但實際中存在不少可能的攻擊方式,攻擊者可能block安全服務所運行的端口,或者使得兩端協商到非認證的連接。使用TLS的基本原則是上層協議必須知道所須要的安全需求,而且不能在低於安全需求的鏈路上傳輸信息。所以在使用知足需求的cipher suite前提下,能夠認爲鏈路是安全的。

這些經過Handshake協議來達成,基本過程以下:client發送ClientHello,server接收到後必須返回ServerHello(不然返回fatal的alert錯誤並斷開連接)。ClietHello和ServerHello用來組建鏈路安全能力。ClientHello和ServerHello用來創建以下屬性:Protocol Version,Session ID,Cipher Suite,以及Compression Method。除此以外,還須要生成並交換2個隨機數:ClientHello.Random和ServerHello.Random。

實際交換key須要用到4個消息:server  Certificate, ServerKeyExchange, client Certificate和ClientKeyExchange。能夠經過定義這些消息的格式以及消息的用途來實現交換key的方法,最終client和server協商出共享密鑰。該密鑰必須足夠長,當前的密鑰交換方式交換的密鑰長度在46字節以上。

hello消息完成以後,sever會在Certificate消息中發送其證書(當須要被認證時),除此以外,可能會發送ServerKeyExchange消息。當server端被認證後,server可能會要求對client進行認證,接下來server會發送ServerHelloDone消息來表示hello階段的握手結束,而後sever端會等待client端的響應。若是server發送了CertificateRequest消息,client必須發送其certificate消息。隨後會發送ClientKeyExchange消息,該消息的內容取決於ClientHello和ServerHello協商選定的公鑰算法。若是client發出了帶簽名能力的certificate,會發送數字簽名的CertificateVerify消息來驗證擁有certificate私鑰的一方。

在client和server進行相互認證以後,client會發送ChangeCipherSpec消息,此時client會將pending state中的Cipher Spec拷貝到Current state中,而後當即使用最新的算法,keys和secrets發送加密的Finished消息,同時,server端會響應它的ChangeCIpherSpec消息,並將pending轉變爲current,使用新的CipherSpec發送Finished消息。到此爲止,握手結束,後續client和server能夠交換應用數據。應用數據不能先於首次握手(非TLS_NULL_WITH_NULL_NULL的cipher suite)發送。

      Client                                               Server

      ClientHello                  -------->
                                                      ServerHello
                                                     Certificate*
                                               ServerKeyExchange*
                                              CertificateRequest*
                                   <--------      ServerHelloDone
      Certificate*
      ClientKeyExchange
      CertificateVerify*
      [ChangeCipherSpec]
      Finished                     -------->
                                               [ChangeCipherSpec]
                                   <--------             Finished
      Application Data             <------->     Application Data

* 表示不必定發送的消息

ChangeCipherSpec是獨立的TLS消息,不屬於Handshake消息的一部分

 當client和server決定重用先前的session會現有的session時,消息流程以下:

client發送ClientHello(帶須要重用的session ID)。server會校驗須要匹配該ID的session。若是匹配成功且server贊成使用指定的session重建連接,會發送帶該Session ID的ServerHello消息。此時client和server必須發送Change CIpher Spec消息並直接處理Finished消息。一旦重建成功,client和server就能夠開始交換應用層數據;若是匹配失敗,Sever會生成一個新的Session ID,並執行完整的握手過程。

      Client                                                Server

      ClientHello                   -------->
                                                       ServerHello
                                                [ChangeCipherSpec]
                                    <--------             Finished
      [ChangeCipherSpec]
      Finished                      -------->
      Application Data              <------->     Application Data

7.4. Handshake Protocol

TLS Handshake協議屬於TLS Record協議的上層協議。該協議用於協商session的安全屬性。Handshake消息在TLS record層之下運行,被封裝成一個或多個TLSPlaintext結構,並被當前session的state處理。

handshake協議消息的發送順序必須聽從以下規則:亂序的handshake消息會致使fatal錯誤;不須要的handshake消息能夠被忽略;惟一一個不須要受發送順序限制的消息是HelloRequest,但client端進行handshake過程當中接收到後應該忽略該消息。

7.4.1. Hello Messages

 hello階段用來創建安全加密的能力。當新建一個session的時候,record層connection state的加密,哈希和壓縮算法都初始化爲null。

7.4.1.1. Hello Request

server端能夠在任什麼時候候發送HelloReques消息。

該消息用來通知client端進行協商,client會發送ClientHello消息進行響應。該消息不能用於斷定哪一端開始創建連接(僅用於初始化協商)。若是client正在握手協商中或者client不一樣意創建連接,client會發送no_renegotiation alert。若是server發送HelloRequest並無受到任何響應,Server可能會關閉連接併發送fatal alert。

該消息不能使用Handshake中(Finished消息和certificate消息)使用的hash。

 7.4.1.2. Client Hello

client發送ClientHello消息來初始化握手協商,ClientHello也用於響應server發送的HelloRequest消息。

ClientHello包含一個隨機數的結構體。以下

 struct {
     uint32 gmt_unix_time;
     opaque random_bytes[28];
 } Random;

gmt_unix_time:是標準unix 32位格式的發送端的內部時鐘時間。在TLS協議中沒有規定該時鐘的精確度。

random_bytes:生成的28字節的安全隨機數。注:隨機數並非session ID

Client Hello消息包含一個可變長度的session id。若是該字段非空,該值表示了client須要重用的session,此時session id能夠來自於先前的連接(1),當前的連接(2)或其餘當前的連接(3)(其餘session的)。第2種用於當client僅須要更新隨機數的場景;第3中用於創建獨立的安全連接(而無需進行完整的握手過程)。當握手協商經過交換Finished後保存的sessionID超時,或遇到fatal錯誤時,sessionID會變爲無效狀態。Session ID的實際內容由server端定義。

因爲SessionID的傳輸沒有通過加密或MAC保護(由於此時加密參數還未協商出來),sever端不能在session id中放置敏感字段,不然可能致使安全攻擊。在握手結束後的消息(含Finished消息)中的session ID會被加密保護。

 ClientHello中的cipher suite列表給出了client支持的加密算法,並按照client偏好排序。每一個cipher suite包含一個交換算法key,塊加密算法,MAC算法和PRF。sever會選擇一個合適的cipher suite,若是沒有合適的則會發送handshake failure alert並關閉連接。若是cipher suite中包含server沒法識別的項,server端必須忽略這些cipher suites,並處理剩餘的cipher suites。

struct {
  ProtocolVersion client_version;
  Random random;
  SessionID session_id;
  CipherSuite cipher_suites<2..2^16-2>;
  CompressionMethod compression_methods<1..2^8-1>;
  select (extensions_present) {
      case false:
          struct {};
      case true:
          Extension extensions<0..2^16-1>;
  };
} ClientHello;

ClientHello經過判斷在compression_method以後是否有多餘的字節來肯定是否由存在擴展字段。

server_version:client建議的最低版本且server支持的最高版本,本協議使用值爲3.3。TLS1.2中若是sever不支持該版本,會返回帶有低版本的ServerHello,若是client贊成使用該低版本,則使用該版本進行協商,不然client返回protocol_version alert並關閉連接。若是server接收到的ClientHello攜帶了高於server支持的最高版本的版本,則必須返回server所支持的最高版;當server接收的ClientHello中的版本低於server所支持的最高版本,若是server贊成使用該低版本,則會選擇不高於ClientHello.client_version中定義的最高版本(如,server支持TLS1.0 1.1和1.2,client_version爲TLS 1.0,則server會使用TLS1.0處理),反之返回protocol_version alert。

random:client生成的隨機數。

session_id:非空表示重用session,空表示新建session

cipher_suites:若是session_id非空,該字段至少須要包含該session已經協商好的cipher_suite(session重用

compression_methods:client支持的壓縮方法,按照偏好排序。若是session id非空,該字段至少須要包含該session已經協商好的compression_method。全部的實現必須支持CompressionMethod.null。

extensions:client可能會經過擴展字段來請求server的擴展功能。

當client使用擴展請求額外的功能,但server不支持時,client可能會斷開握手。server端必須接收帶或不帶擴展字段的ClientHello,並解析這些擴展字段,若是發現沒法解析的字段,則必須返回decode_error alert。

client發送完ClientHello後會等待server端的ServerHello,非ServerHello(HelloRequest除外)的消息會被認爲fatal錯誤。

7.4.1.3. Server Hello

在server接收到ClientHello且可以接受其中列出的cipher suite時會發送ServerHello

struct {
  ProtocolVersion server_version;
  Random random;
  SessionID session_id;
  CipherSuite cipher_suite;
  CompressionMethod compression_method;
  select (extensions_present) {
      case false:
          struct {};
      case true:
          Extension extensions<0..2^16-1>;
  };
} ServerHello;

server_version:與client的定義一致

random:server端生成的隨機數,獨立於client的隨機數

session_id:server可能會發送空的session id,表示session不會被緩存且不會被重用。

其他字段與client一致

7.4.1.4. Hello Extensions

 擴展字段的格式以下:

struct {
  ExtensionType extension_type;
  opaque extension_data<0..2^16-1>;
} Extension;

enum {
  signature_algorithms(13), (65535)
} ExtensionType;

extension_type:表示特定的擴展類型

extension_data:表示特定的擴展的信息

IANA維護的擴展參見Section 12

只有在ClientHello中出現的擴展才能出如今ServerHello中。若是client接收到的ServerHello中出現了ClientHello中不相關的擴展,則client必須斷開連接併發送unsupported_extension fatal alert。將來可能會實現「server-oriented」的擴展,參見Hello Extensions

當ClientHello或ServerHello消息中存在多個擴展時,擴展的能夠以任意順序存在,但不能出現同一擴展類型的多個實例。

擴展能夠在初始化新的session或重用session時發送。在client請求重用session時,因爲它並不知道server端是否會支持不一樣的擴展,這種狀況下,client會發送以前發送過的擴展。

每一個擴展類型須要規定在完整的握手和session重用場景下的做用。目前大部分TLS 擴展的實現中僅關注session初始化:當重用先前session的時候,sever不會處理ClientHello中的擴展,也不會將他們保存在ServerHello中。

開發extension的注意點參見Hello Extensions

7.4.1.4.1. Signature Algorithms

client使用signature_algorithm擴展來告訴server端用於數字簽名時使用的signature/hash算法對。該擴展的"extension_data'字段包含"supported_signature_algorithms"值。

enum {
  none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
  sha512(6), (255)
} HashAlgorithm;

enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
SignatureAlgorithm;

struct {
    HashAlgorithm hash;
    SignatureAlgorithm signature;
} SignatureAndHashAlgorithm;

SignatureAndHashAlgorithm
supported_signature_algorithms<2..2^16-2>;

 每一個SignatureAndHashAlgorithm列表包含一個hash/signature對(不是全部的hash和signature都能配對),按照偏好排序。

hash:代表須要使用的哈希算法,如MD5,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512等。「none」表示爲之後擴展使用,也用於僅使用signature但不使用hash的場景。

signature:代表須要使用的簽名算法,如RSASSA-PKCS1-v1_5,DSA,ECDSA等,該字段必須出如今該擴展中。

因爲Cipher Suite中也定義了容許的簽名算法(但沒有定義哈希算法),所以在結合該擴展使用時會變得比較複雜,參見7.4.2和7.4.3章節

若是client僅支持默認的hash和signature算法,則可能忽略signature_algorithm擴展。若是client不支持默認算法,或支持其餘hash/signature算法,則必須發送signature_algorithm擴展並列出接受的算法。

若是client沒有發送signature_algorithm擴展,則server必須:

若是協商的密鑰交換算法爲RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA其中之一,則認爲client發送了{sha1,rsa}

若是協商的密鑰交換算法爲DHE_DSS, DH_DSS其中之一,則認爲client發送了{sha1,dsa}

若是協商的密鑰交換算法爲ECDH_ECDSA, ECDHE_ECDSA其中之一,則認爲client發送了{sha1,ecdsa}

TLS1.2以前的版本沒法識別該擴展。

server不能發送該擴展,但server必須支持接收該擴展

當重用session時,ServerHello中不能包含該擴展,且server忽略ClientHello中的該擴展。

7.4.2. Server Certificate

 當兩端須要使用基於證書的認證時,server端必須發送Certificate消息。該消息老是在ServerHello中發送。

Certificate消息會發送server的證書鏈。證書必須符合協商出來的密鑰交換算法和擴展。 

opaque ASN.1Cert<1..2^24-1>;

struct {
  ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;

certificate_list:證書鏈。發送者的證書必須排在第一個,後續的證書依此(直接)認證前面一個。由於證書認證要求root keys獨立發佈,自簽證書中指定的root CA可能會被忽略,所以遠端必須擁有自簽證書的root key來進行驗證。

 客戶端響應certificate request消息的消息類型和結構與server相同。當client沒有合適的證書時,可能不會發送證書。server端使用證書時須要知足以下要求:

證書必須是X509v3,除非明確協商使用其餘類型的證書

證書的公鑰必須可以兼容協商的密鑰交換算法

密鑰交換算法         證書key類型

RSA/RSA_PSK        RSA公鑰,證書必須可以用於加密(當出現key esage擴展時,keyEncipherment必須置位)

DHE_RSA/ECDHE_RSA    RSA公鑰,證書必須可以用於簽名(當出現key esage擴展時,digitalSignature必須置位)

DHE_DSS          DSA公鑰,證書必須可以用於簽名(結合server key exchange消息中出現的hash算法)

DH_DSS/DH_RSA       Diffie-Hellman公鑰(當出現key esage擴展時,keyAggrement必須置位)

ECDH_ECDSA        ECDH-capable公鑰,該公鑰必須使用client支持的curve和point格式

ECDHE_ECDSA       ECDSA-capable公鑰,證書必須容許key進行簽名且必須使用client支持的curve和point格式

「server_name」和「trusted_ca_keys」擴展用於指導證書選擇。

若是client提供了signature_algorithm擴展,那麼server提供的全部證書都必須使用該擴展中出現的hash/algorithm算法對進行簽名(數字簽名),這也意味着包含某種簽名算法密鑰的證書可能被不一樣的簽名算法進行簽名(如RSA key使用DSA key進行簽名)。這也是與TLS1.1不一樣的地方。

若是server擁有多個證書,client會根據上述原則(除此以外,還有如本地配置和偏好)挑選其中一個進行驗證;若是server只有一個證書,則必須知足全部規則。

7.4.3. Server Key Exchange Message

該消息會在server certificate以後發送,且僅在server Certificate消息不可以提供用於client交換premaster secret的數據時發送。下面密鑰交換算法會發送該消息

DHE_DSS DHE_RSA DH_ann

下面交換算法不能發送該消息

RSA DH_DSS DH_RSA

該消息用來給client提供後續傳輸premaster  secret的加密信息。client端使用Diffie-Hellman公鑰配合該消息承載的數據能夠完成premaster secret交換(或其餘算法功能)。

  enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa /* may be extended, e.g., for ECDH -- see [TLSECC] */ } KeyExchangeAlgorithm;

  struct {
      opaque dh_p<1..2^16-1>;
      opaque dh_g<1..2^16-1>;
      opaque dh_Ys<1..2^16-1>;
  } ServerDHParams;     /* Ephemeral DH parameters */

  dh_p
     The prime modulus used for the Diffie-Hellman operation.

  dh_g
     The generator used for the Diffie-Hellman operation.

  dh_Ys
     The server's Diffie-Hellman public value (g^X mod p).

  struct {
      select (KeyExchangeAlgorithm) {
          case dh_anon:
              ServerDHParams params;
          case dhe_dss:
          case dhe_rsa:
              ServerDHParams params;
              digitally-signed struct {
                  opaque client_random[32];
                  opaque server_random[32];
                  ServerDHParams params;
              } signed_params;
          case rsa:
          case dh_dss:
          case dh_rsa:
              struct {} ;
             /* message is omitted for rsa, dh_dss, and dh_rsa */
          /* may be extended, e.g., for ECDH -- see [TLSECC] */
      };
  } ServerKeyExchange;

params:serverkey exchange的參數,以下

signed_params:用於非匿名密鑰交換,對server交換的密鑰參數的簽名。能夠看到,簽名的內容包含client和server的隨機數以及交換算法的參數

若是client提供了signature_algorithm擴展,則該消息中必須使用client的signature_algorithm擴展中出現的hash/algorithm對(下面紅框中的hash/algorithm算法是client 支持的)。但在實際使用中會出現不一致的狀況,如client提供了DHE_DSS密鑰交換但在signature_algorithm擴展中卻忽略全部的DSA(即擴展中忽略了cipher suite中定義的簽名算法)。爲了可以正確地協商,server必須在選擇前校驗全部的cipher suites與signature_algorithms(即cipher suites中的簽名算法與擴展不一致時)。除此以外,hash/signature算法必須與server端證書中的key相匹配。RSA keys可能與任何hash算法兼容(簽名與哈希組合的方式受限於證書)。

 

 7.4.4. Certificate Request

 當非匿名server須要對client進行認證時會發送該消息,跟在ServerKeyExchange後面。

enum {
  rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
  rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
  fortezza_dms_RESERVED(20), (255)
} ClientCertificateType;

opaque DistinguishedName<1..2^16-1>;

struct {
  ClientCertificateType certificate_types<1..2^8-1>;
  SignatureAndHashAlgorithm
    supported_signature_algorithms<2^16-1>;
  DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;

certificate_type:client可能會提供的證書類型

rsa_sign:包含RSA key的證書

dss_sign:包含DSA key的證書

rsa_fixed_dh:包含static DH key的證書

dss_fixed_dh:包含static DH key的證書

supported_signature_algorithms:server支持的hash/signature算法,按偏好排序

certificate_authorities:可接受的CA的distinguished names(DN),DER編碼格式。這些DN字段可能會指定一個root CA或子CA指望的DN,所以該消息能夠用來描述已知的根以及指望的受權範圍。若是certificate_authorities列表爲空,則client可能會選擇發送合適的ClientCertificateType類型的證書。

certificate_types和supported_signature_algorithms字段交互比較複雜,certificate_types在SSLv3版本中出現,但仍然待肯定,它的大部分功能被supported_signature_algorithms取代。規則以下:

client提供的證書必須使用supported_signature_algorithms中定義的hash/signature算法進行簽名

client提供的證書必須包含於certificate_types兼容的key,若是key是一個簽名key,則該key必須能配合supported_signature_algorithms中的hash/signature算法使用。

因爲歷史緣由,一些client證書類型包含用於簽名這些證書的算法。如在早期的TLS版本中,rsa_fixed_dh表示使用RSA簽名的證書且該證書包含一個static DH key。在TLS 1.2中,該功能被(supported_signature_algorithms)廢棄,證書類型再也不限制用於簽名證書的算法。如,server發送的dss_fixed_dh類型的證書,以及{{sha1, dsa}, {sha1, rsa}}的簽名類型,client可能會回覆帶DH key的證書,使用RSA-SHA1簽名。

7.4.5. Server Hello Done

 server發送該消息用來表示完成了key exchange的消息的交互,client能夠進入密鑰交互階段。client在接收到ServerHelloDone消息後,會對server提供的證書進行校驗,若是證書校驗經過則繼續對server的hello參數進行校驗。

7.4.6. Client Certificate

 該消息是client接收到ServerHelloDone消息以後發送的第一個消息,且只在server請求證書時發送。若是沒有合適的證書,client也必須發送該消息,消息中不包含任何證書,即certificate_list長度爲0。若是client沒有發送任何證書,server可能會握手(不對client進行認證),也可能會返回handshake_faiure fatal alert。若是證書鏈的某些地方不可接受(如簽名的CA不可知),server可能會繼續握手或返回fatal alert。

該消息會傳遞client的證書鏈,server會使用該消息來校驗CertificateVertify消息或計算premaster secret(non-ephemeral Diffie- Hellman)。證書必須匹配協商的cipher suite的密鑰交換算法以及擴展。

證書類型必須是X509v3(除非明確指出使用其餘類型的證書)。

client證書必須於CertificateRequest中的證書類型匹配。

client證書類型            證書key類型

rsa_sign              RSA公鑰,證書必須可以用於簽名(結合certificates verify消息中的hashsignature算法)

dss_sign              DSA公鑰,證書必須可以用於簽名(結合certificates verify消息中的hashsignature算法)

ecdsa_sign             ECDSA-capable公鑰,證書必須可以用於簽名(結合certificates verify消息中的hashsignature算法);公鑰必須使用server支持的curve和point格式

rsa_fixed_dh/dss_fixed_dh      Diffie_Hellman公鑰,必須與server key的premaster相同

rsa_fixed_ecdh/ecdsa_fixed_ecdh   ECDH-capable公鑰,必須與server key的curve相同,必須使用server支持的point格式

若是certificates 請求中的certificate_authorities (DN)列表非空,則CA列表中的某個CA應該簽發了證書鏈中的某個證書。

證書必須使用可接受的hash/algorithm進行簽名(與7.4.4章節相同)。

7.4.7. Client Key Exchange Message

該消息在certificate以後發送,若是沒有發送certificate消息,則在ServerHelloDone以後發送。

發送該消息表示premaster secret已經生成(經過直接傳輸RSA加密的premaster secret或傳遞用於兩端生成相同premaster secret的Diffie_Hellman參數)

當client使用ephemeral Diffie-Hellman exponent進行密鑰交換時,該消息包含了client的Diffie-Hellman public值;若是client發送的certificate包含static DH exponent,則該消息必須發送,但必須爲空

 

struct {
  select (KeyExchangeAlgorithm) {
      case rsa:
          EncryptedPreMasterSecret;
      case dhe_dss:
      case dhe_rsa:
      case dh_dss:
      case dh_rsa:
      case dh_anon:
          ClientDiffieHellmanPublic;
  } exchange_keys;
} ClientKeyExchange;

7.4.7.1. RSA-Encrypted Premaster Secret Message

RSA用於key協商和認證,client會生成48字節的premaster secret,並將premaster secret使用server 證書提供的公鑰進行加密,最後發送到server端。該結構是ClientKeyExchange的變種,且不是一個獨立的消息。

struct {
  ProtocolVersion client_version;
  opaque random[46];
} PreMasterSecret;

client_version
 The latest (newest) version supported by the client.  This is
 used to detect version rollback attacks.

random
 46 securely-generated random bytes.

struct {
  public-key-encrypted PreMasterSecret pre_master_secret;
} EncryptedPreMasterSecret;

pre_master_secret:client用於生成master secret的隨機值。PreMasterSecret中的版本號由ClientHello.client_version提供,而非協商的鏈路版本,該設計用於防止rollback攻擊。不幸的是有些老的實現會使用協商出的版本號,與這些實現交互時可能會失敗。

 client的實現中必須在PremasterSecret中發送正確的版本號。若是ClientHello.client_version爲TLS1.1或更高,server的實現中必須檢查該版本號;若是版本號爲1.0或更早,server可能會檢查版本號,也可能不檢查。

TLS server在加密premaster secret失敗或遇到非指望的版本號時不能發送alert,而應該使用一個隨機生成的premaster secret進行握手。

公鑰加密的數據是一個0~2^16-1長度的opaque向量,所以ClientKeyExchange中使用RSA加密的PreMasterSecret以前爲2個字節的長度字段(表示其可變長度大小)。EncryptedPreMasterSecret 是ClientKeyExchange的惟一數據。

7.4.7.2. Client Diffie-Hellman Public Value

當client的certificate中沒有出現Diffie-Hellman public的值時發送,該消息是ClientKeyExchange的變體。當certificate中已經包含合適的Diffie-Hellman key(用於fixed_dh client認證),此時必須於發送client key exchange消息,但必須爲空。

 7.4.8. Certificate Verify

該消息用於提供client證書的校驗,證實client擁有這些證書的私鑰。僅在client certificate由簽名功能時發送(除了包含fixed Diffie-Hellman參數的證書),跟在client key exchange 消息以後發送。

struct {
   digitally-signed struct {
       opaque handshake_messages[handshake_messages_length];
   }
} CertificateVerify;

這裏的handshake_messages表示從ClientHello開始的全部接收和發送的握手消息(不包含本消息),該消息級聯了全部握手消息,結構以下

struct {
  HandshakeType msg_type;    /* handshake type */
  uint24 length;             /* bytes in message */
  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;

該實現會要求兩端緩存該消息或計算出(到接收到CertificateVerity爲止的)全部可能的hash算法。server能夠經過在CertificateRequest中設置限制來減少運算。

簽名的hash/signature算法必須是CertificateRequest消息中提供的。除此以外,hash/signature算法必須與client端的certificate兼容。

 7.4.9. Finished

該消息在ChangeCipherSpec消息以後發送,ChangeCipherSpec表示密鑰交換和認證都已經完成。

Finish是第一個使用協商的算法保護的消息,key和secrets保護的消息,接收到該消息以後必須驗證消息內容的有效性,在認證成功後就能夠發送應用消息。

struct {
    opaque verify_data[verify_data_length];
} Finished;

verify_data:PRF(master_secret, finished_label, Hash(handshake_messages)) [0..verify_data_length-1];在舊版本中的TLS,verify_data爲12 octets,當前版本則卻決於使用的cipher suite。任何沒有明確指定verify_data_length的verify_data_length默認爲12 octets。

finished_label:client發送的Finished消息相關的字符串爲"client finished',server發送的爲「server finished」

Hash:表示握手消息的hash,該hash與PRF使用的hash相同。cipher suite定義的PRF必須定義用於FInished計算的Hash

handshake messages:握手過程當中的全部消息(除HelloRequest外)。只包括handshake層的可見數據,不包含Record層首部。

在握手過程當中,若是沒有在合適的時機處理Finished消息,則返回fatal 錯誤。值handshake_message與7.4.8章節中定義的handshake_message不一樣,它包含了CertificateVerify消息, 且client的handshake_message與server的也不相同(由於發送消息的一端會包含對端已經發過來的消息)

ChangeCipherSpec,alert和其餘Record類型的消息不是握手消息,且不會進行hash運算(HelloRequest也不會)

 A.5. The Cipher Suite

本節定義了ClientHello和ServerHello的cipher suite使用的cipher suite。TLS初始化的cipher suite爲TLS_NULL_WITH_NULL_NULL,但不能使用該值進行協商(沒有提供任何保護)

CipherSuite TLS_NULL_WITH_NULL_NULL               = { 0x00,0x00 };

以下CipherSuite須要server提供用於密鑰交換的RSA證書。server可能會在CertificateReuqest中請求signature-capable證書。 

CipherSuite TLS_RSA_WITH_NULL_MD5                 = { 0x00,0x01 };
CipherSuite TLS_RSA_WITH_NULL_SHA                 = { 0x00,0x02 };
CipherSuite TLS_RSA_WITH_NULL_SHA256              = { 0x00,0x3B };
CipherSuite TLS_RSA_WITH_RC4_128_MD5              = { 0x00,0x04 };
CipherSuite TLS_RSA_WITH_RC4_128_SHA              = { 0x00,0x05 };
CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA         = { 0x00,0x0A };
CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA          = { 0x00,0x2F };
CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA          = { 0x00,0x35 };
CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256       = { 0x00,0x3C };
CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA256       = { 0x00,0x3D };

以下Cipher suite用於。DH表示server的證書包含CA簽名的Diffie-Hellman參數。DHE表示 ephemeral Diffie-Hellman,此時使用signature-capable證書(該證書u也被CA簽名)簽名Diffie-Hellman參數。server使用的簽名算法在Cipher Suite的DHE名字以後。

CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x0D };
CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x10 };
CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA     = { 0x00,0x13 };
CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA     = { 0x00,0x16 };
CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA       = { 0x00,0x30 };
CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA       = { 0x00,0x31 };
CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA      = { 0x00,0x32 };
CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA      = { 0x00,0x33 };
CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA       = { 0x00,0x36 };
CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA       = { 0x00,0x37 };
CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA      = { 0x00,0x38 };
CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA      = { 0x00,0x39 };
CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA256    = { 0x00,0x3E };
CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA256    = { 0x00,0x3F };
CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256   = { 0x00,0x40 };
CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256   = { 0x00,0x67 };
CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA256    = { 0x00,0x68 };
CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA256    = { 0x00,0x69 };
CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA256   = { 0x00,0x6A };
CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA256   = { 0x00,0x6B };

server能夠向client請求signature-capable證書或DH證書來對client進行認證。client提供的全部Diffie-Hellman證書必須使用server提供(或生成)的參數

以下cipher suite用於在兩端都沒有認證狀況下的匿名Diffie-Hellman交互。該模式容易遭中間人攻擊,所以使用場景比較有限。該模式不能用於TLS1.2的實現中(除非明確指出容許匿名key交互)。

CipherSuite TLS_DH_anon_WITH_RC4_128_MD5          = { 0x00,0x18 };
CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA     = { 0x00,0x1B };
CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA      = { 0x00,0x34 };
CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA      = { 0x00,0x3A };
CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA256   = { 0x00,0x6C };
CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA256   = { 0x00,0x6D };

目前使用最多的cipher suite:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256解析以下:

ECDHE爲密鑰交互算法,RSA爲簽名算法,AES_123_GCM爲使用GCM模式下的128位AEAD加密算法,SHA256爲建立消息摘要的MAC算法

CipherSuite的詳細定義能夠參考Cipher suite definitions

帶RC4的表示使用流加密

Appendix B. Glossary

Advanced Encryption Standard (AES):對稱加密算法,塊加密。TLS當前僅支持128-和256-位長度的AES

authenticated encryption with additional data (AEAD):對稱加密算法

block_cipher:塊加密做用於一組比特位的純文本算法,以前使用64bit,目前使用128bit,通用的塊大小

cipher block chaining (CBC):在每一個純文本塊加密前會於前面一個純文本(第一個塊與初始化向量-IV 進行運算)進行異或運算。解碼時首先進行解密,再與前面文本塊進行異或運算

Digital Signature Standard (DSS):數字簽名算法

digital signature:數字簽名使用公鑰和單向hash函數來產生簽名數據。

Data Encryption Standard:廣泛使用的對稱加密算法

Initialization Vector (IV):當塊加密使用CBC時,首個文本塊會與IV進行異或運算。

client write key:用於加密client的數據

client write MAC key:用於認證client的數據

Message Authentication Code (MAC):單向hash處理的數據,生成消息摘要。

master secret:用於生成加密key,MAC secrets和IVs

RC4:流加密。

session:session定義了可與多個連接共享的安全參數。用來避免爲每一個連接進行安全參數協商形成的消耗。

stream cipher:將一個key加密爲keystream,並與文本進行異或運算。

F.1.1.2. RSA Key Exchange and Authentication

使用RSA,key exchange和server認證能夠同時進行。server的證書中包含了公鑰。注意,使用靜態的RSA key可能致使該靜態key保護的全部session失效。

client驗證完server的證書後,會使用證書中的公鑰對pre_master_secret加密。server端成功解密pre_master_secret以後會並處理Finished消息以後,server認爲client對server的認證成功。

當使用RSA進行密鑰協商時,client經過certificate verify消息進行認證。client會對全部處理的握手消息進行簽名,這些握手消息包括server certificate(該消息使用的簽名與server相關)以及ServerHello.random(該數值與當前握手交互使用的簽名相關)

 F.1.1.3. Diffie-Hellman Key Exchange with Authentication

當使用Diffie-Hellman密鑰交換時,server能夠提供包含fixed Diffie-Hellman參數的證書或使用server KeyExchange消息發送一系列使用DSA或RSA簽名的臨時DH參數。這些臨時參數在簽名前會使用hello.random進行hash,用以防止攻擊者使用老參數進行攻擊。其餘場景下,client能夠經過驗證證書和簽名來確保該消息來自server。

若是client有包含fixed Diffie-Hellman參數的證書,該證書中的信息能夠用於完成密鑰交互。這種狀況下,client和server會生成相同的DH結果(pre_master_secret)。爲了防止pre_master_secret過長地滯留在內存中,在完成它的計算後應該儘快將其轉化爲master secret。client 的DH參數必須兼容server端的DH參數(key exchange交換而來)。

若是client使用DSA或RSA證書或其未被認證,它會在clientKeyExchange消息中發送臨時的參數,後續可能使用certificate verify消息對其進行認證。

若是使用DH密鑰對進行多個握手,因爲client和server都擁有一個包含fixed DH密鑰對的證書或server重用DH密鑰,須要注意方式subgroup攻擊。

小型的subgroup攻擊能夠經過使用DHE cipher suite並未每一個握手生成新的DH私鑰來解決。

 因爲TLS容許serve提供任意的DH groups,client應該對DH group進行校驗(與本地策略比較)。

 F.1.3. Detecting Attacks Against the Handshake Protocol

攻擊者可能會經過握手消息來修改兩端使用的加密算法。所以,攻擊者必須修改握手過程當中的一個或多個消息,當發生這種狀況的時候,client和server會計算出不一樣的hash值(消息摘要改變),此時兩端不會接受對端的Finished消息。因爲沒法獲取master_secret,攻擊者沒法修復Finished消息,這樣就能夠發現攻擊。

F.1.4. Resuming Sessions

 當須要重用session來創建連接時,會使session的master secret生成新的ClientHello.random和SeverHello.random。

只有在client和server雙方贊成的狀況下才能重用session。若是一端拒絕或證書過時(或被撤銷),此時應該進行完整的握手。

F.2. Protecting Application Data

master secret(使用ClientHello.random和ServerHello.random生成)用於生成加密數據的keys和MAC secrets

master_secret = PRF(pre_master_secret, "master secret",ClientHello.random + ServerHello.random)

使用MAC保護髮送的數據。爲了方式消息重複和篡改,使用MAC key,序列號,消息長度,消息內容以及2個固定字符串生成MAC 。消息類型字段用來確保該消息服務於某個TLS Record層。序列號用來確保可以感知到消息的刪除和重複。因爲序列號爲64位長度,能夠保證數值不會被溢出。因爲使用了獨立的MAC keys,一方的消息不能插入到另外一方的輸出中(插入後MAC會錯誤)。相似地,因爲server write和client wirte keys是獨立的,所以只會用到一次流加密keys。

MAC(MAC_write_key, seq_num +TLSCompressed.type +TLSCompressed.version +TLSCompressed.length +TLSCompressed.fragment);

若是攻擊者獲取了加密key,那麼全部的加密消息都會被讀取。相似地,泄露MAC key會致使message-modification攻擊。因爲MAC是加密的,message-alteration同時也須要突破對MAC的加密算法。

F.4. Security of Composite Cipher Modes

TLS使用cipher suite中定義的對稱加密和認證函數對傳輸的應用數據進行保護,目的是防止網絡攻擊形成數據的篡改。

當前最健壯的方式稱爲encrypt-then-authenticate(加密再認證),首先對數據進行加密,而後對密文使用MAC計算消息摘要。該方法使用加密和MAC函數保證數據的加密防禦和完整性。前者用於防止針對明文的攻擊(信息泄露),後者用於防止針對消息的攻擊(鏈路攻擊)。其次,TLS使用其餘方式,稱爲authenticate-then-encrypt(認證再加密),首先先對明文使用MAC,而後對整個數據(明文+MAC)進行加密。這種方式已經經過使用特定加密函數和MAC函數的組合證實了其安全能力,但一般不能保證安全。特別地,在使用當前很是好的加密函數再結合某個MAC函數的狀況下,沒法很好地防護主動攻擊。

目前已經證實在某些狀況下更加適合使用authenticate-then-encrypt。其中一種狀況是使用流加密時,消息pad+MAC tag的長度不可知的狀況;另外一種時在CBC模式下使用塊加密。這些狀況下,安全能力能夠經過一方對明文+MAC使用CBC加密以及對每一個明文和MAC使用(新的,獨立的,不可預測的)IV體現出來。

TLS使用塊加密+HMAC,流加密+HMAC以及AEAD(Authenticated-Encryption With Additional data)來保證數據的完整和安全。TLS1.3中廢除了除AEAD外的加密方式

 

TIPS:

  • 實際中基本不使用流加密方式
  • key exchange的目的是生成pre_master_secret,最終生成master secret,經過Finished來校驗pre_master_secret的正確性。
  • 數字簽名過程爲發送端首先使用hash算法生成消息摘要,而後使用簽名算法生成數字簽名;接收端爲上述逆過程

 參考:

 https://blog.helong.info/blog/2015/09/07/tls-protocol-analysis-and-crypto-protocol-design/

 http://blog.fourthbit.com/2014/12/23/traffic-analysis-of-an-ssl-slash-tls-session

 https://www.linuxidc.com/Linux/2015-07/120230.htm

 https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/

 https://segmentfault.com/a/1190000002554673?utm_source=tag-newest

 https://blog.helong.info/blog/2015/01/23/ssl_tls_ciphersuite_intro/

 https://httpd.apache.org/docs/2.4/ssl/ssl_intro.html

相關文章
相關標籤/搜索