RFC 8446 TLS 1.3(翻譯進度:第4章)

1. 介紹

    TLS 的主要目標是爲通信的雙方提供一個安全的通道;對下層傳輸的唯一要求是一個可靠的,有序的數據流。特別的地,安全通道應該提供如下屬性:

    - 認證: 通道的server端應該總是被認證的;client端可以選擇性的認證。認證可以通過非對稱算法(例如,RSA, 橢圓曲線數字簽名算法(ECDSA),或Edwards曲線數字簽名算法(EdDSA))完成,或通過一個對稱的預共享密鑰(PSK)。

    - 機密性:在建立完成的通道上發送的數據只能對終端是可見的。TLS不能隱藏它傳輸的數據的長度,雖然終端能夠填充TLS記錄來隱藏長度並提升針對流量分析技術的防護。

    - 完整性:在建立完成的通道上發送的數據不能被攻擊者修改且不會被發現(譯註:就是說如果修改了一定會被發現)。

    這些屬性應當是真實的,即使是面臨着已經完全控制網絡的攻擊者,就像RFC 3552裏面描述的那樣。關於相關的安全屬性詳見附錄E。

    TLS由兩個主要組件構成:

    - 一個握手協議(第4節),認證通信雙方,協商密碼模式和參數,病建立共享密鑰。握手協議被設計用來抵抗篡改;如果連接未受到攻擊,則活動攻擊者不應該強制對等方協商不同的參數。

    - 一個記錄協議(第5節),使用由握手協議建立的參數來保護通信雙方的流量。記錄協議將流量分爲一系列記錄,每個記錄獨立地使用流量密鑰來保護。

    TLS是一個獨立的應用協議;高層協議可以透明地位於TLS之上。然而,TLS標準並未指定協議如何增強TLS的安全;如何發起TLS握手以及如何理解認證證書交換留給運行在TLS之上的協議的設計者和實現者來判斷。

    本文取代和廢除了以前版本的TLS,包括1.2版本[RFC5246]。也廢除了在[RFC5077]裏面定義的TLS ticket機制,並用定義在第2.2節中的機制取代它。由於TLS 1.3改變了密鑰的產生方式,它更新了[RFC5705]。正如7.5節描述的那樣。它也改變了在線證書狀態協議(OCSP)消息的傳輸方式,因此更新了[RFC6066],廢除了[RFC6961],如第4.4.2.1節所述。

1.1公約和術語

略。

1.2與TLS 1.2的主要差異

下面的列表描述了TLS 1.2和TLS 1.3的主要功能差異。這個列表並不是詳盡無遺的,此外還有很多次要的差別。

   - 已支持的對稱算法的列表已經剪除了所有被認爲是“遺產”的算法。列表保留了所有使用“帶關聯數據的認證加密”(AEAD)算法。密碼族的概念已經轉變爲將認證和密鑰交換機制與記錄保護算法(包括機密密鑰長度)分離,一個hash會被用於密鑰導出函數和握手消息認證碼(MAC)。

    - 添加了一個0-RTT模式,爲一些應用數據在連接建立階段節省了一次往返,這是以犧牲一定的安全特性爲代價的。

    - 靜態RSA和Diffie-Hellman密碼族已經被刪除;所有基於公鑰的密鑰交換算法現在都能提供前向安全。

    -所有ServerHello之後的握手消息現在都已經加密。新引入的EncryptedExtension消息允許之前在ServerHello中以明文發送的各種擴展同樣享有針對活動攻擊者的機密保護。

    - 密鑰導出函數被重新設計。新的設計使得密碼學家能夠通過改進的密鑰分離特性進行更容易的分析。基於HMAC的提取-擴展密鑰導出函數(HKDF)被用作一個基礎的原始組件(primitive)。

    - Handshake狀態機進行了引人注目的重組,以便更具一致性和刪除多餘的消息如ChangeCipherSpec(除了由於中間件兼容性被需要時)。

    - 橢圓曲線算法已經屬於基本的規範,且包含了新的簽名算法,如EdDSA。TLS 1.3刪除了點格式協商以便於每個曲線使用單點格式。

    - 其它的密碼學改進包括改變RSA填充以使用RSA概率簽名方案(RSASSA-PSS),刪除壓縮,DSA,和定製DHE組。

    - TLS1.2的版本協商機制被廢棄以便在一個擴展中添加一個版本列表。這增加了與不正確地實現版本協商的server的兼容性。

    - 帶有和不帶server端狀態的會話恢復以及TLS早期版本的基於PSK密碼族已經被一個單獨的新PSK交換所取代。

    - 酌情更新引用以指向最新版本的RFC(例如,RFC 5280而不是RFC 3280)。

1.3 更新對TLS1.2的影響

    本文定義了幾個選擇性影響TLS 1.2實現的變化,包括那些不支持TLS 1.3的修改:

    - 一個在4.1.3節中描述的版本降級保護機制。

    - 在4.2.3節中定義的RSASSA-PSS簽名方案。

    - ClientHello中“supported_versions”的擴展可以被用於協商TLS使用的版本,它優先於ClientHello中的legacy_version域。

    - "signature_algorithms_cert"擴展允許一個client顯示它使用哪種簽名算法驗證X.509證書。

    此外,本文澄清了一些需要服從的需求以支持TLS的早期版本;見9.3節。

2 協議概覽

        安全通道所使用的密碼參數由TLS握手協議生成。這個TLS的子協議在client和server第一次通信時使用。握手協議允許兩端協商一個協議版本,選擇密碼算法,選擇性互相認證,並建立共享的密鑰數據。一旦握手完成,雙方就會使用建立好的密鑰保護應用層流量。
        一個失敗的握手或其它的協議錯誤會觸發連接的中止,在這之前可以有選擇地發送一個警報消息(第6章)。
        TLS支持3種基本的密鑰交換模式:
        - (EC)DHE (基於有限域或橢圓曲線的Eiffie-Hellman)
        - 單獨的PSK
        -  PSK結合(EC)DHE
        下面的圖1顯示了基本TLS握手的全部流程:

                  +  標明是在以前標註的消息中發送的值得注意的擴展
                  *  表示可選的或者依賴一定條件的消息/擴展,它們不總是發送
                  () 表示消息由從client_early_traffic_secret導出的密鑰保護
                  {} 表示消息使用從一個[sender]_handshake_traffic_secret導出的密鑰保護
                  [] 表示消息使用從[sender]_application_traffic_secret_N導出的密鑰保護

                    圖1:完整握手消息流

        握手可以被認爲有三個階段(在上面的圖中已表明):
        - 密鑰交換:建立共享密鑰數據並選擇密碼參數。在這個階段之後所有的數據都會被加密。
        - Server參數:建立其它的握手參數(client是否被認證,應用層協議支持等)。
        - 認證:認證server(並且選擇性認證client),提供密鑰確認和握手完整性。

        在密鑰交換階段,client會發送ClientHello(4.1.1節)消息,其中包含了一個隨機nonce(ClientHello.random);它提供了協議版本,一個對稱密碼/HKDF hash對的列表;一個Diffie-Hellman密鑰共享集合或一個預共享密鑰標籤(在4.2.11節的"key_share"擴展中)集合,或二者都有;和可能的其它擴展。

        Server處理ClientHello併爲連接確定合適的密碼參數。然後它會以自己的ServerHello(4.1.3節)作爲響應,其中表明瞭協商好的連接參數。ClientHello和ServerHello合在一起來確定共享密鑰。如果已經建立的(EC)DHE密鑰正在被使用,則ServerHello中會包含一個”key_share”擴展,和這個擴展一起的還有server的臨時Diffie-Hellman共享參數,這個共享參數必須與client的一個共享參數在相同的組裏。如果使用的是PSK密鑰,則ServerHello中會包含一個"pre_shared_key"擴展以表明client提供的哪一個PSK被選中。需要注意的是實現上可以將(EC)DHE和PSK一起使用,這種情況下兩種擴展都需要提供。
隨後Server會發送兩個消息來建立Server參數:
        EncryptedExtensions: 用來響應不用於決定密碼參數的ClientHello擴展,除了針對用戶證書的擴展。[4.3.1節]
        CertificateRequest: 如果被要求基於證書的client認證,則包含與證書相關的參數。如果client認證不被要求則此消息會被省略。
        最後,client和server交換認證消息。TLS在每次認證時使用相同的消息集,特別是:
        Certificate: 終端和任何每證書擴展的證明。如果不帶證書認證則此消息會被server忽略;如果server沒有發送CertificateRequest(因此表明client不使用證書認證),此消息會被client忽略。需要注意的是如果原始公鑰[RFC 7250]或緩存的信息擴展[RFC 7924]正在被使用,則此消息不會保護一個證書而是包含一些與server的長期密鑰相關的其它值。[4.4.2節]
        CertificateVerify: 使用與證書消息中的公鑰配對的私鑰對整個握手消息進行簽名。如果終端沒有使用證書進行驗證則此消息會被忽略。
        Finished: 對整個握手消息的MAC(消息認證碼)。這個消息提供了密鑰確認,將終端身份與交換的密鑰綁定在一起,這樣在PSK模式下也能認證握手。[4.4.4節]
        接收到server的消息之後,client會響應它的認證消息,即Certificate,CertificateVerify (如果需要), 和Finished。
        這時握手已經完成,client和server會提取出密鑰材料用於記錄層交換應用層數據,這些數據需要通過認證的加密來保護。應用層數據一定不能在Finished消息之前、必須等到記錄層開始使用加密密鑰之後纔可以發送。需要注意的是server可以在收到client的認證消息之前發送應用數據,任何在這個時間點發送的數據,當然都是在發送給一個未被認證的對端。

2.1 錯誤的DHE共享

        如果client沒有提供一個充分的”key_share”擴展(例如,它只包含server不接受或不支持的DHE或ECDHE組),server會使用一個HelloRetryRequest來糾正這個不匹配問題,client需要使用一個合適的”key_share”擴展來重啓握手,如圖2所示。如果沒有通用的密碼參數能夠協商,server必須使用一個適當的警報來中止握手。

                                                圖2:一個帶有不匹配參數的完整握手過程的消息流程

注:這個握手過程包含初始的ClientHello/HelloRetryRequest交換;它不能被新的ClientHello重置。

TLS也支持幾個基本握手中的優化變體,正如下面的章節中描述的那樣。

2.2 恢復和預共享密鑰(PSK)

        雖然TLS預共享密鑰(PSK)能夠在帶外建立,預共享密鑰也能在一個之前的連接中建立然後重用(會話恢復)。一旦一次握手完成,server就能給client發送一個與一個獨特密鑰對應的PSK身份,這個密鑰來自初次握手(見4.6.1節)。然後client能夠使用這個PSK身份在將來的握手中協商相關PSK的使用。如果server接受它,新連接的安全上下文在密碼學上就與初始連接關聯在一起,從初次握手中得到的密鑰就會用於裝載密碼狀態來替代完整的握手。在TLS 1.2以及更低的版本中,這個功能由"session IDs"和"session tickets" [RFC5077]來提供。這兩個機制在TLS 1.3中都被廢除。

        PSK可以與(EC)DHE密鑰交換算法一同使用以便使共享密鑰具備前向安全,或者PSK可以被單獨使用,這樣是以丟失了應用數據的前向安全爲代價。

        圖3顯示了兩次握手,第一次建立了一個PSK,第二次時使用它:

                                                                               圖3: PKS和恢復消息流

        當server通過一個PSK進行認證時,它不會發送一個Certificate或一個CertificateVerify消息。當一個client通過PSK提供一個恢復時,它也應當提供一個"key_share"給server,以允許server拒絕恢復,如果需要的話回退到一個完整的握手。Server響應一個"pre_shared_key"擴展來協商建立PSK密鑰的方法,並響應一個"key_share"擴展(如圖所示)來進行(EC)DHE密鑰建立,由此提供前向安全。

        當PKS在帶外提供時,PSK身份和與PSK一起使用的KDF hash算法也必須被提供。

        注:當使用一個帶外提供的預共享密鑰時,一個關鍵的考慮是在密鑰生成時使用足夠的熵,就像[RFC4086]中討論的那樣。從一個口令或其它低熵源導出的一個共享密鑰並不安全。一個低熵密碼,或口令,易遭受基於PSK綁定器的字典攻擊。指定的PSK認證並不是一個基於強口令的已認證的密鑰交換,即使使用了Diffie-Hellman密鑰建立方法。

2.3 0-RTT數據

        當client和server共享一個PSK(從外部獲得或通過一個以前的握手獲得)時,TLS 1.3允許client在第一個發送出去的消息("early data")中攜帶數據。Client使用這個PSK來認證server並加密early data。

        正如圖4所示,0-RTT數據在第一個發送的消息中被加入到1-RTT握手裏。握手的其餘消息與帶PSK恢復的1-RTT握手消息相同。
 

             

                  +  標明是在以前標註的消息中發送的值得注意的擴展

                  *  表示可選的或者依賴一定條件的消息/擴展,它們不總是發送

                  () 表示消息由從client_early_traffic_secret導出的密鑰保護

                  {} 表示消息使用從一個[sender]_handshake_traffic_secret導出的密鑰保護

                  []表示消息使用從[sender]_application_traffic_secret_N導出的密鑰保護

                                                                   圖4: 一個0往返握手的消息流

 

        重要標註:0-RTT數據的安全屬性比其它類型的TLS數據弱,特別是:

        1. 這類數據沒有前向安全,它只使用了從被提供的PSK中導出的密鑰進行加密。

        2. 不能保證在多條連接之間不會有重放。爲普通的TLS 1.3.1-RTT數據提供抗重放的保護方法是使用server的隨機數據,但0-RTT不依賴於ServerHello,因此只能得到更弱的保護。如果數據與TLS client認證或在應用協議裏一起驗證,這一點尤其重要。這個警告適用於任何使用early_exporter_master_secret的情況。

3. 陳述語言

        本文使用另外的表示方法處理數據格式。下面會用到非常基礎甚至是有些隨便定義的陳述語法。

3.1 基本塊大小

        所有數據條目的描述都是被顯示指定的。基本數據塊大小是1個字節(即8位)。多個字節數據條目是字節的串聯,從左到右,從上到下。從字節流的角度 看,一個多字節條目(在例子中是一個數值)的組織方式(使用C的記法)如下:
value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) | ... | byte[n-1];
對於多字節數值這個字節序是普通的網絡字節序或大端格式。

3.2 其它

        註釋以"/*"開頭,以"*/"結束。
        可選組件通過將其包含在"[[ ]]" 雙括號中來表示。
        包含未解釋數據的單字節實體屬於opaque類型。
        可以爲一個現有類型T定義一個別名T':
               T T';

3.3 向量

        一個向量(一維數組)是一個同類數據元素的流。向量的大小可能在編寫文檔時指定或留待運行時確定。在任何情況下,向量的長度都是指字節數而非元素數。定義一個新類型T'(是一個固定長度的類型T的向量)的語法是:
        T T'[n];
        這裏,T'在數據流中佔據了n個字節,而n是多個類型T的大小。向量的長度並不包含在編碼流中。
        在下面的例子中,Datum被定義爲協議不能理解的3個連續字節, 而Data是三個連續的Datum,共佔據9個字節。
        opaque Datum[3];      /* 三個未知字節 */
        Datum Data[9];        /* 3個連續的3字節向量 */
        變長向量的定義是通過指定一個合法長度的子範圍來實現(使用符號<floor..ceiling>)。當這些被編碼時,在字節流中實際長度是在向量的內容之前。這個長度會以一個數字的形式出現,並消耗足夠多的字節以便表示向量的最大長度(ceiling)。一個實際長度是0的變長向量會被當做一個空向量。
        T T'<floor..ceiling>;

        在下面的例子中會強制要求一個向量必須包含300-400個字節的opaque類型數據,它不能爲空。實際長度域佔用兩個字節,一個uint16,這足以代表數值400(見3.4節)。相似地,更長的向量可以描述多達800字節的數據,或400個uint16類型的元素,這個向量可以爲空。它的編碼會包含一個兩字節的實際長度域設置在向量前。一個編碼向量的長度必須是單個元素長度的偶數倍(例如,一個17字節長的uint16類型的向量是非法的)。
      opaque mandatory<300..400>;  /*長度域是2字節,不能爲空 */
      uint16 longer<0..800>;  /* 0-400 16-bit 無符號整數 */

3.4 數字

        基本數字數據類型是一個無符號字節(uint8)。所有更大的數字數據類型都被組織成固定長度的字節序列並如4.1節中所描述的那樣被串聯,且同樣是無符號的。下面是預定義的數字類型。
        uint8 uint16[2];
        uint8 uint24[3];
        uint8 uint32[4];
        uint8 uint64[8];
        本篇規範中的所有的數值都是以網絡字節序(大端)存儲;一個uint32類型的十六進制字節01 02 03 04等於十進制數16909060。

3.5 枚舉

        另外一種少見的數據類型是枚舉。每個定義都是一個不同的類型。只有相同類型的枚舉能被指定或比較。一個枚舉的每個元素必須被指定一個值,就像下面的例子所表明的。既然枚舉類型的元素並不是有序的,它們能夠被以任意順序指定任意獨一的值。
        enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;

        將來對協議的擴展或添加會定義新的值。實現需要能夠解析或者忽略未知的值,除非字段的定義另有說明。

        一個枚舉在字節流中佔據的空間足夠存儲其定義的最大有序數值。下面的定義會使用1個字節來表示Color類型的域。
        enum { red(3), blue(5), white(7) } Color;
        一個選擇是指定一個值但不關聯標記以強制定義枚舉的大小,這樣無需定義一個多餘的元素.在下面這個例子中,Taste在字節流中會消耗2個字節, 但在當前的協議版本中只能表示數值1,2,或4。
        enum { sweet(1), sour(2), bitter(4), (32000) } Taste;
        一個枚舉類型的元素的名稱被侷限於定義的類型。在第一個例子中,對枚舉的第二個元素的完全合格的引用是Color.blue,如果賦值的目標是被 很好地指定(譯註:這句話的意思應該不會引起衝突,或叫二義性),則這樣的格式是不需要的。
        Color color = Color.blue;     /* 過度指定, 合法 */
        Color color = blue;           /* 正確, 類型隱藏 */
        指定給枚舉的名字不需要是唯一的。數字的值可以描述一個相同名稱枚舉應用的範圍。這個值包括取值範圍中最小和最大的包含值,由兩個週期字符分隔開。這是主要用於保留空間區域。
        enum { sad(0), meh(1..254), happy(255) } Mood;

3.6構造類型

      爲了方便,結構體類型可以由原始類型構建。每個規範聲明瞭一個新的、獨特的類型。定義的語法很像C語言:
      struct {
          T1 f1;
          T2 f2;
          ...
          Tn fn;
      } T;
    固定長度和變長向量域被允許使用標準的向量語法。下面的變量示例中的結構體V1和V2表明了這一點。
        結構體內的域可以用類型的名字來描述,使用類似於枚舉的語法。例如,T.f2引用了前面定義的結構的第二個域。

3.7 常量

      域和常量可以使用"="來賦予一個固定的值,像下面那樣:
      struct {
          T1 f1 = 8;  /* T.f1 必須一直是8 */
          T2 f2;
      } T;

3.8 變量

    考慮到從環境中獲得的一些信息是變化的,定義的結構體可以有一些變量。選擇符必須是一個定義了結構體中變量取值範圍的枚舉類型。Select語句的case條件指定了變量域的類型和一個可選的域標籤。通過這個機制變量可以在運行時被選擇,這個機制不能被陳述語言所描述。
     struct {
          T1 f1;
          T2 f2;
          ....
          Tn fn;
          select (E) {
              case e1: Te1 [[fe1]];
              case e2: Te2 [[fe2]];
              ....
              case en: Ten [[fen]];
          };
      } Tv;
   例如:
      enum { apple(0), orange(1) } VariantTag;
      struct {
          uint16 number;
          opaque string<0..10>; /* 變長 */
      } V1;
      struct {
          uint32 number;
          opaque string[10];    /* 定長 */
      } V2;
      struct {
          VariantTag type;
          select (VariantRecord.type) {
              case apple:  V1;
              case orange: V2;
          };
      } VariantRecord;

4. 握手協議

 

    握手協議用於協商連接的安全參數。握手消息被提供給TLS記錄層,在那裏他們被封裝到一個或多個TLSPlaintext或TLSCiphertext中,它們按照當前活動連接狀態的指定進行處理和傳輸。

    enum {

         client_hello(1),

         server_hello(2),

         new_session_ticket(4),

         end_of_early_data(5),

         encrypted_extensions(8),

         certificate(11),

         certificate_request(13),

         certificate_verify(15),

         finished(20),

         key_update(24),

         message_hash(254),

         (255)

     } HandshakeType;

     struct {

         HandshakeType msg_type;    /*handshake type */

         uint24 length;             /*bytes in message */

         select (Handshake.msg_type) {

              case client_hello:          ClientHello;

              case server_hello:          ServerHello;

              case end_of_early_data:     EndOfEarlyData;

              case encrypted_extensions:  EncryptedExtensions;

              case certificate_request:   CertificateRequest;

              case certificate:           Certificate;

              case certificate_verify:    CertificateVerify;

              case finished:              Finished;

              case new_session_ticket:    NewSessionTicket;

              case key_update:            KeyUpdate;

         };

     } Handshake;

    協議消息必須以4.4.1節中定義的順序發送,這個順序也已經在第2章的圖中展示了。對端如果收到了不按順序發送的握手消息必須使用一個"unexpected_message"警報來中止握手。

    新的握手消息類型已經由IANA指定並在第11章中描述。

4.1 密鑰交換消息

    密鑰交換消息用於確定client和server之間的安全能力,並建立包括流量密鑰在內的共享密鑰來保護其餘的握手消息和數據。

4.1.1 密碼的協商

    在TLS中,密碼的協商通過client在ClientHello中提供下面4個選項集合來實現:

    - 一個密碼族列表¬——表明client所支持的AEAD算法/HKDF hash對;

    - 一個”支持的組”(4.2.7節)擴展——表明client支持的(EC)DHE組,和一個”key_share”(4.2.8)擴展——包含了一些貨全部這些組所共享的(EC)DHE密鑰。

   - 一個"signature_algorithms"(4.2.3節)擴展——表明client能接受的簽名算法。
   - 一個"pre_shared_key" (4.2.11節)擴展——包含了一個client知曉的對稱密鑰,和一個"psk_key_exchange_modes" (4.2.9擴展)——表明與PSK一起使用的密鑰交換模式。
      如果server沒有選擇PSK,則這些選項的前3個是完全正交的:server獨立地選擇一個密碼族,一個(EC)DHE組和用於建立密鑰的密鑰共享,一個簽名算法/證書對用於認證自己和client。如果接收到的"supported_groups"和server所支持的組之間沒有重疊,則server必須用一個"handshake_failure" 或一個"insufficient_security"警報中止握手。

      如果server選擇了一個PSK,則它也必須從client的"psk_key_exchange_modes"擴展(目前是僅有PSK或帶(EC)DHE)所表明的集合中選擇一個密鑰建立模式。需要注意的是如果PSK可以不帶(EC)DHE就能被使用,則"supported_groups"參數不重疊不一定是致命的,就像以前段落中討論過的非PSK場景一樣。

         如果server選擇了一個(EC)DHE組並且client沒有在初始ClientHello中提供一個兼容的"key_share"擴展,server必須響應一個HelloRetryRequest(4.1.4節)消息。

         如果server成功地選擇了參數且沒有發送HelloRetryRequest,表明ServerHello中所選的參數如下:

        -  如果PSK被使用,則server會發送一個”pre_shared_key”擴展表明所選的密鑰。

        -  如果PSK沒有被使用,則(EC)DHE和基於證書的認證會一直被使用。

        -  當使用(EC)DHE時,server將會提供一個” key_share”擴展。

        -  當通過證書進行驗證時,server將會發送Certificate(4.4.2節)和CertificateVerify(4.4.3節)消息。在本文定義的TLS1.3中,一個PSK或一個證書會一直被使用,但不會同時使用。將來的文檔可能會定義怎樣同時使用它們。

      如果server不能協商一個可支持的參數集合(例如,client和server的參數集合沒有重疊),它必須用一個"handshake_failure" 或一個"insufficient_security"警報(見第6章)中止握手。

4.1.2 Client Hello

    當一個client第一次連接一個server時,它需要發送ClientHello作爲它的第一個消息。當server用HelloRetryRequest來響應client的ClientHello時,client也應當發送ClientHello。這種條件下,client必鬚髮送相同的ClientHello(無修改),除非:

    -  如果HelloRetryRequest帶有一個”key_share”擴展,則將共享的列表用一個列表取代,這個列表包含單個來自表明的組中的KeyShareEntry。

    -  如果存在”early_data”擴展則將其移除。早期數據(earlydata)不允許在HelloRetryRequest之後出現。

    -  如果HelloRetryRequest中提供了一個”cookie”擴展,則需要包含一個;

    - 如果需要重新計算"obfuscated_ticket_age" 和綁定值,並(可選地)刪除任何不兼容server展示的密碼族的PSK,則更新"pre_shared_key"擴展。

    -  選擇性地增加,刪除或更改”padding”擴展[RFC 7685]的長度。

    由於TLS 1.3禁止重協商,如果一個server已經協商完成了TLS 1.3並且在任何其它時間收到了一個ClientHello,它必須用一個"unexpected_message"警報中止連接。

    如果一個server用以前版本的TLS建立了一個TLS連接並在重協商時接收了一個TLS1.3的ClientHello,它必須保持以前的協議版本。特別是,它不能協商TLS 1.3。

    這個消息的結構:

      uint16 ProtocolVersion;

      opaque Random[32];

      uint8 CipherSuite[2];    /* 密碼族選擇器 */

      struct {

          ProtocolVersion legacy_version = 0x0303;    /* TLS v1.2 */

          Random random;

          opaquelegacy_session_id<0..32>;

          CipherSuitecipher_suites<2..2^16-2>;

          opaquelegacy_compression_methods<1..2^8-1>;

          Extension extensions<8..2^16-1>;

      } ClientHello;

        legacy_version 在以前版本的TLS裏,這個域被用於版本協商和表示由client所支持的最高版本號。經驗表明很多server沒有適當地實現版本協商,導致“版本容忍”會使server拒絕了版本號高於它支持的其它可接受的ClientHello。在TLS 1.3中,client在"supported_versions" 擴展(4.2.1節)中表明的它的版本偏好,且legacy_version域必須被設置爲0x0303,這是TLS1.2的版本號。(關於後向兼容的細節見附錄D)
        random  由一個安全隨機數生成器產生的32字節隨機數。額外信息見附錄C。
        legacy_session_id  TLS 1.3之前的TLS版本支持一個"會話恢復"特性,在這個版本中此特性已經與預共享密鑰合併了(見2.2節)。一個client需要將這個域設置爲由一個TLS 1.3之前版本的server所設置的緩存的 session ID。在兼容模式下(見附錄D.4)此域必須是非空,所以一個不能提供TLS 1.3之前版本會話的client必須產生一個32字節的新值。這個值不必是隨機的但應該是不可預測的以避免實現上固定爲一個具體的值(也被稱爲僵化)。否則,它必須被設置爲一個0長度向量(例如,一個0字節長度域)。
        cipher_suites: client支持的對稱密碼族選項列表,具體有記錄保護算法(包括密鑰長度)和與HKDF一起使用的hash算法,這些算法以client期望的降序排列。密碼族的值定義在Appendix B .4。如果列表中包含server不認識,不支持,或不想使用的密碼族,server必須忽略這些密碼族並且正常處理其餘的密碼族。如果client試圖建立一個PSK,它應該通告至少一個密碼族以表明與PSK相關的hash算法。
        legacy_compression_methods:TLS 1.3以前的版本支持支持壓縮,並提供一個支持的壓縮方法列表。對於TLS 1.3的每個ClientHello,這個向量必須只包含1字節並設置爲0,對於以前的TLS版本這代表null。如果收到一個TLS 1.3 ClientHello這個域是其它的值,server必須以一個"illegal_parameter" alert來中止握手。請注意,TLS 1.3 server可能會接收TLS 1.2或之前的ClientHello包含其它壓縮方法,(如果與這樣一個先前版本協商)必須遵循適當的TLS先前版本的流程。

        extensions: Client通過在extensions域發送數據來向server請求擴展的功能。實際的"Extension"格式定義在4.2節中。在TLS 1.3中,使用特定的extensions是強制的,因爲一些功能被轉移到了extensions裏以保留ClientHello與先前TLS版本的兼容性。Server必須忽略無法識別的extensions.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章