傳輸層安全協議(TLS)1.2版

1.介紹

TLS協議的主要目標是在兩個通信應用之間提供私密性和數據完整性。這個協議由兩組成:TLS記錄協議和TLS握手協議。最低層是基於一些可靠傳輸協議(如TCP)的TLS記錄協議。TLS記錄協議提供的連接安全有兩個基本性質:

  • 連接是私有的。對稱密碼學被用於數據加密(如:AES,RC4等)。對稱加密的密鑰對每條連接都是獨特的,而且是基於另外一種協議(如TLS握手協議)進行的祕密協商而生成的。記錄協議也能用於無加密的情況
  • 連接是可靠的。消息的傳輸包含了一個使用基於密鑰的MAC的消息完整性檢查。安全hash函數(如SAH-1等)被用於MAC計算。記錄協議可以不使用MAC,但這種模式只能用於TLS握手協議使用記錄協議傳輸消息來協商安全參數的情況。
        TLS記錄協議被用於封裝各種高層協議。其中一種被封裝的協議就是TLS握手協議,這種協議允許服務器和客戶端在應用層協議傳輸或接收第一個字節數據之前驗證彼此的身份並協商一個加密算法和加密密鑰。TLS握手協議提供連接安全有三個基本性質:
  • 對端的身份能夠使用非對稱(或公鑰)密碼學(如RSA,DSA等)來驗證。這個驗證是可選的,但通常要求至少驗證一方。
  • 共享機密的協商是安全的:竊聽者無法得到所協商的機密,對於已認證的連接,攻擊者即使把自己置於連接的中間也是無法得到機密的。
  • 協商是可靠的:攻擊者不能在不被通信的參與者獲知的情況下修改協商數據。

        TLS的一個優點是它是應用層協議無關的。高層協議可以透明地置於TLS協議之上。然而,TLS標準不會指定協議怎樣爲TLS增加安全性。關於怎樣初始化TLS握手、怎樣理解認證證書交換的相關決策,則留給運行於TLS之上的協議的設計者和實現者做判斷。

1.1需求術語

略。

1.2與TLS1.1的主要差別

        本文是TLS 1.1協議的一個修訂,修訂內容包括提升了靈活性,尤其是密碼學算法的協商。主要變更如下:

  • 在僞隨機函數中合併使用MD5和SHA-1算法的做法被在僞隨機函數中指定密碼協議族的方法所取代。本文中所有的密碼協議族使用P_SHA256。
  • 在數字簽名要素中合併使用MD5和SHA-1算法的做法被單獨的hash算法取代。現在的簽名素包含一個顯指定所用hash算法的域。
  • 對客戶端和服務器的能力進行實質性的清理,以便指定他們接受的hash和簽名算法。這樣也會減小使用以前版本TLS中的簽名和hash算法的約束。
  • 增加了對“以其它數據模式進行認證加密”的支持。
  • 增加了對TLS擴展的定義和AES協議族的支持
  • 對加密的預主密鑰的版本號進行更嚴格的檢查。
  • 嚴格限定了一些需求。
  • Verifi_data的長度現在取決於密碼協議(默認仍然是12)。
  • 清除了對Bleichenbacher/Klima攻擊防禦的描述。
  • 在很多情況下必須發送警報消息。
  • 在發出一個“證書請求”消息之後,如果客戶端沒有收到證書,則必須發送一個空證書列表。
  • TLS_RSA_WITH_AES_128_CBC_SHA現在是一個強制實現的密碼協議族。
  • 增加了HMAC-SHA256密碼協議族。
  • 移除了IDEA和DES協議族,它們已經不被贊成使用,且會在一個單獨的文檔中說明。
  • 對SSLv2後向兼容hello的支持現在是“可以”而非“應該”(支持的方式爲迴應”SHOULD NOT);將來這種支持很可能成爲“”不應該“
  • 在演示語言中增加受限的”通過“,以便允許多種情況的arms擁有相同的編碼。(原文:Added limited "fall-through" to the presentation language to allow multiple case arms to have the same encoding.)
  • 增加了章節描述關於實現上的易犯的錯誤
  • 通常的澄清和編輯工作

2.目標

TLS協議的目標按照優先級排列如下:

  1. 密碼安全:TLS應當被用於在通信雙方之間建立一個安全連接。 
  2. 互操作性:不相關的程序員們應當能夠在不瞭解他人代碼的情況下使用TLS開發出能成功地交換密碼參數的應用。
  3. 可擴展性:TLS致力於提供一個框架,新的公鑰和塊加密方法能夠作爲必要內容被合並進去。這樣也會實現兩個子目標:阻止了創造新協議的需要(和引入可能存在新弱點的風險)和避免了實現一整套新安全庫的需要。
  4. 相對效率:密碼操作趨於高CPU消耗,尤其是公鑰操作。正因如此,TLS協議已經結合了一個可選的會話緩存機制以減小連接(that need to be
          established from scratch)的數量。此外,關於減少網絡活動(譯者注:應該指的是流量)也獲得了關注。

3.本文的目標

        本文和TLS協議自身都是基於由Netscape公佈的SSL 3.0規範。TLS和SSL3.0的差異並不是引人注目的,但差異也足夠大到使各種版本的TLS和SSL3.0不能互操作(雖然每種協議都包含一個機制使其能夠兼容之前的版本)。本文的主要目標讀者是協議實現者和對協議進行密碼分析的人員。這個思想貫穿於這篇規範的制定過程,並致力於反應這兩部分羣體(譯者注:協議實現和協議分析人員)的需求。出於這個原因,很多算法相關的數據結構和規則被包含在文檔的內容中(或附錄中),以方便獲取。
        本文並不致力於提供任何關於服務定義和接口定義的細節,雖然處於維護安全的堅實性,它確實有選擇地覆蓋了一些策略的區域。

4.陳述語言

        本文使用另外的表示方法處理數據格式。下面會用到非常基礎甚至是有些隨便定義的陳述語法。這種語法源自多處。雖然它在語法上像編程語言C,在語法和目的上像XDR(External Data Representation),但有太多相似之處是有風險的。這種陳述語言只用於將TLS文檔化,在這個特定目標外該語言不會有普遍的應用。

4.1 基本塊大小

        所有數據條目的描述都是被顯示指定的。基本數據塊大小是1個字節(即8位)。多個字節數據條目是字節的串聯,從左到右,從上到下。從字節流的角度 看,一個多字節條目(在例子中是一個數值)的組織方式(使用C的記法)如下:

value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) | ... | byte[n-1];

對於多字節數值這個字節序是普通的網絡字節序或大端格式。

4.2 其它

        註釋以"/*"開頭,以"*/"結束。

        可選組件通過將其包含在"[[ ]]" 雙括號中來表示。

        包含未解釋數據的單字節實體屬於opaque類型。

4.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(見4.4節)。另外一方面,更長的向量可以描述多達800字節的數據,或400個uint16類型的元素,這個向量可以爲空。它的編碼會包含一個兩字節的實際長度域設置在向量前。一個編碼向量的長度必須是單個元素長度的偶數倍(例如,一個17字節長的uint16類型的向量是非法的)。

      opaque mandatory<300..400>;  /*長度域是2字節,不能爲空 */
      uint16 longer<0..800>;  /* 0-400 16-bit 無符號整數 */

4.4 數字

        基本數字數據類型是一個無符號字節(uint8)。所有更大的數字數據類型都被組織成固定長度的字節序列並如4.1節中所描述的那樣被串聯,且同樣是無符號的。下面是預定義的數字類型。

        uint8 uint16[2];
        uint8 uint24[3];
        uint8 uint32[4];
        uint8 uint64[8];

        本篇規範中的所有的數值都是以網絡字節序(大端)存儲;一個uint32類型的十六進制字節01 02 03 04等於十進制數16909060。
        需要注意的是在一些情況下(如DH參數)有必要將整數以不透明(譯註:opaque)向量的形式表示。在這種情況下,它們代表無符號整數(即,最開始的0字節是不需要的,即使設置了最有意義的bit(譯註:不明白這個bit是什麼))。

4.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;           /* 正確, 類型隱藏 */
        對於不能轉化爲外部表示的枚舉(原文:external representation),其數字信息會被忽略。
        enum { low, medium, high } Amount;

4.6構造類型

        出於方便,結構體類型可以由原始類型構建。每個規範聲明瞭一個新的、獨特的類型。定義的語法很像C語言:

      struct {
          T1 f1;
          T2 f2;
          ...
          Tn fn;
      } [[T]];

        結構體內的域可以用類型的名字來描述,使用類似於枚舉的語法。例如,T.f2引用了前面定義的結構的第二個域。結構體的定義可以嵌套。

4.6.1 變量

         基於從環境中獲得的知識,定義的結構體可以有一些變量。選擇符必須是一個定義了結構體中變量取值範圍的枚舉類型。在select中聲明的每個枚舉元素必須有一個case條件。Case條件有受限的通過條件:如果兩個case條件中間緊緊相連,它們中間沒有域,則它們擁有相同的域。因此,在下面的例子中,"orange"和"banana"都包含V2,注意這是TLS 1.2中的一個新的語法。

        變量結構體的體可以添加一個標籤用於引用。通過這個機制變量可以在運行時被選擇,並不會被描述語言所限制。
   struct {
          T1 f1;
          T2 f2;
          ....
          Tn fn;
           select (E) {
               case e1: Te1;
               case e2: Te2;
               case e3: case e4: Te3;
               ....
               case en: Ten;
           } [[fv]];
      } [[Tv]];
        例如:

        enum { apple, orange, banana } VariantTag;

      struct {
          uint16 number;
          opaque string<0..10>; /*變長*/
      } V1;

      struct {
          uint32 number;
          opaque string[10];    /* 固定長度 */
      } V2;

      struct {
          select (VariantTag) { /*selector的值是隱晦的 */
              case apple:
                V1;   /* 變量體, tag = apple */
              case orange:
              case banana:
                V2;   /*變量體, tag = orange or banana */
          } variant_body;       /* 變量的可選標籤*/
      } VariantRecord;

4.7 密碼屬性

     5個密碼操作(數字簽名,流密碼加密,塊密碼加密,AEAD(authenticated encryption with)加密,公鑰加密)分別被命名爲:數字簽名、流加密、塊加密、aead加密和公鑰加密。一個域的密碼處理流程是通過將一個經過適當合適的關鍵字放在域類型規範之前來指定的。密碼密鑰由當前連接的狀態所暗示的(見6.1節)
一個數字簽名元素被編碼爲一個DigitallySigned結構:

      struct {
         SignatureAndHashAlgorithm algorithm;
         opaque signature<0..2^16-1>;
      } DigitallySigned;

         algorithm域指定了所使用的算法(見7.4.1.4.1節對這個域的定義)。需要注意的是algorithm域的介紹是改變自以前的版本。signature是一個使用這些算法對內容元素進行的數字簽名。這些內容本身不會出現在網絡通路上但可以被簡單計算出來。signature的長度由簽名算法和密鑰確定。

         對於RSA簽名,opaque向量包含使用RSASSA-PKCS1-v1_5簽名方案(定義在[PKCS1]中)所生成的signature。 正如在[PKCS1]中所討論的,DigestInfo必須是DER編碼的[X680][X690]。對於沒有參數的hash算法(包括SHA- 1),DigestInfo.AlgorithmIdentifier.parameters 域必須是NULL,但實現上必須接受有無參數和NULL參數。需要注意的是TLS早期版本使用了一個不同的RSA簽名方案,這個方案不包含 DigestInfo編碼。對於DSA,20字節的SHA-1hash會通過數字簽名算法來直接運行,不需要添加額外的hash算法。這樣產生了兩個值,r和s。DSA簽名 是一個opaque向量,像上面的一樣,其內容是DER編碼的:

     Dss-Sig-Value ::= SEQUENCE {
          r INTEGER,
          s INTEGER
      }

        注意:在當前的術語中,DSA是指數字簽名算法,DSS是指NIST標準。在原始的SSL和TLS規範中,DSS使用得很廣泛。本文使用 "DSA"是指算法,"DSS"是中標準,在代碼中使用"DSS"是考慮到歷史的連續性。

        在流密碼加密中,明文是同源自一個密碼學安全密鑰的僞隨機數生成器的相同數量的輸出進行的異或運算。

        在塊密碼加密中,每個明文塊被加密爲一個密文塊。所有的密文塊都以CBC(密碼分組鏈接模式)模式生成。所有的分塊加密的元素都會是密文塊長度的精確倍數。

        在AEAD加密中,明文同時被加密和進行完整性保護。輸入可以是任意長度,aead加密輸出通常比輸入大,以容納完整性檢驗值。

        在公鑰加密中,一個公鑰算法所加密的數據只有使用匹配的私鑰才能解密。一個公鑰加密元素被編碼成一個opaque向量<0..2^16-1>,這裏的長度由加密算法和密鑰指定。

        RSA加密可以使用RSAES-PKCS1-v1_5加密機制實現,這個機制在[PKCS1]中定義。

        在下面的例子中,

      stream-ciphered struct {
          uint8 field1;
          uint8 field2;
          digitally-signed opaque {
            uint8 field3<0..255>;
            uint8 field4;
          };
      } UserType;

      內部結構(field3和field4)的內容被用作簽名/hash算法的輸入,然後整個結構體被流密碼加密。這個結構體的長度按字節計算,等於field1和field2所用的2個字節,加上簽名和hash算法用的2個字節,加上簽名長度用的兩個字節,加上簽名算法輸出的長度。簽名的長度是已知的,因爲簽名所用的算法和密鑰在編碼或解碼這個結構體之前就已經知道了。

4.8 常量

        出於規範性,固定類型的常量的定義可以通過聲明一個所需類型的符號並賦值來實現。

        不確定的類型(譯註:原文是“Under-specified types”)(opaque,變長向量,和包含opaque類型的結構體)不能被賦值。多元素結構體或向量的賦值可以忽略域的名稱。

        例如:

      struct {
          uint8 f1;
          uint8 f2;
      } Example1;

      Example1 ex1 = {1, 4};  /* 設置 f1 = 1, f2 = 4 */

5. HMAC和僞隨機函數

        TLS記錄層使用一個有密鑰的信息驗證碼(MAC)來保護信息的完整性。本文中定義的密碼算法族使用了一個被稱爲HMAC(在[HMAC]中描 述)的MAC算法,它基於一個hash函數。如果必要的話其它密碼算法族可以定義它們自己的MAC算法。

        此外,爲了進行密鑰生成或驗證,需要一個MAC算法對數據塊進行擴展以增加機密性。這個僞隨機函數(PRF)將機密信息(secret),種子和 身份標籤作爲輸入,併產生任意長度的輸出。

        在本節中,我們基於HMAC定義了一個PRF。這個使用SHA-256 hash函數的PRF被用於所有的密碼算法族,這些密碼算法在本文中定義,或在本文之前、在TLS1.2的協商階段就發表的TLS文獻中定義。新的密碼算 法族必須顯式指定一個PRF,通常應該將SHA-256或更強的標準hash算法與TLS PRF一同使用。
首先,我們定義一個數據擴展函數,P_hash(secret, data),它使用一個hash函數擴展一個secret和種子,形成任意大小的輸出:

         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次(通過 A(3)),產生96字節的輸出數據;最終迭代產生的最後16字節會被丟棄,留下80字節作爲輸出數據。

         TLS的PRF可以通過將P_hash運用與secret來實現:
                 PRF(secret, label, seed) = P_<hash>(secret, label + seed)

         label是一個ASCII字符串。它應該以嚴格地按照它被給出的內容進行處理,不包含一個長度字節或結尾添加的空字符。例 如,label"slithy toves"應該通過hash下列字節的方式被處理:

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

         (譯註:上述數據是字符串"slithy toves"的十六進制格式)

6.TLS記錄協議

         TLS記錄協議是一個層次化的協議。在每一層中,消息都可能包含長度、描述、內容等域。記錄協議承載被髮送的消息,將數據分片爲可管理的塊,有選擇地壓縮數據,應用MAC,加密,傳輸最終數據。接收到的數據被解密,驗證,解壓縮,重組,然後傳遞給高層客戶。

        本文中描述了4個使用記錄協議的協議:握手協議,告警協議,更改密碼規格協議,和應用數據協議。爲了支持TLS協議擴展,額外的記錄內容類型也可以被記錄協議支持。新的記錄內容類型值被IANA在TLS內容類型註冊(在12節描述)中分配。

        應用不能發送本文沒有定義的記錄類型,除非經過一些擴展的協商。如果一個TLS實現接收到一個非期望的記錄類型,它應該發送一個“unexpected_message”告警消息。

        任何被設計用來使用TLS的協議必須嚴格地設計以處理可能的攻擊。從實踐上來說,者意味着協議設計者必須意識到TLS能夠實現何種安全特性,無法提供或不能安全地依賴後者。

        特別需要注意的是一個記錄消息的類型和長度不能使用加密保護。如果這個信息本身是敏感的,應用設計者可能會希望採取一些措施(填充,覆蓋流量(譯註:原文是“cover traffic”))以減小信息泄露。

6.1 連接狀態

        一個TLS連接的狀態就是TLS記錄協議的操作環境。 它指定了一個壓縮算法,一個加密算法,一個MAC算法。此外,這些算法的參數必須是已知的:用於連接的讀、寫兩個方向的MAC密鑰和塊加密密鑰。 邏輯上總是有4個狀態比較突出:當前讀和寫狀態,掛起的讀和寫狀態。所有的記錄協議都在當前的讀寫狀態下處理。掛起狀態的安全參數可以通過TLS 握手協議來設置,而ChangeCipherSpec可以有選擇地設置當前狀態爲掛起狀態,在這種情況下適當的當前狀態被設置,並被掛起狀態所替 代; 掛起狀態隨後會被重新初始化爲一個空狀態。將一個狀態未經安全參數的初始化就設置爲一個當前狀態是非法的。初始當前狀態一直會指定不使用加密,壓縮或 MAC。
一個TLS連接讀寫狀態的安全參數可以通過提供如下值來設定:
         連接終端
                在這個連接中這個實體被認爲是“client”或“server”。
         PRF算法
                被用於從主密鑰生成密鑰的算法(見5和6.3節)。
         塊加密算法
             被用於塊加密的算法。本規範包含了這種算法的密鑰長度,它是成塊加密,流加密,或AEAD加密,密文的塊大小(如果合適的話),和顯示和隱式初始化向量 (或nonces)的長度
         MAC算法
              被用於消息驗證的算法。本規範包含了MAC算法返回值的長度。
         壓縮算法
               用於數據壓縮的算法。被規範必須包含算法執行壓縮所需的所有信息。
         主密鑰
               在連接的兩端之間共享的48字節密鑰
         客戶端隨機數
               由客戶端提供的32字節隨機數
          服務器隨機數
               由服務器提供的32字節隨機數
         上述參數通過描述語言定義如下:
      enum { server, client } ConnectionEnd;

      enum { tls_prf_sha256 } PRFAlgorithm;

      enum { null, rc4, 3des, aes }
        BulkCipherAlgorithm;

      enum { stream, block, aead } CipherType;

      enum { null, hmac_md5, hmac_sha1, hmac_sha256,
           hmac_sha384, hmac_sha512} MACAlgorithm;

      enum { null(0), (255) } CompressionMethod;

         /* CompressionMethod, PRFAlgorithm,
         BulkCipherAlgorithm, 和 MACAlgorithm 指定的算法可以增加 */  

    struct {
          ConnectionEnd          entity;
          PRFAlgorithm           prf_algorithm;
          BulkCipherAlgorithm    bulk_cipher_algorithm;
          CipherType             cipher_type;
          uint8                  enc_key_length;
          uint8                  block_length;
          uint8                  fixed_iv_length;
          uint8                  record_iv_length;
          MACAlgorithm           mac_algorithm;
          uint8                  mac_length;
          uint8                  mac_key_length;
          CompressionMethod      compression_algorithm;
          opaque                 master_secret[48];
          opaque                 client_random[32];
          opaque                 server_random[32];
      } SecurityParameters;

        記錄層會使用安全參數產生如下的6個條目(其中的一些並不是所有算法都需要的,因此會留空):

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

        當server端接收並處理記錄時會使用client寫參數,反之亦然。使用安全參數來生成這些條目的算法在6.3節中描述。

        一旦安全參數被設定且密鑰被生成,連接狀態就可以將它們設置爲當前狀態來進行初始化。這些當前狀態必須在處理每一條記錄後更新。每個連接狀態包含如下元素:

        壓縮狀態
                壓縮算法的當前狀態

        密碼狀態
                加密算法的當前狀態。這個狀態由連接的預定密鑰組成。對於流密碼,這個狀態也將包含對流數據進行加解密所需的任何必要的狀態信息。
        MAC密鑰
                當前連接的MAC密鑰,以前述方式生成。

        序列號
                每個連接狀態包含一個序列號,讀狀態和寫狀態分別維持一個序列號。當一個連接的狀態被激活時序列號必須設置爲0.序列號的類型是uint64,所以序列號大小不會
超過2^64-1。序列號不能迴繞。如果一個TLS實現需要回繞序列號,則必須重新協商。一個序列號在每條記錄信息被髮送之後增加:特別地,在一個特殊連接狀態下發送的
第一條記錄消息必須使用序列號0.

6.2 記錄層

        TLS記錄層以任意大小的非空塊從高層接收無解釋的數據。

6.2.1. 分片

        記錄層將信息塊分片爲攜帶2^14字節或更小的大塊數據的TLSPlaintext。client信息邊境並不在記錄層保留(即,多個同一內容類型的client信息會被合併成一個TLSPlaintext,或者一個消息會被分片爲多個記錄)。

      struct {
          uint8 major;
          uint8 minor;
      } ProtocolVersion;

      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
            用於處理封裝的分片的高層協議

    version
            協議的版本。本文所描述的TLS 1.2的版本是{3, 3}。版本值3.3是基於歷史的,因爲TLS 1.0使用的是{3, 1}(見附錄A.1.)。需要注意的是一個支持多個版本TLS的client在收到ServerHello之前可能並不知道版本是什麼。關於ClientHello中使用什麼樣的記錄層版本號的討論見附錄E。

    length
              接下來的TLSPlaintext.fragment的長度(以字節計) 。這個長度不能超過2^14.

    fragment
             應用數據。這種數據是透明的並且作爲一個獨立的塊由type域所指定的高層協議來處理。

     實現上不能發送fragments長度爲0的握手,報警,或ChangeCipherSpec內容類型。發送fragment長度爲0的應用數據在進行流量分析時是有用的。

      注意:不同TLS記錄層內容類型的數據可能是交錯的。應用數據的傳輸優先級通常低於其它內容類型。然而, 記錄必須以記錄層能提供保護的順序傳遞到網絡中。接收者必須接收並處理一條連接中在第一個握手報文之後交錯的應用層流量.

6.2.2. 記錄壓縮和解壓縮

        所有的記錄都使用在當前會話狀態中定義的壓縮算法進行壓縮。這裏的壓縮算法必須一直是激活的;然而,初始時它被定義爲CompressionMethod.null。壓縮算法將一個TLSPlaintext結構轉換爲一個TLSCompressed結構,在連接狀態被激活時壓縮函數會由默認狀態信息進行初始化。[RFC3749]描述了用於TLS的壓縮算法.
        壓縮必須是無損的,也不能增加內容的長度超過1024字節。如果解壓函數遇到一個TLSCompressed.fragment,其解壓後的函數超過2^14字節,則必須報告一個fatal壓縮失敗錯誤。
      struct {
          ContentType type;       /* 與TLSPlaintext.type相同 */
          ProtocolVersion version;/* 與TLSPlaintext.version相同 */
          uint16 length;
          opaque fragment[TLSCompressed.length];
      } TLSCompressed;

    length
        接下來的TLSCompressed.fragment的長度(以字節計) 。這個長度不能超過2^14 + 1024.

    fragment
        TLSPlaintext.fragment壓縮後的形態

    注意:一個CompressionMethod.null的操作是恆等操作,不改變任何域。

    實現注意:解壓函數需要保證消息不會導致內部緩存溢出。

6.2.3 記錄載荷保護

       解密和MAC函數將一個TLSCompressed結構轉換爲TLSCiphertext,加密函數實現相反的過程。記錄的MAC包含了一個序列號用於感知丟失、增加和重複的消息。
      struct {
          ContentType type;
          ProtocolVersion version;
          uint16 length;
          select (SecurityParameters.cipher_type) {
              case stream: GenericStreamCipher;
              case block:  GenericBlockCipher;
              case aead:   GenericAEADCipher;
          } fragment;
      } TLSCiphertext;

   type
      這個type域與TLSCompressed.type相同.

   version
      這個version域與TLSCompressed.version相同.

   length
      接下來的TLSCiphertext.fragment的長度(以字節計) 。這個長度不能超過2^14 + 2048.

    fragment
      TLSCompressed.fragment的加密形態, 加上MAC.

6.2.3.1. 空加密或標準流加密

    流加密(包括BulkCipherAlgorithm.null;見附錄A.6)將TLSCompressed.fragment結構轉換爲流的TLSCiphertext.fragment結構,或相反的操作。

        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

        這個記錄的序列號

   MAC

       由SecurityParameters.mac_algorithm指定的MAC算法

        需要注意的是MAC在加密之前計算。流加密算法加密整個塊,包括MAC。對於不使用同步向量的流加密算法(如RC4),流加密算法狀態在一個記錄的結束後就簡單地用於隨後的包。如果密碼算法族是TLS_NULL_WITH_NULL_NULL,加密則由同一性操作構成(即數據不加密,MAC大小是0,意味着不使用MAC)。對於空算法和流加密,TLSCiphertext.length是TLSCompressed.length加上SecurityParameters.mac_length。

6.2.3.2. CBC塊加密

        對於塊加密算法(如3DES或AES),加密和MAC函數將TLSCompressed.fragment轉換爲TLSCiphertext.fragment結構塊或相反的操作。
   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的產生方法與6.2.3.1節相同.

    IV
        初始化向量(IV)應該隨機產生,並且必須是不能預測的。需要注意的是在TLS1.1以前的版本是沒有IV域的。以前的記錄中最後一個密文塊(CBC的剩 餘)被用作IV。使用隨機IV是爲了阻止在[CBCATT]中描述的攻擊。對於塊加密,IV的長度是 SecurityParameters.record_iv_length的值,這個值等於 SecurityParameters.block_size。

    padding
        Padding用於強制明文的長度是塊加密塊長度的整數倍,它可能是任意長度,最長是255字節,只要它使得TLSCiphertext.length是 塊長度的整數倍。超出必要的長度在挫敗基於對交換消息長度的分析進行的協議攻擊時可能是必要的。在padding數據向量中的每個uint8必須 被填充padding的長度值。接收者必須檢查這個pading且必須使用bad_record_mac alert來暗示padding錯誤。

    padding_length
         Padding的長度必須使GenericBlockCipher的總長度是密碼塊長度的整數倍。合法的取值範圍是從0到255,包含0和 255.這個長度指定了padding域的長度但不包含padding_length域的長度。

    密文數據的長度(TLSCiphertext.length)大於SecurityParameters.block_length, TLSCompressed.length, SecurityParameters.mac_length, 和padding_length之和。
例如:如果塊長度是8字節,內容長度(TLSCompressed.length)是61字節,MAC長度是20字節,則填充簽訂長度是82字節 (不包含IV)。爲了使總長度是8字節(塊長度)的偶數倍,填充長度模8必須等於6.即填充長度可以是6, 14, 22, 以此類推, 直到254.如果有必要使填充長度最小,爲6,則填充必須是6字節,每個字節都賦值爲6.因此,GenericBlockCipher在塊加密前的最後8 個字節可能是 xx 06 06 06 06 06 06 06, 這裏xx是MAC的最後一個字節。

        注意:對於CBC模式(密文分組鏈接模式)的塊加密,關鍵的是記錄的整個明文在傳輸任何密文之前就已被知道。否則,攻擊者可能會發動 [CBCATT]中描述的攻擊。
實現註記:Canvel et al. [CBCTIME]闡述了一個基於MAC計算時間的針對CBC填充的定時攻擊。爲了防禦此類攻擊,實現上必須確保物理填充是否正確記錄的處理時間是基本一 樣的。通常,做到這一點最好的方式是即使填充是錯的也要計算MAC,然後只能丟棄整個包。例如,如果填充不正確,實現上可能假定一個0長度的填充 然後計算MAC。這樣會留下一個小的定時通道,因爲MAC計算性能某種程度上依賴於數據分片的長度,但不能確信這個長度會大到足夠被利用,這是因 爲現存MAC的塊大而定時信號的長度小。

6.2.3.3. AEAD加密

        對於AEAD[AEAD]加密(如:[CCM]或[GCM]),AEAD函數將TLSCompressed.fragment結構轉換爲AEAD TLSCiphertext.fragment結構或相反。

        struct {

         opaque nonce_explicit[SecurityParameters.record_iv_length];

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

        AEAD加密的輸入有:單個密鑰,一個nonce,一塊明文,和被包含在驗證檢查中的“額外數據”(在[AEAD]2.1節中描述)。密鑰是 client_write_key或者the server_write_key。不使用MAC密鑰。

        每個AEAD密碼族必須指定提供給AEAD操作的nonce是如何構建的,GenericAEADCipher.nonce_explicit部 分的長度是什麼。在很多情況下,使用在[AEAD]3.2.1節中描述的部分隱藏的nonce技術是合適的;record_iv_length就 是GenericAEADCipher.nonce_explicit的長度。在這種情況下,隱式部分應該作爲client_write_iv和 server_write_iv從 key_block中(在6.3節中描述)推導出來,顯示部分被包含在GenericAEAEDCipher.nonce_explicit中。

        明文是TLSCompressed.fragment。

        額外的驗證數據(我們表示爲additional_data)定義如下:
        additional_data = seq_num + TLSCompressed.type +
                        TLSCompressed.version + TLSCompressed.length;
            這裏“+”表示連接。

        AEAD的輸出由AEAD加密操作所產生的密文輸出構成。長度通常大於TLSCompressed.length,在量上會隨着AEAD加密的不同而不同。因爲加密可能包含填充,開銷的大小可能會因TLSCompressed.length值二不同。每種AEAD加密不能產生大於1024字節的長度擴張。象徵性地,

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

        爲了解密和驗證,加密算法將密鑰、nonce、“額外數據”和AEADEncrypted的值作爲輸入。輸出要麼是明文要麼是解密失敗導致的錯誤。這裏沒有分離完整性檢查。即:
        TLSCompressed.fragment = AEAD-Decrypt(write_key, nonce,
                                            AEADEncrypted,
                                            additional_data)

        如果解密失敗,會產生一個bad_record_mac致命警報。

6.3. 密鑰計算

        記錄協議需要一個算法從握手協議提供的安全參數中生成當前連接狀態(見附錄A.6)所需的密鑰。

        主密鑰被擴張爲一個安全字節序列,它被分割爲一個客戶端寫MAC密鑰,一個服務端寫MAC密鑰,一個客戶端寫加密密鑰,一個服務端寫加密密鑰。它們中的每一個都是從字節序列中以上述順序生成。未使用的值是空。一些AEAD加密可能會額外需要一個客戶端寫IV和一個服務端寫IV(見6.2.3.3節)。
生成密鑰和MAC密鑰時,主密鑰被用作一個熵源。

        爲了生成密鑰數據,計算

            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節中描述的隱式nonce技術生成。

        實現註記:當前定義的密碼協議族使用最多的是AES_256_CBC_SHA256。它需要2 x 32字節密鑰和2 x 32字節MAC密鑰,它們從128字節的密鑰數據中產生。

7. TLS握手協議

        TLS擁有3個子協議用於支持通信雙方協商記錄層安全參數,確認它們自己的身份,實例化以協商的安全參數,彼此報告錯誤狀況。

        握手協議負責協商一個會話,這個會話由以下元素組成:

        session identifier
            由Server端選取的一個任意字節的序列用於辨識一個活動的或可恢復的連接狀態。

        peer certificate
            對端的X509v3 [PKIX]證書。這個元素的狀態可以是空

        compression method

            在加密之前壓縮數據的算法

        cipher spec

        指定用於產生密鑰數據的僞隨機函數(PRF),塊加密算法(如:空,AES等),和MAC算法(如:HMAC-SHA1)。它也定義了密碼學屬性如mac_length.  (常見定義見附錄A.6)

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

        is resumable

            一個用於標識會話是否能被用於初始化新連接的標籤

        這些元素元素隨後會被用於產生安全參數並由記錄層在保護應用數據時使用。利用TLS握手協議的恢復特性,使用相同的會話可以實例化許多連接。

7.1 變更密碼規範協議

        變更密碼規範協議存在的目的是通告加密策略的改變。這個協議由單個消息組成,這個消息會被在當前(並非掛起)連接狀態下被加密和壓縮。這個消息由一個值爲1的單個字節構成。

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

        ChangeCipherSpec消息可以被client和server發送,以通告接收方隨後的記錄消息將會由新協商的密碼規範和密鑰所保護。接收到這個消息會導致接收者指示記錄層立即將讀掛起狀態複製到讀當前狀態。發送此消息後,發送這必須立即指示記錄層將寫掛起狀態轉變爲寫活動狀態(見6.1節)。ChangeCipherSpec消息在握手過程中發送,但要在安全參數協商完畢之後,且在驗證結束消息發送之前。

        注意:如果發生一個重握手事件而連接的數據還在流動,通信的雙方可能使用舊的CipherSpec繼續發送數據。然而,一旦ChangeCipherSpec被髮送了,新的CipherSpec必須被使用。先發送ChangeCipherSpec的一方不知道另外一方已經完成了新密鑰數據的計算(例如,如果它執行一個耗時的公鑰操作)。因此,在接收方必須緩存數據時會存在一個小的窗口時間。事實上,在現代機器中這個間隔會相當短。

7.2 報警協議

        TLS記錄層支持的內容類型之一是報警類型。報警消息傳遞了消息的嚴重程度(警告或致命)和報警的描述。致命類型的報警消息會導致連接的立即結束。在這種情況下,與會話對應的其它連接可以繼續,但會話描述符必須非法化,以阻止失敗的會話被用於建立新的連接。像其它消息一樣,報警消息按照當前連接的狀態指定的那樣被加密和壓縮。

        enum { warning(1), fatal(2), (255) } AlertLevel;
       enum {
          close_notify(0),
          unexpected_message(10),
          bad_record_mac(20),
          decryption_failed_RESERVED(21),
          record_overflow(22),
          decompression_failure(30),
          handshake_failure(40),
          no_certificate_RESERVED(41),
          bad_certificate(42),
          unsupported_certificate(43),
          certificate_revoked(44),
          certificate_expired(45),
          certificate_unknown(46),
          illegal_parameter(47),
          unknown_ca(48),
          access_denied(49),
          decode_error(50),
          decrypt_error(51),
          export_restriction_RESERVED(60),
          protocol_version(70),
          insufficient_security(71),
          internal_error(80),
          user_canceled(90),
          no_renegotiation(100),
          unsupported_extension(110),
          (255)
      } AlertDescription;

      struct {
          AlertLevel level;
          AlertDescription description;
      } Alert;

7.2.1 關閉警報

        客戶端和服務器必須共享連接結束的信息以避免截斷攻擊每一方都可以發起關閉消息的交換
        close_notify
            這個消息通知接收者發送方在這條連接上將不再發送任何消息。像TLS 1.1一樣,正常關閉一條連接失敗不再要求一個會話不能恢復。這個變化從TLS 1.0開始並得到了應用實現的廣泛遵守。

        每一方都可以通過發送一個close_notify警報來發起一個關閉。在收到關閉警報後接收到任何數據都應該被忽略。

        除非傳遞了一些其它致命類型的警報,每一方在關閉連接的寫功能時都需要發送一個close_notify警報。另外一方必須以發送一個字節的close_notify作爲迴應,並立即關閉連接,丟棄任何掛起的寫。不要求關閉的發起者在關閉連接的讀功能前等待對端發送close_notify報警。

        如果使用TLS的應用協議支持在TLS連接關閉之後在底層傳輸連接之上傳輸數據,則TLS實現必須在暗示應用層TLS已經結束之前收到對應的close_notify警報。如果應用協議不再傳輸任何額外的數據,而是僅僅關閉底層傳輸連接,則實現必須選擇關閉連接而不再等待相應的close_notify警報。這個標準任何部分都不能被用於決定TLS管理其數據傳輸的使用模式,包括何時打開或關閉連接。

注意:假定在銷燬傳輸之前關閉一個連接會可靠地投遞掛起的數據。

7.2.2 錯誤警報

         在TLS握手協議中錯誤處理非常簡單。當探測到一個錯誤時,探測方發送一個消息給另一方。發送或接收到一個致命警報消息之後,雙方立即關閉連接。服務端和客戶端必須忘記任何會話描述符,密鑰,和與一個失敗的連接相關的機密信息。因此,任何一個被一個致命警報終結的連接都不能被恢復。

        一個實現無論何時遭遇到一個被定義爲致命警報的消息時,它必須在關閉者連接之前發送合適的警報。對於所有警報級別沒有顯式指定的錯誤,發送方可以自行決定是否將其作爲致命錯誤對待。如果實現選擇發送一個警報但意圖隨後立即關閉連接,它必須以致命警報等級發送這個警報。

        如果收到一個警告級別的警報時,通常連接可以正常繼續。如果接收方決定不再繼續連接(例如,收到一個它不願意接收的no_renegotiation警報),它應該發送一個致命警報終結連接。鑑於此,發送防通常不會知道接收方會有何行爲。因此,警告類警報在發送方向繼續連接時不是很有用,並且因此有時會被忽略。例如,如果一個對端決定接受一個證書過期警報(也許是在與用戶確認之後)並想繼續連接,它通常不會發送一個certificate_expired警報。

        定義瞭如下類型的錯誤警報:

        unexpected_message
            收到一個不合適的消息。這個警報一直是致命類型且不應該在正確的實現之間被觀察到。

        bad_record_mac
           如果收到一個記錄其MAC是不正確的,則會返回這種警報。當因爲一個TLSCiphertext以不正確的方式解密(或者它不是塊長度的偶數倍,或它的填充值被檢查出不正確)而發送一個警報時此類警報也必須發送。這個消息通常是致命類型並且不應該在正確的實現之間被觀察到(除非消息在網絡中損壞)。

        decryption_failed_RESERVED

            這種警報被用於一些早期版本的TLS,且可能導致針對CBC模式的特定攻擊。在兼容型實現中不能發送此消息。

        record_overflow

            收到一個TLSCiphertext的消息其長度大於2^14+2048字節,或一個記錄被解密爲TLSCompressed後其長度大於2^14+1024字節。這個消息通常是致命類型並且不應該在正確的實現之間被觀察到(除非消息在網絡中損壞)。

        decompression_failure

            解壓縮函數收到不正常的輸入(例如, 數據擴展爲過多的長度).這個消息通常是致命類型並且不應該在正確的實現之間被觀察到(除非消息在網絡中損壞)

        handshake_failure
            收到 handshake_failure警報消息意味着在給定選項時發送方不能協商一個可接受的安全參數集。這是個致命錯誤。

        no_certificate_RESERVED
            這個警報用於SSLv3但不是任何版本的TLS。在兼容型實現中不能發送此消息。

        bad_certificate
            證書被損壞,包含的簽名無法正確驗證等。

        unsupported_certificate
            證書是不支持的類型

        certificate_revoked
            證書被其簽名者撤銷

        certificate_expired
            證書過期或當前無效

        certificate_unknown
            在處理證書時產生了一些其它(未指定)問題,導致其無法接受

       illegal_parameter
            在握手階段一個域的值超出合法範圍或與其它的域不一致。這個消息一直是致命的。

       unknown_ca
            一個有效的證書鏈或部分鏈被接受,但證書沒有被接受,因爲CA證書不能被定位或不能與一個知名的、可信任的CA匹配。這個消息一直是致命的。

       access_denied
            接收到一個有效的證書, 但應用訪問控制時, 發送方決定不繼續協商. 這個消息一直是致命的。

       decode_error
            由於一些域超出指定範圍或消息長度不正確導致消息不能被解碼. 這個消息通常是致命類型的且絕不能在兩個合理的TLS實現之間通信時出現(除非消息在網絡中損壞)

       decrypt_error
            一個握手密文操作失敗, 包括不能正確驗證簽名或一個結束消息. 這個消息一直是致命的。

       export_restriction_RESERVED
            這個alert曾被用於一些TLS的早期版本. 在兼容實現中不能發送此消息.

       protocol_version
           Client端試圖協商的協議版本號版本被支持(例如, 舊的協議版本由於安全原因被廢棄). 這個消息一直是致命的。

        insufficient_security
            當一個協商由於server需要比client能夠支持的更安全的算法族而失敗時取代handshake_failure消息返回, 這個消息一直是致命的.

        internal_error
            一個與對端或協議正確性都無關的內部錯誤(例如內存分配錯誤)使得協議無法繼續執行.這個消息一直是致命的.

        user_canceled
            這次握手由於一些與協議錯誤無關的原因被取消.如果在握手完成後用戶才取消操作,只通過發送一個close_notify消息來關閉連接更合適. 這個alert應該跟隨一個close_notify. 這個消息通常是一個警告.

       no_renegotiation
            由客戶端發送用於響應一個hello請求,或由服務端發送用於在初始化握手時響應一個client hello.二者中的任何一個都通常會導致重協商;當重協商不合適時, 接收端應答用此警報來響應.這時,原始請求者能決定是否繼續連接.一種適當的情況是一個server產生一個進程以滿足一個請求;這個進程能在啓動時接收安全參數(密鑰長度,認證等),在這個階段之後再修改這些參數則可能會很困難.這個消息通常是一個警告.

       unsupported_extension
            由客戶端發送;該客戶端接收到了server hello消息中包含的一個擴展,但這些擴展不能被放入相應的client hello消息中.這個消息一直是致命的.

        新的Alert的值在12章中由IANA指定.

7.3.  握手協議概覽

        會話狀態的加密參數由TLS握手協議產生, 這個協議在TLS記錄層之上運行. 當一個TLS client和server開始通信時, 它們就協議版本達成一致, 選擇加密算法, 彼此選擇驗證, 使用公鑰加密技術產生共享密鑰.

        TLS握手協議包含如下幾步:
            - 交互Hello消息以協商算法, 交互隨機數, 檢查會話恢復.
            - 交互必要的密碼參數以允許client和server協商預主密鑰
            - 交換證書和密碼信息以允許client和server進行身份認證
            - 從預主密鑰和交互的隨機數中產生主密鑰
            - 提爲記錄層供安全參數
            - 允許client和server驗證它們的對端已經計算出了相同的安全參數, 而且握手過程不被攻擊者篡改.

         需要注意的是更高層不能過度依賴TLS是否一直爲連接雙方協商最強的連接.中間人攻擊者有很多方法能夠使兩個協商者降級到使用它們能夠支持的最低的安全方法. 協議被用來最小化這種風險, 但仍然會存在攻擊: 例如, 一個攻擊者能夠阻止訪問一個安全服務運行的端口, 或試圖使對端協商一個未經認證的連接. 基礎的規則是更高層必須認識到它們的安全需求是什麼, 且絕對不能在一個不滿足它們的安全需求的通道上傳輸信息. 如果任何密碼族能夠提供它們承諾的安全等級則TLS協議是安全的: 如果你使用一個1024位的RSA密鑰交換和驗證過證書的主機來協商3DES, 你可以期待它是安全的. 

        這些目標的達成是靠握手協議實現的, 這個協議總結如下: client發送一個ClientHello消息, server必須迴應一個ServerHello消息或產生一個驗證錯誤並且連接會失敗. ClientHello和ServerHello用於在client和server之間建立安全性增強的能力. ClientHello和ServerHello建立了如下的屬性: 協議版本, 會話ID, 密碼協議族, 壓縮算法. 此外, 產生並交換兩個隨機數: ClientHello.random和ServerHello.random.

        實際的密鑰交換使用了最多4個消息: server Certificate, ServerKeyExchange, client Certificate,和ClientKeyExchange.新的密鑰交換方法可以通過這些方法產生:爲這些消息指定一個格式, 並定義這些消息的用法以允許client和server就一個共享密鑰達成一致. 這個密鑰必須很長;當前定義的密鑰交換方法交換的密鑰大於46字節.

        在hello消息之後, server會在Certificate消息中發送它自己的證書, 如果它即將被認證. 此外, 一個ServerKeyExchange消息會被髮送, 如果需要的話(例如, 如果server沒有證書, 或者它的證書只用於簽名).如果server被認證過了, 它可能會要求client發送證書, 如果對於已選擇的密碼協議族來說是合適的話.接下來, server會發送ServerHelloDone消息, 意味着握手的hello消息階段完成. server將會等待client的響應. 如果server以及發送了一個CertificateRequest消息, client必須發送Certificate消息. 現在ClientKeyExchange消息需要發送, 這個消息的內容取決於ClientHello和ServerHello之間選擇的公鑰算法. 如果client發送了一個帶簽名能力的證書, 一個數字簽名的CertificateVerify消息需要發送以顯式驗證證書中私鑰的所有權.

        這時, client發送一個ChangeCipherSpec消息, 並且複製待定的Cipher Spec到當前的Cipher Spec中. 然後client在新算法, 密鑰確定後立即發送Finished消息. 作爲迴應, server會發送它自己的ChangeCipherSpec消息, 將待定的Cipher Spec轉換爲當前的Cipher Spec, 在新的Cipher Spec下發送Finished消息. 這時, 握手完成, client和server可以開始交換應用層數據(見下面的流程圖). 應用數據一定不能在第一個握手完成前(在一個非TLS_NULL_WITH_NULL_NULL類型的密碼協議族建立之前)發送.

      Client                                               Server

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

             Figure 1.  一個完整的握手消息流程

        * 意味着可選或並不會一直被髮送的條件依賴性消息.

        註記: 爲了有助於避免pipeline stalls, ChangeCipherSpec是一種獨立的TLS協議內容類型, 並且事實上不是一種TLS消息.

        當client和server決定繼續一個以前的會話或複製一個現存的會話(取代協商新的安全參數)時, 消息流如下:

        Client使用需要恢復的當前會話的ID發送一個ClientHello. Server檢查它的會話緩存以進行匹配. 如果匹配成功, 並且server願意在指定的會話狀態下重建連接, 它將會發送一個帶有相同會話ID值的ServerHello消息. 這時, client和server必須都發送ChangeCipherSpec消息並且直接發送Finished消息. 一旦重建立完成, client和server可以開始交換應用層數據(見下面的流程圖). 如果一個會話ID不匹配, server會產生一個新的會話ID, 然後TLS client和server會完成一個完整的握手.
      Client                                                Server

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

          Figure 2.  一個簡化的握手的消息流程

   每個消息的內容和含義會在下面的章節中詳細闡述.

7.4.  握手協議

        TLS握手協議是TLS記錄協議的一個已定義的高層客戶端. 這個協議用於協商一個會話的安全屬性. 握手消息提供給TLS記錄層, 這裏它們會被封裝在一個或多個TLSPlaintext結構中, 這些結構按照當前活動會話狀態所指定的方式被處理和傳輸.

      enum {
          hello_request(0), client_hello(1), server_hello(2),
          certificate(11), server_key_exchange (12),
          certificate_request(13), server_hello_done(14),
          certificate_verify(15), client_key_exchange(16),
          finished(20), (255)
      } HandshakeType;

      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;

        握手協議消息在下文中會以發送的順序展現;以未期望的順序發送握手消息會導致一個致命錯誤。然而,不需要的握手消息會被忽略。需要注意的是例外的順序是:證書消息在握手(從server到client,然後從client到server)過程中會使用兩次,但只在它第一次出現的位置處描述。不被這些順序所約束的一個消息是HelloRequest消息,它可以在任何時間發送,但如果在握手中間到達應該被client忽略。
        新的握手消息類型由IANA指定,正如12節中所描述的。

7.4.1.  Hello消息

        hello階段的消息用於在client和server之間交互安全增強能力。當一個新的會話開始時,記錄層連接狀態加密,hash,和壓縮算法被初始化爲空。當前連接狀態用於重協商消息。

7.4.1.1.  Hello Request

        當這個消息即將被髮送時:
            HelloRequest消息可以在任何時間由server發送。
        這個消息的含義:
            HelloRequest是一個簡單的通告client應該開始重協商流程。 在響應過程中,client應該在方便的時候發送一個ClientHello消息。這個消息並不是意圖確定哪端是client或server,而僅僅是發起一個新的協商。server不應該在client發起連接後立即發送一個HelloRequest。這時發送一個ClientHello消息是client的工作。

        如果client當前正在協商一個會話時這個消息會被client忽略。 這個消息會被client忽略,如果client不想重新協商一個會話,或client希望響應一個no_renegotiation警報。因爲握手消息意圖先於應用數據被傳送, 它希望協商會在少量記錄消息被client接收之前開始。 如果server發送了一個HelloRequest但沒有收到一個ClientHello響應,它應該用一個致命警報關閉連接。
        在發送一個HelloRequest之後, server不應該重複這個請求直到隨後的握手協商完成。

        這個消息的結構:

              struct { } HelloRequest;

       這個消息不能被包含在握手消息中維護的消息hash中, 也不能用於結束的消息和證書驗證消息。

7.4.1.2.  Client Hello

當這個消息被髮送時:

        當一個client第一次連接一個server時, 它被要求發送ClientHello作爲第一個消息。 Client也能發送一個ClientHello作爲對HelloRequest的響應,或用於自身的初始化以便在一個已有連接中重新協商安全參數。

        這個消息的結構是:
        ClientHello消息包含一個隨機數據結構, 它會隨後被用於協議中.

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

      gmt_unix_time
依據發送者內部時鐘以標準UNIX 32位格式表示的當前時間和日期(從1970年1月1日UTC午夜開始的秒數, 忽略閏秒). 基本TLS協議不要求時鐘被正確設置; 更高層或應用層協議可以定義額外的需求. 需要注意的是, 出於歷史原因, 數據元素使用格林尼治時間命名, 它是當前時間通用時間基準世界協調時間(UTC)的前任.

      random_bytes
         由一個安全的隨機數生成器產生的28個字節數據.

      ClientHello消息包含一個變長的會話標識符. 如果非空, 這個值標識了同一對client和server之間的會話, client希望重新使用這個會話中server的安全參數. 

      會話標識符可能來自於一個早期的連接, 本次連接, 或來自另一個當前活動的連接. 第二個選擇是有用的, 如果client只是希望更新隨機數據結構並且從一個連接中導出數值; 第三個選擇使得在無需重複全部握手協議的情況下就能夠建立若干獨立的安全連接.這些獨立的連接可能先後或同時建立. 一個SessionID在握手協商完成成爲有效的, 通過交互Finished消息得以完善, 並堅持到由於老化或在一個與會話有個的連接上遭遇致命錯誤導致它被刪除爲止. SessionID的實際內容由server定義.

       opaque SessionID<0..32>;

        警告: 由於SessionID在傳輸時沒有加密或直接的MAC保護, server一定不能將機密信息放在會話標識符中或使僞造的會話標識符的內容違背安全原則.(需要注意的是握手的內容作爲一個整體, 包括SessionID, 是由在握手結束時交換的Finished消息保護的).

         密碼族列表, 在ClientHello消息中從client傳遞到server, 以client所傾向的順序(最喜愛的在最先)包含了client所支持的密碼算法. 每個密碼族定義了一個密鑰交互算法, 一個塊加密算法(包括密鑰長度), 一個MAC算法, 和一個隨機數生成函數. Server將選擇一個密碼協議族, 如果沒有可以接受的選擇, 在返回一個握手失敗警報然後關閉連接. 如果列表包含了server不能識別, 支持或希望使用的密碼協議族, server必須忽略它們, 並正常處理其餘的部分. 
      uint8 CipherSuite[2];    /* Cryptographic suite selector */

      ClientHello保護了client所支持的壓縮算法列表, 按照client的傾向排序. 

       enum { null(0), (255) } CompressionMethod; 

       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;

    TLS 允許在compression_methods域之後的extensions塊中添加擴展. 通過查看compression_methods後面是否有多餘的字節在ClientHello結尾處就能探測到擴展的存在. 需要注意的是這種探測可選數據的方法與正常的TLS變長域不一樣, 但它用於與TLS一起定義的擴展兼容.

   client_version
        client願意在本次會話中使用的TLS協議的版本. 這個應當是client所能支持的最新版本(值最大), 對於本規範來說, 這個版本應該是3.3(關於後向兼容性的細節見附錄E).

   random
      一個client所產生的隨機結構.

   session_id
      Client希望在本次連接中所使用的會話ID. 如果沒有session_id或client想生成新蛋安全參數, 則這個域是空.

   cipher_suites
      Client所支持的密碼選項列表, client最傾向使用的排在最先. 如果session_id域不空(意味着一個會話恢復請求), 這個向量必須至少包含那條會話中的cipher_suite. 數值在附錄A.5中定義.

   compression_methods

        這是client所支持的壓縮算法的列表, 按照client所傾向的順序排列. 如果session_id域不空(意味着一個會話恢復請求), 它必須包含那條會話中的compression_method.這個向量中必須包含, 所有的實現也必須支持CompressionMethod.null. 因此, 一個client和server將一直能就壓縮算法協商一致.


   extensions
      Clients可以通過在擴展域中發送數據來請求server的擴展功能. 實際的"Extension"的格式在7.4.1.4節中定義.

   如果一個client使用擴展來請求額外的功能, 並且這個功能Server並不支持, 則client可以中止握手. 一個server必須接受帶有或不帶擴展域的ClientHello消息, 並且(對於其它所有消息也是一樣)它必須檢查消息中數據的數量是否精確匹配一種格式; 如果不是, 它必須發送一個致命"decode_error"警報.

   發送ClientHello消息之後, client會等待ServerHello消息. Server返回的任何握手消息, 除HelloRequest外, 均被作爲一個致命錯誤.

7.4.1.3. Server Hello

   當這個消息被髮送時:

        Server將發送這個消息作爲對ClientHello消息的響應, 當它能夠找到一個可接受的算法集時. 如果不能找到這樣的算法集, 它會發送一個握手失敗警報作爲響應.

    這個消息的結構是:
      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;

    通過查看compression_methods後面是否有多餘的字節在ServerHello結尾處就能探測到擴展的存在.

    server_version

        這個域將包含client在client hello消息中建議的較低版本和server所能支持的最高版本. 本規範中的版本是3.3. (關於後向兼容性的細節見附錄E)
   random

        這個結構由server產生並且必須獨立於ClientHello.random.

    session_id

        這是與本次連接相對應的會話的標識. 如果ClientHello.session_id非空, server將在它的會話緩存中進行匹配查詢. 如果匹配項被找到, 且server願意使用指定的會話狀態建立新的連接, server會將與client所提供的相同的值反饋回去. 這意味着恢復了一個會話並且規定雙方必須在Finished消息之後繼續進行通信. 否則這個域會包含一個不同的值以標識新會話. Server會返回一個空的session_id以顯示會話將不再被緩存從而不會被恢復. 如果一個會話被恢復了, 它必須使用原來所協商的密碼協議族. 需要注意的是沒有要求server恢復任何會話, 即使它之前提供了一個session_id.Client必須準備好進行一次完整的協商 -- 包括協商新的密碼協議族-- 在任意一次握手中. 

        由server在ClientHello.cipher_suites中所選擇的單個密碼族. 對於被恢復的會話, 這個域的值來自於被恢復的會話狀態.

   compression_method
        由server在ClientHello.compression_methods所選擇的單個壓縮算法. 對於被恢復的會話, 這個域的值來自於被恢復的會話狀態.

   extensions
        擴展的列表. 需要注意的是隻有由client給出的擴展才能出現在server的列表中.

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" 包含的信息卻決於特定的擴展類型.

    擴展的初始集合在一個文檔[TLSEXT]中定義.The initial set of extensions is defined in a companion document[TLSEXT].  擴展類型列表由INAM賦值維護,詳見12節.

    一個擴展不能出現在ServerHello中除非同樣的擴展類型出現在對於的ClientHello中. 如果一個client在ServerHello中收到一個擴展類型但在相關的ClientHello中並沒有請求, 它必須用一個unsupported_extension致命警報來丟棄握手.

    儘管如此, "面向server"的擴展將來可以在這個框架中提供. 這樣的一個擴展(比如, 類型x的擴展)可能要求client首先發送一個類型x的擴展在ClientHello中, 並且extension_data爲空以表示它支持擴展類型. 在這個例子中, client提供了理解擴展類型的能力, server基於client提供的內容與其進行通信.

    當ClientHello或ServerHello中有多個不同類型的擴展存在時, 這些擴展可能會以任意順序出現. 一個類型不能擁有超過一個擴展.

    最後, 需要注意的是擴展可能在開始一個新會話和要求恢復一個會話是發送. 的確, 一個請求恢復會話的client通常不會知道server是否會接受這個請求, 因此它應該像它不打算回覆會話時那樣發送擴展.

    通常, 每個擴展類型的規範需要描述擴展對全部握手流程和會話恢復的影響. 大多數當前的TLS擴展僅當一個會話被初始化時纔是相關聯的: 當一箇舊的會話被恢復時, server不會處理Client Hello中的擴展, 也不會將其包含在Server Hello中. 然而, 一些擴展可以在會話恢復時指定不同的行爲.

    在這個協議的新特性與現存特性之間會有一些敏感(以及不很敏感)的交互產生, 這可能會導致整體安全性的顯著降低. 當設計新的擴展時應考慮下列事項:

-  一些情況下一個server沒有就一個擴展協商一致是錯誤情況,  一些情況下則簡單地拒絕支持特定特性. 通常,錯誤警報應該用於前者, server擴展中的一個域用於響應後者.

-  擴展應該儘可能在設計上阻止任何通過操縱握手消息來強制使用(或不使用)一個特殊特性進行的攻擊. 無論這個特性是否被確認會導致安全問題, 這個原則都應該被遵循.
 
通常擴展域擴展域都會被包含在Finished消息的hash輸入中, 但需要給予極大關注的是在握手階段擴展改變了發送消息的含義. 設計者和實現者應該注意的事實是, 握手被認證後, 活動的攻擊者才能修改消息並插入, 移動或替換擴展.

   -  使用擴展來改變TLS設計的主要方面在技術上是可能的; 例如密碼族協商的設計. 這種做法並不被推薦; 更合適的做法是定義一個新版本的TLS -- 尤其是TLS握手算法有特定的保護方法以防禦基於版本號的版本回退攻擊, 版本回退攻擊的可能性應該在任何主要的修改設計中都是一個有意義的考量.

7.4.1.4.1. 簽名算法
        Client使用"signature_algorithms"擴展來向server表明哪個簽名/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值都列出了一個client願意使用的hash/簽名對.這些值根據傾向使用的程度按降序排列.

   注: 由於並不是所有的簽名算法和hahs算法都會被一個實現所接受(例如: DSA接受SHA-1, 不接受SHA-256), 所有算法是按對列出.

   hash
這個域表明可能使用的hash算法. 這些值分別表明支持無hash, MD5, SHA-1, SHA-224, SHA-256, SHA-384, 和SHA-512. "none"值用於將來的可擴展性, 以防一個簽名算法在簽名之前不需要hash.

   signature
      這個域表明使用哪個簽名算法. 這些值分別表示匿名簽名, RSASSA-PKCS1-v1_5, DSA和ECDSA. "anonymous"值在這個上下文中是無意義的, 但會在7.4.3節中使用. 它不能出現在這個擴展之中.
    這個擴展的語義某種程度上有些複雜, 因爲密碼族表明允許的簽名算法而不是hash算法. 7.4.2和7.4.3節描述了合適的規則.

    如果client只支持默認的hash和簽名算法(本節中所列出的), 它可以忽略signature_algorithms擴展. 如果client不支持默認的算法, 或支持其它的hash和簽名算法(並且它願意使用他們來驗證server發送的消息, 如:server certificates和server key exchange), 它必須發送signature_algorithms擴展, 列出它願意接受的算法.

    如果client不發送signature_algorithms擴展, 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}.

    注: 這個對於TLS 1.1是一個變更, 且沒有顯式的規則, 但在實現上可以假定對端支持MD5和SHA-1.

   注: 這個擴展對早於1.2版本的TLS是沒有意義的, 對於之前的版本Client不能這個擴展. 然而, 即使client提供了這個擴展, [TLSEXT]中明確的規則要求server如果不能理解擴展則忽略之. 

    Server不能發送此擴展, TLS server必須支持接收此擴展.

    當進行會話恢復時, 這個擴展不能被包含在Server Hello中, 且server會忽略Client Hello中的這個擴展(如果有).

7.4.2. Server證書

    當這個消息即將被髮送時:

    server必須發送一個Certificate,無論何時協商一致的密鑰交換算法使用證書進 行認證(包括除DH_anon外本文中定義的所有密 鑰交互算法)。 這個消息一直是 緊隨在ServerHello消息之後。
    這個消息的含義是:

    這個消息傳達了server的證書鏈給client.

    證書必須適用於已協商的密碼族的密鑰交互算法和任何已協商的擴展。

    這個消息的結構是:
      opaque ASN.1Cert<1..2^24-1>;

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

   certificate_list

    這是一個證書序列(鏈)。發送者的證書必須在列表的第一個位置。每個隨後的證 書必須直接證明它前面的證書。 因爲證書驗證需要被獨立發佈的根密鑰, 確定了 根證書權威的自簽名證書可以被在鏈中忽略, 如果遠程終端已經擁有了它以便在 任何情況下來驗證它。 

    相同的消息類型和結果將用於client端對一個證書請求消息的響應. 需要注意的是一個client可能不發送證書, 如果它沒有合適的證書來發送以響應server的認證請求.

    注: PKCS #7不會被用做證書向量的格式因爲PKCS #6擴展的證書沒有被使用. 同樣, PKCS #7定義了一個集合而非一個序列, 使得解析列表的任務變得更難完成.

    如下的規則會被應用於server發送的證書:
   -  證書類型必須是X.509v3, 除非顯式協商了其它的類型(如, [TLSPGP]).
   -  終端實體證書的公鑰(和相關的限制)必須與選擇的密鑰交互算法兼容.
      密鑰交換算法.       證書類型
      RSA                      RSA公鑰; 證書必須允許密鑰用於加密(keyEncipherment位必須被設置, 如果密鑰使用擴展存在的話).
      RSA_PSK            注:RSA_PSK 定義於[TLSPSK]

      DHE_RSA            RSA公鑰;證書必須允許密鑰使用server密鑰交互消息中的簽名機制和hash算法進行簽名
      ECDHE_RSA       (如果密鑰用法擴展存在的話,digitalSignature位必須設置)
                                   注: ECDHE_RSA定義於[TLSECC].

      DHE_DSS            DSA公鑰; 證書必須允許密鑰使用server密鑰交互消息中的簽名機制和hash算法進行簽名

      DH_DSS             Diffie-Hellman公鑰; 如果密鑰用法擴展存在的話,keyAgreement位必須設置
      DH_RSA             

      ECDH_ECDSA      ECDH-capable公鑰; 公鑰必須使用一個能夠被client支持的曲線和點格式, 正如[TLSECC]中描述的那樣
      ECDH_RSA           

      ECDHE_ECDSA    ECDSA-capable公鑰; 證書必須允許密鑰使用server密鑰交互消息中的簽名機制和hash算法進行簽名;
                                     公鑰必須使用一個能夠被client支持的曲線和點格式, 正如[TLSECC]中描述的那樣

   -  "server_name"和"trusted_ca_keys"擴展[TLSEXT]被用於指導證書選擇.

      如果client提供了一個"signature_algorithms"擴展, 則所有由server提供的證書必須由出現在這個擴展中的一個hash/簽名算法對進行簽名. 需要注意的是這意味着一個包含了一個簽名算法密鑰的證書應該被一個不同的簽名算法簽名(例如, RSA密鑰被DSA密鑰簽名). 這個與TLS 1.1不同, 後者要求算法是相同的. 需要注意的是這也意味着DH_DSS, DH_RSA, ECDH_ECDSA, 和ECDH_RSA密鑰交換算法並不限制用於對證書籤名的算法. 固定的DH證書可以被出現在擴展中的任意hash/簽名算法對簽名. DH_DSS, DH_RSA, ECDH_ECDSA, 和ECDH_RSA是歷史上的名稱.

    如果server有多個證書, 它基於上述標準(此外其它的標準有:傳輸層端點, 本地配置和偏好等)選擇其中一個.如果server只有一個證書, 它應該嘗試使這個證書符合這些標準.

    需要注意的是有很多證書使用無法與TLS兼容的算法或算法組合. 例如, 一個使用RSASSA-PSS簽名密鑰的證書(在SubjectPublicKeyInfo中是id-RSASSA-PSS OID)不能被使用因爲TLS沒有定義相應的簽名算法.

    正如密鑰族指定了用於TLS協議的新的密鑰交換方法, 它們也指定了證書格式和要求的編碼的按鍵信息.

7.4.3. Server密鑰交換消息

    當這個消息即將被髮送時:

    這個消息會緊隨在server證書消息之後發送(或erverHello消息, 如果是一個匿名協商的話);

    ServerKeyExchange消息由server發送, 但僅在server證書消息(如果發送了)沒有包含足夠的數據以允許client交換一個預密鑰時. 這個限制對於如下的密鑰交換算法是成立的:

         DHE_DSS
         DHE_RSA
         DH_anon

    對於如下密鑰交換算法發送ServerKeyExchange是非法的:

         RSA
         DH_DSS
         DH_RSA

    其它的密鑰交換算法, 如在[TLSECC]中所定義的那些, 必須指定是否發送ServerKeyExchange; 如果消息發送了, 則必須指定發送內容.

    這個消息的含義是:

    這個消息傳遞了密碼信息以允許client就預主密鑰進行交互: 一個client用於完成一個密鑰交換的Diffie-Hellman公鑰(結果就是預主密鑰)或一個其它算法的公鑰

    這個消息的結構是:

      enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa
            /* 可以被擴展, 例如, 對於ECDH -- 見 [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;     /* 瞬時DH參數 */

      dh_p

        用於Diffie-Hellman操作的素模數

     dh_g

        用於Diffie-Hellman操作的生成器

     dh_Ys

        Server的Diffie-Hellman公開數值 (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 {} ;
                 /* 消息忽略rsa, dh_dss, 和dh_rsa */
              /* 可以被擴展, 例如, 對於ECDH -- 見 [TLSECC] */
          };
      } ServerKeyExchange;

      params
         Server密鑰交互參數

      signed_params
         對於非匿名密鑰交換, 這是一個對server密鑰交互參數的簽名

    如果client已經提供了"signature_algorithms"擴展, 簽名算法和hash算法必須成對出現在擴展中. 需要注意的是這裏可能會有不一致的可能, 例如, client可能提供DHE_DSS密鑰交換但在"signature_algorithms"擴展中忽略任何與DSA配對的組合.爲了達成正確的協商, server必須在選擇密碼族之前檢查任何"signature_algorithms"擴展之外的候選密碼族. 這在某種程度上並不優雅, 但卻是一個折中方案, 用以最小化對原始密碼族設計的修改.

    此外, hash和簽名算法必須與位於server的終端實體證書中的密鑰相兼容. RSA密鑰可以與任何允許的hash算法配合使用, 並服從任何證書的約束(如果有的話).

    由於DSA簽名不包含任何安全的表明hash算法類型的方式, 如果多個hash可以與任何密鑰共同使用時會存在hash被替換的風險(譯者注: 不理解). 當前, DSA[DSS]可以只與SAH-1一起使用. 將來修訂版的DSS [DSS-3]可以預期允許DSA與使用其它的摘要算法一起使用, 正如摘要算法應對與每個密鑰的大小進行配合的指導原則一樣. 此外, 將來修訂版的[PKIX]可以指定證書機制以表明哪些摘要算法將與DSA一起使用.

    作爲額外爲TLS定義的包含新的密鑰交換算法的密碼族, server密鑰交換消息會被髮送, 當且僅當與密鑰交互算法關聯的證書類型沒有提供足夠的信息供client交換一個預主密鑰.

7.4.4. 證書請求

        當這個消息即將被髮送時:

        一個非匿名的server能有選擇地請求一個client發送的證書, 如果選定的密碼族合適的話. 這個消息, 如果發送了, 將緊隨在ServerKeyExchange消息之後(如果發送了; 否則, 這個消息跟隨在server的證書消息之後).

        這個消息的結構是:
        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_types

      client可以提供的證書類型的列表.
        rsa_sign        一個包含RSA密鑰的證書
        dss_sign        一個包含DSA密鑰的證書
        rsa_fixed_dh    一個包含靜態DH密鑰的證書
        dss_fixed_dh    一個包含靜態DH密鑰的證書

      supported_signature_algorithms

        一個hash/簽名算法對列表供server選擇, 按照偏好降序排列

      certificate_authorities

      可接受的certificate_authorities著名名稱[X501]的列表, 以DER編碼的格式體現. 這些著名的名稱可以爲一個根CA或一個次級CA指定一個期望的著名名稱; 因此, 這個消息可以被用於描已知的根述和期望的認證空間. 如果certificate_authorities列表爲空, 則client可以發送ClientCertificateType中的任意證書, 除非有一些屬於相反情況的外部設定. 

        certificate_types和supported_signature_algorithms域的交互關係某種程度上有些複雜, certificate_type自從SSLv3開始就在TLS中存在, 但某種程度上並不規範. 它的很多功能被supported_signature_algorithms所取代. 應用下述規則:

        - Client提供的任何證書必須使用在supported_signature_algorithms中存在的hash/簽名算法對來簽名

        - Clinet提供的終端實體的證書必須包含一個與certificate_types兼容的密鑰. 如果這個密鑰是一個簽名密鑰, 它必須能與supported_signature_algorithms中的一些hash/簽名算法對一起使用

        - 出於歷史原因, 一些client證書類型的名稱包含了簽名證書的算法. 例如, 在早期版本的TLS中, rsa_fixed_dh意味着一個用RSA和包含一個靜態DH密鑰簽名的證書. 在TLS 1.2中, 這個功能被supported_signature_algorithms廢除, 證書類型不再限制簽名證書的算法. 例如, 如果server發送了dss_fixed_dh證書類型和{{sha1, dsa}, {sha1, rsa}}簽名類型, client可以回覆一個包含一個靜態DH密鑰的證書, 用RSA-SHA1簽名

        新的ClientCertificateType值由INAN指定, 在12節中描述.

        注: 被列爲保留類型的值不能被使用. 它們在SSLv3中使用.

        注: 一個匿名server請求認證client會產生一個致命的handshake_failure警告.

7.4.5. Server Hello Done

        當這個消息將被髮送時:

        ServerHelloDone消息已經被server發送以表明ServerHello及其相關消息的結束. 發送這個消息之後, server將會等待從client發送的響應.

        這個消息的含義:

        這個消息意味着server發送完支持密鑰交換的消息, client能繼續它的密鑰交換處理.

        在收到ServerHelloDone消息之後, client應當驗證server提供的是否是有效的證書, 如果有要求的話, 檢查server hello參數是否可以接受.

        這個消息的結構:

        struct { } ServerHelloDone;

7.4.6. Client證書

        當這個消息將被髮送時:

        這是client在收到一個ServerHelloDone消息後發送的第一個消息. 這個消息只能在server請求一個證書時發送. 如果沒有合適的證書, client必須發送一個不帶證書的證書消息. 即, certificate_list結構體的長度是0. 如果client不發送任何證書, server可以自行決定或者繼續握手不驗證client, 或者回復一個致命handshake_failure警報. 而且, 如果證書鏈某些方面不能接受(例如, 它沒有被一個知名的可信CA簽名), server可以自行決定繼續握手(考慮到client無認證)或發送一個致命警報.

        Client證書使用7.4.2節中定義的Certificate結構發送.

        這個消息的含義:

        這個消息傳遞client的證書鏈給server; 當驗證CertificateVerify消息時(當client的驗證基於簽名時)server會用它來驗證或計算預主密鑰(對於非瞬時Diffie-Hellman). 證書必須適用於已協商的密碼族的密鑰交換算法, 和任何已協商的擴展.

        尤其是:

        - 證書類型必須是X.509v3, 除非顯示協商其它類型(例如, [TLSPGP]).

        - 終端實體證書的公鑰(和相關的限制)應該與列在CertificateRequest中的證書類型兼容:

        Client Cert. Type  證書密鑰類型
        rsa_sign                RSA公鑰;證書必須允許這個密鑰被用於簽名, 並與簽名方案和hash算法一起被用於證書驗證消息.
        dss_sign               DSA公鑰;證書必須允許這個密鑰被用於簽名, 並與hash算法一起被用於證書驗證消息.
        ecdsa_sign           能勝任ECDSA的公鑰;證書必須允許這個密鑰被用於簽名, 並與hash算法一起被用於證書驗證消息; 這個公鑰必須使用一個曲線和server支持的點的格式.
        rsa_fixed_dh        Diffie-Hellman公鑰; 必須使用與server的密鑰相同的參數
        dss_fixed_dh

        - 如果列出在證書請求中的certificate_authorities非空, 證書鏈中的一個證書應該被一個列出的CA簽發.

        - 證書必須被一個可接受的hash/簽名算法對簽名, 正如7.4.4節描述的那樣. 需要注意的是這放寬了在以前的TLS版本中對證書籤名算法的限制.

        需要注意的是, 與server證書一樣, 有一些證書使用了當前不能用於TLS的算法/算法組合.

7.4.7. Client密鑰交換消息

        當這個消息即將被髮送時:

            這個消息一直由client發送. 如果被髮送的話, 它必須緊隨着client證書消息. 否則, 它必須是在client收到ServerHelloDone後發送的第一個消息.

        這個消息的含義:

            在這個消息中設置了預主密鑰, 這個或者通過RSA加密後直接傳輸, 或者通過傳輸Diffie-Hellman參數來允許雙方協商出一致的預主密鑰.

            當client使用一個瞬時ephemeral指數時, 這個消息就會包含client的Diffie-Hellman公開數. 如果client正在發送一個包含一個靜態DH指數(例如, 它正在進行fixed_dh client認證)的證書時, 這個消息必須被髮送但必須爲空.

        這個消息的結構:

        這個消息的選項依賴於選擇了哪種密鑰交互方法. 見7.4.3節關於KeyExchangeAlgorithm的定義.

      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加密的預主密鑰消息

    如果RSA被用於密鑰協商和認證, client會生成一個48字節的預主密鑰,使用server證書中的公鑰加密,然後以一個加密的預主密鑰消息發送. 這個結構體是ClientKeyExchange消息的一個變量, 它本身並非一個消息.

    這個消息的結構是:

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

      client_version
         client所支持的最新版本. 這用於探測版本號以抑制攻擊.

      random
         46字節以安全方式產生的隨機字節.

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

      pre_master_secret
          這個隨機數由client產生,且用於生成族密鑰, 如8.1節所述.

    注意:PreMasterSecret中的版本號是由client在ClientHello.client_version中提供的, 並不是爲這個連接協商的版本號. 這特性被用來防止回滾攻擊. 不幸的是, 一些舊的實現使用了協商的版本, 因此檢查版本號會導致與這些不正確的clieng實現之間的互操作失敗.

    Client實現必須一直在PreMasterSecret中發送正確的版本號. 如果ClientHello.client_version是TLS 1.1或更高, server實現必須按照以下的描述檢查版本號. 如果版本號是TLS 1.0或更早, server實現應該檢查版本號, 但可以有一個可配置的選項來禁止這個檢查. 需要注意的是如果檢查失敗, PreMasterSecret應該按照以下的描述將PreMasterSecret隨機化.

    注: 由Bleichenbacher [BLEI]和Klima et al.[KPR03]發現的攻擊能被用於攻擊TLS server, 這表明一個特定的消息在解密時,是否已經被格式化爲PKCS#1, 包含一個有效的PreMasterSecret結構,或有正確的版本號.

    正如Klima [KPR03]所描述的, 這些弱點能夠被避免, 通過不區別對待格式不正確的消息塊和/或不匹配的版本號和格式正確的RSA塊. 換句話說:
    1. 生成一個46字節隨機字符串R;
    2. 解密這消息來恢復明文M;
    3. 如果PKCS#1填充不正確,或消息M的長度不是精確的48字節:
           pre_master_secret = ClientHello.client_version || R
       否則,如果ClientHello.client_version <= TLS 1.0, 且版本號檢查被顯示禁用:
           pre_master_secret = M
       否則:  
           pre_master_secret = ClientHello.client_version || M[2..47]

    需要注意的是使用ClientHello.client_version顯式構造pre_master_secret會產生一個無效的master_secret, 如果client在原始的pre_master_secret中發生了錯誤的版本的話。

    另外一個可供選擇的方法是講版本號不匹配作爲一個PKCS-1格式錯誤來處理, 並將預主米有完全隨機化:
1. 生成一個46字節隨機字符串R;
2. 解密這消息來恢復明文M;
3. 如果PKCS#1填充不正確,或消息M的長度不是精確的48字節:
       pre_master_secret = R
   否則,如果ClientHello.client_version <= TLS 1.0, 且版本號檢查被顯示禁用:
       pre_master_secret = M
   否則,如果M的前兩個字節不等於ClientHello.client_version:
       premaster secret = R
   否則:  
       pre_master_secret = M

    雖然沒有已知的針對這個結構體的攻擊, Klima et al. [KPR03]描述了一些理論上的攻擊, 因此推薦第一種結構描述。

    在任何情況下,一個TLS Server一定不能產生一個警報,如果處理一個RSA加密的預密鑰消息失敗,或版本號不是期望的。作爲替代,它必須以一個隨機生成的預主密鑰即系握手流程。出於定位問題的意圖將失敗的真正原因記錄在日誌中可能是有幫助的。但必須注意避免泄露信息給攻擊者(例如,計時,日誌文件或其它渠道)

    在[PKCS1]中定義的RSAES-OAEP加密方案對於Bleichenbacher攻擊是更安全的。然而,爲了最大程度上兼容早期的TLS版本,本規範使用RSAES-PKCS1-v1_5方案。如果上述建議被採納的話,不會有多少已知的Bleichenbacher能夠奏效。

    實現註記:公鑰加密數據被表現爲一個非透明向量<0..2^16-1> (見4.7節)。因此,一個ClientKeyExchange消息中的RSA加密的預主密鑰以兩個長度字節爲先導。 這些字節對於RSA是冗餘的因爲EncryptedPreMasterSecret是ClientKeyExchange中僅有的數據,它的長度會明確地確定。SSLv3規範對公鑰加密數據的編碼沒有明確指定,因此很多SSLv3實現沒有包含長度字節 -- 它們將RSA加密數據直接編碼進ClientKeyExchange消息中。

    本規範要求EncryptedPreMasterSecret和長度字節一起正確地編碼。結果PDU會與很多SSLv3實現不兼容。實現者從SSLv3升級時必須修改他們的實現以生成和接受正確的編碼。希望兼容SSLv3和TLS的實現者必須使他們的實現的行爲依賴於版本號。

    實現註記:現在得知對TLS進行基於計時的攻擊是可能的,至少當client和server在相同局域網中時是可行的。相應地,使用靜態RSA密鑰的實現必須使用RSA混亂或其它抗計時攻擊技術,如[TIMING]所述。

7.4.7.2. Client Diffie-Hellman Public Value

    這個消息的含義是:

    這個結構體傳遞了client的Diffie-Hellman公開值(Yc)如果這個值沒有被包含在clietn的證書中。Yc所用的編碼由PublicValueEncoding所列舉。這個結構是client密鑰交換消息的一個變量,它本身並非一個消息。

    這個消息的結構是:

        enum { implicit, explicit } PublicValueEncoding;

        implicit

        如果client發送了一個證書其中包含了一個合適的Diffie-Hellman密鑰(用於fixed_dh類型的client認證),則Yc是隱式的且不需要再次發送。這種情況下,client密鑰交換消息會被髮送,單必須是空。

        explicit

        Yc需要被髮送。

        struct {
          select (PublicValueEncoding) {
              case implicit: struct { };
              case explicit: opaque dh_Yc<1..2^16-1>;
          } dh_public;
      } ClientDiffieHellmanPublic;

      dh_Yc

        client的Diffie-Hellman公開值(Yc)

7.4.8. Certificate Verify

         當這個消息將被髮送時:

        這個消息用於對一個client的證書進行顯式驗證。這個消息只能在一個client證書具有簽名能力時才能發送(例如,所有除了包含固定Diffie-Hellman參數的證書)。當發送時,它必須緊隨着client密鑰交換消息。

        這消息的結構是:
            struct {
                digitally-signed struct {
                   opaque handshake_messages[handshake_messages_length];
               }
           } CertificateVerify;

      這裏handshake_messages是指發送或接收到的所有握手消息,從client hello開始到但不包括本消息,包含握手消息的類型和長度域。這是到目前爲止所有握手結構(如在7.4節中定義的那樣)的關聯。需要注意的是這要求兩端要麼緩存消息,要麼計算用所有可用的hash算法計算運行時hash值直到計算CertificateVerify的hash值爲止。Server可以通過在CertificateRequest消息中提高一個受限的摘要算法及來最小化這種計算代價。

    在簽名中使用的hash和簽名算法必須是CertificateRequest消息中supported_signature_algorithms域所列出的算法中的一種。此外,hash和簽名算法必須與client的終端實體證書相兼容。RSA密鑰可以與任何允許的hash算法一起使用,但需要服從證書中的限制,如果有的話。

    由於DSA簽名不包含任何安全表明hash算法的方法,如果任意密鑰使用多個hash的話會產生一個hash替代風險。目前DSA[DSS]可以與SHA-1一起使用。將來版本的DSS[DSS-3]被希望允許與DSA一起使用其它的摘要算法,

    正如說明摘要算法應該使用的密鑰大小的指導一樣。此外,將來版本的[PKIX]可以指定機制以允許證書表明哪些摘要算法能與DSA一起使用。

7.4.9.  Finished

    當這個消息即將被髮送時:

        一個結束消息一直會在一個change cipher spec消息後立即發送,以證明密鑰交換和認證過程是成功的。一個change cipher spec消息必須在其它握手消息和結束消息之間被接收。

    這個消息的含義:

        結束消息是第一個被剛剛協商的算法,密鑰和機密保護的消息。結束消息的接收者必須驗證內容是正確的。一旦一方已經發送了結束消息且接收並驗證了對端發送的結束消息,它必須在連接上開始發送和接收應用數據。

    這個消息的結構:
      struct {
          opaque verify_data[verify_data_length];
      } Finished;

      verify_data
         PRF(master_secret, finished_label, Hash(handshake_messages))
            [0..verify_data_length-1];

      finished_label
         對於由client發送的結束消息,字符串是"client finished". 對於由server發送的結束消息,字符串是"server finished".

      Hash指出了握手消息的一個hash。對於在第5節定義的PRF,hash必須用作PRF的基礎。任何定義了一個不同PRF的密碼族必須定義Hash用於結束消息的計算。

    在TLS之前的版本中,verify_data一直是12字節長。在當前的TLS版本中,她取決於密碼族。任何沒有顯式指定verify_data_length的密碼族都有一個verify_data_length等於12.這包括了所有現有的密碼族。需要注意的是這種表示的編碼與之前的版本相同。將來密碼族可能會指定其它長度但這個長度必須至少是12字節。

    handshake_messages
        所有在本次握手過程(不包括任何HelloRequest消息)到但不包括本消息的消息中的數據。這是只能在握手層中看見的數據且不包含記錄層頭。這是到目前爲止所有在7.4節中定義的握手結構體的關聯。

        如果一個結束消息在握手的合適環節上沒有一個ChangeCipherSpec在其之前則是致命錯誤。

        handshake_messages的值包括了從ClientHello開始一直到(但不包括)結束消息的所有握手消息。這與7.4.8節中的handshake_messages不同,因爲它包含CertificateVerify消息(如果發送了)。同樣,client發送的結束消息的handshake_messages與server發送的結束消息不同,因爲第二個被髮送的要包含前一個。

        注意:ChangeCipherSpec消息,警報,和任何其它記錄類型不是握手消息,不會被包含在hash計算中。同樣,HelloRequest消息也被握手hash忽略。

8. 密碼學計算

    爲了開始連接保護,TLS記錄協議要求指定一個算法族,一個主密鑰和client及server端隨機數。認證,加密和消息認證碼算法由cipher_suite確定,cipher_suite是由server選定並在ServerHello消息中表明出來。壓縮算法在hello消息這協商出來,隨機數也在hello消息中交換。所有這些都用於計算主密鑰。

8.1. 計算主密鑰

    對於所有的密鑰交換算法,相同的算法都會被用來將pre_master_secret轉化爲master_secret。一旦master_secret計算完畢,pre_master_secret就應當從內存中刪除。        

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

    主密鑰的長度一直是48字節。預密鑰的長度根據密鑰交換算法而變。

8.1.1. RSA

    當RSA被用於身份認證和密鑰交換時,client會產生一個48字節的pre_master_secret,用server的公鑰加密,然後發送給server。Server用它自己的私鑰解密pre_master_secret。然後雙方按照前述方法將pre_master_secret轉換爲master_secret。

8.1.2. Diffie-Hellman

    一個傳統的Diffie-Hellman計算需要被執行。協商出來的密鑰(Z)會被用做pre_master_secret, 並按照前述方法將其轉換爲master_secret。在被用做pre_master_secret之前,Z開頭所有的0位都會被壓縮。

    注:Diffie-Hellman參數由server指定,可能是臨時的或包含在server的證書中。

9. 強制密碼套件

    在沒有指定一個應用配置標準時,一個TLS兼容的應用必須實現密碼套件TLS_RSA_WITH_AES_128_CBC_SHA (定義見附錄A.5).

10. 應用數據協議

    應用數據消息由記錄層承載和分片、壓縮、並基於當前連接狀態進行加密。這些消息被記錄層當做透明數據處理。

11. 安全考慮

    安全問題的討論貫穿本備忘錄的全文,尤其是附錄D, E和F。

12. IANA考慮

    本文檔使用了幾個在[TLS1.1]中原創的Registry。 IANA更新了這些參考穩定。這些Registry和它們的分配策略(照搬自[TLS1.1])列在下面。

    -  TLS ClientCertificateType標識符Registry: 在0-63(十進制)範圍內(包含0和63)的將來的數值由標準行爲[RFC2434]來指定。在64-223(十進制)範圍內(包含64和223)的數值由規範需求[RFC2434]來指定。在224-255(十進制)範圍內(包含224和255)的數值保留以備私用[RFC2434]。

   -  TLS密碼套件Registry:  在0-191(十進制)範圍內(包含0和191)的將來的數值連同第一個字節由標準行爲[RFC2434]來指定。在192-254(十進制)範圍內的數值連同第一個字節由規範需求[RFC2434]來指定。數值255連同第一個字節保留以備私用[RFC2434]。

   -  本文定義了幾個新的基於HMAC-SHA256的密碼套件,它們的數據(在附錄A.5中)已經從TLS密碼套件registry中分配。

   -  TLS ContentType Registry: 將來的數值由標準行爲[RFC2434]來分配。

   -  TLS警報Registry: 將來的數值由標準行爲[RFC2434]來分配。

   -  TLS HandshakeType Registry: 將來的數值由標準行爲[RFC2434]來分配。

本文檔也使用了幾個在[RFC4366]中原創的Registry。 IANA更新了這些參考穩定。這些Registry和它們的分配策略(照搬自[RFC4366])列在下面。

   -  TLS ExtensionType Registry: 將來的值由IETF一致分配[RFC2434].  IANA已經更新了這個registry以包含signature_algorithms擴展和它對應的值(見 7.4.1.4節).

   此外,本文還定義了兩種新的registry並由IANA維護:

   -  TLS SignatureAlgorithm Registry: 這個registry已經初始化爲在7.4.1.4.1節中描述的值. 在0-63(十進制)範圍內(包含0和63)的將來的數值由標準行爲[RFC2434]來指定。在64-223(十進制)範圍內(包含64和223)的數值由規範需求[RFC2434]來指定。在224-255(十進制)範圍內(包含224和255)的數值保留以備私用[RFC2434]。      

   -  TLS HashAlgorithm Registry: 這個registry已經初始化爲在7.4.1.4.1節中描述的值. 在0-63(十進制)範圍內(包含0和63)的將來的數值由標準行爲[RFC2434]來指定。在64-223(十進制)範圍內(包含64和223)的數值由規範需求[RFC2434]來指定。在224-255(十進制)範圍內(包含224和255)的數值保留以備私用[RFC2434]。      

      本文也使用了TLS壓縮方法標識符Registry, 在[RFC3749]中定義.  IANA已經分配了值0給"null"壓縮方法。

Appendix A. 協議數據結構和常量值

本節描述了協議類型和常量。

A.1. 記錄層

struct {

uint8 major;

uint8 minor;

} ProtocolVersion;


ProtocolVersion version = { 3, 3 }; /* TLS v1.2*/


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;


struct {

ContentType type;

ProtocolVersion version;

uint16 length;

opaque fragment[TLSCompressed.length];

} TLSCompressed;


struct {

ContentType type;

ProtocolVersion version;

uint16 length;

select (SecurityParameters.cipher_type) {

case stream: GenericStreamCipher;

case block: GenericBlockCipher;

case aead: GenericAEADCipher;

} fragment;

} TLSCiphertext;


stream-ciphered struct {

opaque content[TLSCompressed.length];

opaque MAC[SecurityParameters.mac_length];

} GenericStreamCipher;

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;


struct {

opaque nonce_explicit[SecurityParameters.record_iv_length];

aead-ciphered struct {

opaque content[TLSCompressed.length];

};

} GenericAEADCipher;

A.2. Change Cipher Specs消息

struct {

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

} ChangeCipherSpec;

A.3. 警報消息

enum { warning(1), fatal(2), (255) } AlertLevel;

enum {

close_notify(0),

unexpected_message(10),

bad_record_mac(20),

decryption_failed_RESERVED(21),

record_overflow(22),

decompression_failure(30),

handshake_failure(40),

no_certificate_RESERVED(41),

bad_certificate(42),

unsupported_certificate(43),

certificate_revoked(44),

certificate_expired(45),

certificate_unknown(46),

illegal_parameter(47),

unknown_ca(48),

access_denied(49),

decode_error(50),

decrypt_error(51),

export_restriction_RESERVED(60),

protocol_version(70),

insufficient_security(71),

internal_error(80),

user_canceled(90),

no_renegotiation(100),

unsupported_extension(110), /* new */

(255)

} AlertDescription;


struct {

AlertLevel level;

AlertDescription description;

} Alert;

A.4. 握手協議

enum {

hello_request(0), client_hello(1), server_hello(2),

certificate(11), server_key_exchange (12),

certificate_request(13), server_hello_done(14),

certificate_verify(15), client_key_exchange(16),

finished(20)

(255)

} HandshakeType;


struct {

HandshakeType msg_type;

uint24 length;

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;

A.4.1. Hello消息

struct { } HelloRequest;


struct {

uint32 gmt_unix_time;

opaque random_bytes[28];

} Random;


opaque SessionID<0..32>;


uint8 CipherSuite[2];


enum { null(0), (255) } CompressionMethod;


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;


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;


struct {

ExtensionType extension_type;

opaque extension_data<0..2^16-1>;

} Extension;

enum {

signature_algorithms(13), (65535)

} ExtensionType;


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-1>;

A.4.2. Server認證和密鑰交換消息

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


struct {

ASN.1Cert certificate_list<0..2^24-1>;

} Certificate;


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 */

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;


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>;

DistinguishedName certificate_authorities<0..2^16-1>;

} CertificateRequest;


struct { } ServerHelloDone;

A.4.3. Client認證和密鑰交換消息

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;


struct {

ProtocolVersion client_version;

opaque random[46];

} PreMasterSecret;


struct {

public-key-encrypted PreMasterSecret pre_master_secret;

} EncryptedPreMasterSecret;


enum { implicit, explicit } PublicValueEncoding;


struct {

select (PublicValueEncoding) {

case implicit: struct {};

case explicit: opaque DH_Yc<1..2^16-1>;

} dh_public;

} ClientDiffieHellmanPublic;


struct {

digitally-signed struct {

opaque handshake_messages[handshake_messages_length];

}

} CertificateVerify;

A.4.4. 握手終結消息

struct {

opaque verify_data[verify_data_length];

} Finished;

A.5. 密碼套件

   下面的值定義了ClientHello和ServerHello消息所使用的密碼套件碼。
   一個密碼套件定義了在TLS 1.2版本中支持的一個密碼規範。
   TLS_NULL_WITH_NULL_NULL 是指定的且是一個TLS連接在通道中初次握手過程中的初始狀態,但不能被協商,它也不能提供比無安全的連接更多的保護。

      CipherSuite TLS_NULL_WITH_NULL_NULL               = { 0x00,0x00 };

   下面的CipherSuite的定義要求server提供一個RSA證書用於密鑰交換。Server可以在證書請求消息中請求任何可簽名的證書。

      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 };

   下面的密碼套件定義是用於server認證的(也可以是client認證的)Diffie-Hellman。DH代表着一類密碼套件,其server證書包含了由證書權威(CA)簽名的Diffie-Hellman參數。DHE代表着瞬時 Diffie-Hellman, 這裏Diffie-Hellman參數由一個可簽名的證書籤名來簽名,這個證書由CA簽發。Server使用的簽名算法由CipherSuite名稱中的DHE組件後面的名稱來指定。Server能夠從client請求任何可簽名的證書用於驗證client,它也可以請求一個Diffie-Hellman證書。任何由client提供的Diffie-Hellman證書必須使用由server描述的參數(組或生成者)。

      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 };


   下面的密碼套件用於完全匿名的Diffie-Hellman通信,其中的任何一方都沒有驗證。需要注意的是這種模式無法防禦中間人攻擊。因此使用這種模式是受限使用的:這些密碼套件不能被TLS 1.2的實現所使用,除非應用層指定要求使用匿名密鑰交換。(匿名密鑰交換有時也是可接受的,例如:在沒有驗證建立的情況下支持投機的加密, 或TLS作爲更復雜的安全協議的一部分來使用,有其它手段來確保驗證)

      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 };

   需要注意的是使用非匿名密鑰交換且沒有實際的密鑰交換驗證在實質上等同於匿名密鑰交換,之前的告警同樣適用。當非匿名密鑰交換總體上包含了比匿名密鑰交換更高的計算和商業成本時, 且應用層允許匿名密鑰交換,出於互操作的目的不禁用非匿名密鑰交換。

   新的密碼套件值已經由IANA指定並在12節中描述。

   注: 密碼套件值 { 0x00, 0x1C }和{ 0x00, 0x1D } 被保留以避免與SSL 3中Fortezza-based密碼套件衝突。

A.6.  安全參數

   這些安全參數由TLS握手協議決定且作爲參數提供給TLS記錄層以初始化一個連接的狀態。SecurityParameters包括:

   enum { null(0), (255) } CompressionMethod;

   enum { server, client } ConnectionEnd;

   enum { tls_prf_sha256 } PRFAlgorithm;

   enum { null, rc4, 3des, aes } BulkCipherAlgorithm;

   enum { stream, block, aead } CipherType;

   enum { null, hmac_md5, hmac_sha1, hmac_sha256, hmac_sha384,
     hmac_sha512} MACAlgorithm;

   /* 在CompressionMethod, PRFAlgorithm, BulkCipherAlgorithm, 和
   MACAlgorithm中指定的其它值可以被加入到算法中. */

   struct {
       ConnectionEnd          entity;
       PRFAlgorithm           prf_algorithm;
       BulkCipherAlgorithm    bulk_cipher_algorithm;
       CipherType             cipher_type;
       uint8                  enc_key_length;
       uint8                  block_length;
       uint8                  fixed_iv_length;
       uint8                  record_iv_length;
       MACAlgorithm           mac_algorithm;
       uint8                  mac_length;
       uint8                  mac_key_length;
       CompressionMethod      compression_algorithm;
       opaque                 master_secret[48];
       opaque                 client_random[32];
       opaque                 server_random[32];
   } SecurityParameters;

A.7.  與RFC 4492相比的變化

   RFC 4492 [TLSECC]將橢圓曲線密碼套件添加到TLS中。本文改變了在那個文檔中使用的一下結構體。本節詳細說明要求RFC 4492和TLS 1.2的實現者做出的改變。TLS 1.2的實現者但不實現RFC 4492的不需要閱讀本節。

    本文添加了一個"signature_algorithm"域到數字簽名的元素中以便標示出生成一個簽名所用的簽名和摘要算法。這個改變應用於數字簽名,也適用於ECDSA簽名,因此允許ECDSA簽名與除SHA1外的摘要算法一起使用,提供這種用法可以兼容證書和[PKIX]的將來的修改所施加的任何限制.

   正如7.4.2節和7.4.6節描述的那樣, 對簽發證書所用的簽名算法的限制不再與密碼套件(被server所使用的)或ClientCertificateType(被client所使用的)所限定。因此,對RFC 4492的第2和第3節中所指定的對簽發證書的簽名算法的限制也同樣解除。在本文中,對終端實體證書中密鑰的限制仍然不變。

Appendix B.  詞彙表

   Advanced Encryption Standard (AES) —— 高級加密標準
      AES [AES]是一個廣泛使用的對稱加密算法。AES是一個塊加密算法,密鑰是128、192、256 bit,塊大小是16字節。TLS當前支持128和256 bit的密鑰長度。

   application protocol —— 應用層協議
      一個應用層協議是一個直接位於傳輸層(例如, TCP/IP)之上的協議。例子包括HTTP, TELNET, FTP, 和SMTP.

   asymmetric cipher —— 非對稱密碼
      見公鑰密碼學。

   authenticated encryption with additional data (AEAD) —— 帶額外數據的認證加密
      一種同時提供機密性和消息完整性的對稱加密算法。

   authentication —— 認證
      認證是一種一個實體確認另一個實體的身份的能力。

   block cipher —— 分組密碼
      一個分組密碼是一種算法,以bit組(稱爲塊)的形式操作明文。64 bit曾經是,128 bit現在是一個通常的塊大小。

   bulk cipher —— 塊密碼
      一個用於加密大量數據的對稱加密算法。

   cipher block chaining (CBC) —— 密碼分組鏈
      CBC是一個模式, 在這個模式中每個用一個密文塊加密的明文塊都首先與前一個密文塊做異或運算(或者,對於第一個塊,與初始向量)。對於解密,每個塊都是先解密,然後再與之前的密文塊(或向量)做異或運算。

   certificate —— 證書
      做爲X.509協議(也被稱爲ISO認證框架)的一部分, 證書由一個可信的證書權威指定並在一方的身份或一些其它屬性和它的公鑰之間提供一個強綁定。

   client —— 客戶端
      與server發起一個TLS連接的應用實體。這也許可能(也許不可能)意味着client發起了基礎的傳輸連接。在操作上client與server的主要差別是server通常是被驗證的,而client只是選擇性驗證。

   client write key —— 客戶端寫密鑰
      用於加密由client所寫數據的密鑰。

   client write MAC key —— 客戶端寫消息認證碼密鑰
      用於認證由client所寫數據的密鑰。

   connection —— 連接
      一個連接是一個提供一直合適類型服務的傳輸層(在OSI分層模型中定義)。對於TLS,這樣的連接是對等關係。這樣的連接是臨時的。每個連接都與一個會話相關聯。
   Data Encryption Standard —— 數據加密標準
      DES [DES]仍然是一個被廣泛使用的對稱加密算法,雖然它限制被認爲相當弱。DES是一個塊加密算,密鑰是56位,塊是8字節。在TLS中,出於密鑰生成的考慮,DES被作爲8字節(64位)密鑰長度來對待,但它仍然只提供56位保護。(每個密鑰字節的最低位用於設置這個密鑰字節的奇偶校驗)DES也可以以一種模式[3DES]操作,在這種模式下對每塊數據用3個獨立密鑰進行三次加密;這會使用168位(對於TLS密鑰生成方法是24字節)密鑰並提供等同於112位的安全。

   Digital Signature Standard (DSS) —— 數字簽名標準
      一個數字簽名的標準,包括數字簽名算法,被美國國家標準與技術研究所(NIST)認可,定義於NIST FIPS PUB 186-2, "數字簽名標準",由美國商務部於2000年1一月發佈[DSS]。一個有意義的更新[DSS-3]已經被草案化並於2006年3月公佈。

   digital signatures —— 數字簽名
      數字簽名使用公鑰密碼學和單向hash函數產生一個能夠被認證的數據的簽名,並且這個簽名難於被僞造或否認。

   handshake —— 握手
      一個client和server之間的初始協商,建立它們之間事物的參數。

   Initialization Vector (IV) —— 初始向量
      當一個塊加密算法使用CBC模式時,在加密之前初始向量會與第一個明文塊進行異或運算。

   Message Authentication Code (MAC) —— 消息認證碼
      一個消息認證碼是一個從一個消息或一些機密數據計算得到的單向hash。它在不知道機密數據的情況下很難僞造。它用於檢測消息是否被修改。

   master secret —— 主密鑰
      用於產生加密密鑰、MAC密鑰和向量的安全機密數據。

   MD5
      MD5 [MD5]是一個散列函數,能將任意長的數據流轉化爲一個固定大小(16字節)的hash值。由於密碼分析的顯著進步,在本文發佈的時候,MD5不再被認爲是一個“安全的”散列函數。

   public key cryptography —— 公鑰密碼學
      使用兩個密鑰進行加解密的一類密碼學技術。公鑰加密的消息只能由相關的私鑰解密。相反,由私鑰簽名的消息只能由公鑰驗證。

   one-way hash function —— 單向hash函數
      一個將任意數量的數據轉換爲一個固定長度hash的變換。在計算上很難反變換或找到碰撞。MD5和SHA就是單向hash函數的例子。

   RC4
      一個由Ron Rivest發明的流加密算法。一個兼容的密碼算法的描述見[SCH]。

   RSA
      一個被非常廣泛使用的公鑰算法,能用於加密或數字簽名[RSA]。

   server —— 服務器
      Server是一個應用實體,能對client的連接請求做出響應。參見"client"。

   session —— 會話
      一個TLS會話是一個在一個client和一個server之間的聯繫。會話由握手協議創建。會話定義了一套能在多個連接中共享的密碼學安全參數。會話被用於避免每個連接爲協商新的安全參數所產生的代價。

   session identifier —— 會話標識符
      一個會話標識符是一個由server產生的值,能標識一個特定的會話。

   server write key —— server寫密鑰
      用於加密由server所寫數據的密鑰。

   server write MAC key —— server寫消息認證碼密鑰
       用於認證由server所寫數據的密鑰。

   SHA
      安全hash算法(SHA)[SHS]在FIPS PUB 180-2中定義。它產生一個20字節的輸出。需要注意的是所有對SHA(無數字後綴)的引用實際上使用的是修改後的SHA-1算法。

   SHA-256
      256位的安全hash算法(SHA)由FIPS PUB 180-2定義。它產生一個32字節的輸出。

   SSL
      網景的安全套接層協議[SSL3]。TLS基於SSL的3.0版本。

   stream cipher —— 流密碼
      一個加密算法,它可以將一個密鑰轉換爲一個密碼學上的強密鑰流,然後用這個密鑰流與明文異或。

   symmetric cipher —— 對稱密碼
      見塊密碼。

   Transport Layer Security (TLS) —— 傳輸層安全
      這是個協議,也是因特網工程任務族中的傳輸層安全工作租。見本文末尾的“工作組信息”(見99頁)。

Appendix C. 密碼套件定義

密碼套件                                                                          密鑰交換      加解密       消息認證碼

TLS_NULL_WITH_NULL_NULL                                   NULL          NULL             NULL

TLS_RSA_WITH_NULL_MD5                                         RSA             NULL              MD5

TLS_RSA_WITH_NULL_SHA                                         RSA             NULL              SHA

TLS_RSA_WITH_NULL_SHA256                                  RSA             NULL              SHA256

TLS_RSA_WITH_RC4_128_MD5                                  RSA           RC4_128          MD5

TLS_RSA_WITH_RC4_128_SHA                                   RSA           RC4_128          SHA

TLS_RSA_WITH_3DES_EDE_CBC_SHA                      RSA     3DES_EDE_CBC    SHA

TLS_RSA_WITH_AES_128_CBC_SHA                         RSA        AES_128_CBC    SHA

TLS_RSA_WITH_AES_256_CBC_SHA                         RSA        AES_256_CBC    SHA

TLS_RSA_WITH_AES_128_CBC_SHA256                  RSA        AES_128_CBC    SHA256

TLS_RSA_WITH_AES_256_CBC_SHA256                  RSA        AES_256_CBC    SHA256

TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA          DH_DSS   3DES_EDE_CBC  SHA

TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA          DH_RSA   3DES_EDE_CBC  SHA

TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA       DHE_DSS 3DES_EDE_CBC   SHA

TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA       DHE_RSA 3DES_EDE_CBC   SHA

TLS_DH_anon_WITH_RC4_128_MD5                    DH_anon     RC4_128           MD5

TLS_DH_anon_WITH_3DES_EDE_CBC_SHA       DH_anon 3DES_EDE_CBC  SHA

TLS_DH_DSS_WITH_AES_128_CBC_SHA              DH_DSS   AES_128_CBC   SHA

TLS_DH_RSA_WITH_AES_128_CBC_SHA              DH_RSA   AES_128_CBC    SHA

TLS_DHE_DSS_WITH_AES_128_CBC_SHA           DHE_DSS AES_128_CBC    SHA

TLS_DHE_RSA_WITH_AES_128_CBC_SHA           DHE_RSA AES_128_CBC    SHA

TLS_DH_anon_WITH_AES_128_CBC_SHA           DH_anon AES_128_CBC     SHA

TLS_DH_DSS_WITH_AES_256_CBC_SHA              DH_DSS AES_256_CBC     SHA

TLS_DH_RSA_WITH_AES_256_CBC_SHA              DH_RSA AES_256_CBC     SHA

TLS_DHE_DSS_WITH_AES_256_CBC_SHA           DHE_DSS AES_256_CBC   SHA

TLS_DHE_RSA_WITH_AES_256_CBC_SHA           DHE_RSA AES_256_CBC   SHA

TLS_DH_anon_WITH_AES_256_CBC_SHA           DH_anon AES_256_CBC    SHA

TLS_DH_DSS_WITH_AES_128_CBC_SHA256       DH_DSS AES_128_CBC     SHA256

TLS_DH_RSA_WITH_AES_128_CBC_SHA256       DH_RSA AES_128_CBC     SHA256

TLS_DHE_DSS_WITH_AES_128_CBC_SHA256    DHE_DSS AES_128_CBC   SHA256

TLS_DHE_RSA_WITH_AES_128_CBC_SHA256    DHE_RSA AES_128_CBC   SHA256

TLS_DH_anon_WITH_AES_128_CBC_SHA256    DH_anon AES_128_CBC    SHA256

TLS_DH_DSS_WITH_AES_256_CBC_SHA256      DH_DSS AES_256_CBC     SHA256

TLS_DH_RSA_WITH_AES_256_CBC_SHA256      DH_RSA AES_256_CBC      SHA256

TLS_DHE_DSS_WITH_AES_256_CBC_SHA256   DHE_DSS AES_256_CBC     SHA256

TLS_DHE_RSA_WITH_AES_256_CBC_SHA256   DHE_RSA AES_256_CBC     SHA256

TLS_DH_anon_WITH_AES_256_CBC_SHA256   DH_anon AES_256_CBC     SHA256

密碼算法       類型   密鑰長度   IV大小 塊大小
-----------  ------  --------  ----  -----
NULL          Stream      0       0    N/A
RC4_128       Stream     16       0    N/A
3DES_EDE_CBC  Block      24       8      8
AES_128_CBC   Block      16      16     16
AES_256_CBC   Block      32      16     16

MAC       算法          mac_length  mac_key_length
--------  -----------  ----------  --------------
NULL      N/A              0             0
MD5       HMAC-MD5        16            16
SHA       HMAC-SHA1       20            20
SHA256    HMAC-SHA256     32            32

   類型
      表明是否是一個流加密算法或是一個在CBC模式下運行的塊加密算法。

   密鑰長度
      用於產生寫密鑰的密鑰塊的字節數。

   IV大小
      用於產生初始化向量的數據的數量。流加密算法是0;塊加密算法等於塊大小(等於SecurityParameters.record_iv_length)。

   塊大小
      一個加密算法一次處理的數據的數量;一個塊加密算法在CBC模式下只能加密自身塊大小偶數倍的數據。

Appendix D. 實現註記

   TLS協議不能阻止很多常見的安全錯誤。這節會提供幾個協助開發者的建議。

D.1. 隨機數生成和種子化


   TLS需要一個密碼學上安全的僞隨機數生成器(PRNG)。在設計和種子化PRNG時必須小心。PRNG基於安全的hash操作,最顯著的是SHA-1,是可接受的,但不能提供比隨機數生成器狀態的大小更多的安全。

   爲了估計所產生的種子材料的量,在每個種子的字節中添加了不可預測信息的位數。例如,從一臺兼容18.2HZ定時器的PC中獲取的按鍵計時數據提供了1或2個安全位,即使計數器數值的總大小是16位或更多。種子化一個128位的PRNG因此應該要求大約100個這樣的定時器數值。

   [RANDOM] 對於隨機數值的生成提供了指導

D.2.  證書和認證

   實現負責驗證證書的完整性,且通常應該支持證書吊銷。證書應該一直被驗證以確保它被一個可信的證書權威(CA)適當的簽發。可信CA的選擇和添加應該十分小心。用戶應該能夠觀察到有關證書和根CA的信息。

D.3.  密碼套件

   TLS支持一個密鑰大小和安全等級的範圍,包括不提供安全或提供最少安全的等級。一個適當的實現可能不會支持很多密碼套件。例如,匿名Diffie-Hellman強烈不推薦因爲它不能阻止中間人攻擊。應用應該強制最小和最大密鑰大小。例如,包含了512位RSA密鑰或簽名的證書鏈不適用於高安全的應用。

D.4.  實現陷阱

   實現的經驗表面早期TLS特定部分的規範並不容易理解,併成爲了安全和互操作問題的一個來源。其中很多領域會已經在本文中澄清,但本附錄包含了一個大多數重要事情的短的列表,希望實現者特別關注。

   TLS協議問題:

   -  你是否能正確處理分片爲多個TLS記錄的握手消息(見6.2.1節)? 包括邊緣實現(如:一個ClientHello被分爲若干個小的分片)? 你會將握手消息分片超過最大分片大小限制嗎?特別是證書和證書請求握手消息能足夠大到要求分片。
   -  你忽略了在ServerHello(見附錄E.1)之前的所有消息中的TLS記錄層版本號了嗎?
   -  你正確處理ClientHello中的TLS擴展了嗎(包括完全忽略擴展域)?
   -  由client或server發起重協商你都支持嗎?當重協商是一個可選特性時,強烈建議支持它。
   -  當server請求一個client的證書但沒有合適的證書可用,你會正確地發送一個空的證書消息而不是忽略整個消息嗎(見7.4.6)?

   密碼學細節:

   -  對於RSA加密的預主密鑰,你正確地發送和驗證了版本號了嗎?當遇到一個錯誤時,你是繼續握手以避免Bleichenbacher攻擊嗎(見7.4.7.1)?
   -  你採取了什麼對抗措施來阻止對RSA解密和簽名操作(見7.4.7.1)的計時攻擊?

   -  對於RSA加密的預主密鑰,你正確地發送和驗證了版本號了嗎?當遇到一個錯誤時,你是繼續握手以避免Bleichenbacher攻擊嗎(見7.4.7.1)?
   -  你採取了什麼對抗措施來阻止對RSA解密和簽名操作(見7.4.7.1)的計時攻擊?
   -  當校驗RSA簽名時,空和缺少參數你都接受嗎?(見4.7節)?你是否驗證RSA的填充在hash值之後不包含任何額外數據?[FI06]
   -  使用Diffie-Hellman密鑰交換時,你會正確地剝離協商的密鑰(見8.1.2節)第一個0字節嗎?
   -  你的TLS客戶端是否檢查server發送的Diffie-Hellman參數是可接受的嗎?
   -  你怎樣爲CBC模式的密碼算法(見6.2.3.2)產生一個不可預測的向量呢?
   -  你接受長CBC模式的填充Do you accept long CBC mode padding (上限255字節;見6.2.3.2節)嗎?
   -  你怎樣防禦CBC模式計時攻擊(見6.2.3.2節)?
   -  你是否使用了一個強壯的,更重要的,進行了適當種子化的隨機數生成器(見Appendix D.1)來生成預主密鑰(用於RSA密鑰交換),Diffie-Hellman私有數據,DSA "k"參數,和其它的重要安全參數?

Appendix E. 後向兼容性

E.1. 與TLS 1.0/1.1和SSL 3.0的兼容

   由於存在着很多版本的TLS(1.0, 1.1, 1.2, 和任何將來的版本)和SSL (2.0和3.0), 意味着需要協商所使用的具體協議版本號。TLS協議提供了一個內置機制用於版本協商,這樣就不會爲其它協議組件引入版本選擇的複雜性。

   TLS版本1.0, 1.1, 1.2, 和SSL 3.0都非常相似,而且都使用兼容的ClientHello消息; 因此, 全部支持這些版本相對容易。相似地,server能輕易的使client試圖使用TLS將來的版本,只要ClientHello格式保持兼容,且client支持server提供的最高版本協議。

   一個希望與這樣的舊版本server進行協商的TLS 1.2 client應該發送一個正常的TLS 1.2 ClientHello,ClientHello.client_version中包含{ 3, 3 } (TLS 1.2)。如果server不支持這個版本,它會迴應一個包含舊版本號的ServerHello。如果client同意使用這個版本,協商將會以適用於所協商協議的方式繼續進行。

   如果server選擇的版本client並不支持(或不能接受),client必須發送一個“protocol_version”警報消息並關閉連接。

   如果一個TLS server接收的ClientHello包含的版本號大於server所支持的最高版本,它必須按照server所支持的最高版本來回應。

   一個TLS server也能接收一個包含的版本號小於最高支持版本的ClientHello。如果server希望與舊的client協商,它將繼續以適用於server所支持的最高版本的方式繼續,這個最高版本不大於ClientHello.client_version。例如,如果server支持TLS 1.0, 1.1, 和1.2,client_version是TLS 1.0,server將以一個TLS 1.0 ServerHello繼續。如果server支持(或願意使用)只比client_version大的版本,它必須發送一個“protocol_version”警報消息並關閉連接。

   無論何時一個client已經得知一個server所這次和的最高協議版本(例如,當恢復一個會話時),它都應當在原始協議中初始化這個連接。

   注: 一些server的實現已經被得知不正確地實現了版本協商。例如,有一些古怪的TLS 1.0 server在client提供的版本號比TLS 1.0新時會簡單地關閉連接。同樣,一些server會拒絕連接,如果ClientHello中包含任何TLS擴展的話。與這些古怪的server進行互操作是一個複雜的話題,超出了本文的範圍,且可能會要求client嘗試進行多次連接。

   更早版本的TLS規範並沒有是否明確記錄層版本號(TLSPlaintext.version)在發送ClientHello時(例如, 在它知道應當採用什麼協議版本之前)應該包含。因此,符合這個規範的TLS server必須接受任意值{03,XX}做爲ClientHello的記錄層版本號。

   希望與舊版本server進行協商的TLS client應當發送任意值{03,XX}做爲記錄層版本號。典型的值可以是{03,00},是client支持的最低版本號,也是ClientHello.client_version的值。沒有單個值能保證與所有舊版本server進行互操作,但這是一個複雜的話題,超出了本文的範圍。

E.2.  與SSL 2.0的兼容

   希望支持SSL 2.0的TLS 1.2 client必須發送在[SSL2]中定義的版本2的CLIENT-HELLO消息。這個消息必須包含與通用ClientHello消息中所用的相同的版本號,且必須在CIPHER-SPECS-DATA域中將所支持的TLS密碼套件安裝如下描述進行編碼。

   警告:發送2.0版本CLIENT-HELLO消息的能力會被儘快淘汰,因爲更新的ClientHello格式提供了更好的機制用於向更新版本演進和協商擴展。TLS 1.2 client不應當支持SSL 2.0。然而,即使不支持SSL 2.0的TLS server也可以接收2.0版本的CLIENT-HELLO消息。這個消息呈現在下面,爲TLS server實現者提供了足夠的細節; 真實的定義仍然假定是[SSL2]。

   爲了進行協商,2.0 CLIENT-HELLO被理解爲一個ClientHello攜帶一個空的壓縮方法且沒有擴展。需要注意的是這個消息必須直接在網線上發送,並不會包裹在一個TLS記錄中。爲了計算Finished和CertificateVerify, msg_length域不會被認爲是握手消息的一部分。

      uint8 V2CipherSpec[3];
      struct {
          uint16 msg_length;
          uint8 msg_type;
          Version version;
          uint16 cipher_spec_length;
          uint16 session_id_length;
          uint16 challenge_length;
          V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
          opaque session_id[V2ClientHello.session_id_length];
          opaque challenge[V2ClientHello.challenge_length;
      } V2ClientHello;

   msg_length
      最高位必須是1;其餘的位包含後續數據的字節長度。

   msg_type
      這個域結合版本號域, 標識了一個版本2的ClientHello消息。這個值必須是1.

   version
      等於ClientHello.client_version.

   cipher_spec_length
      這個域是cipher_specs域的總長度。它不能是0,且必須是V2CipherSpec長度的整數倍(3)。

   session_id_length
      這個域必須有一個0值用於一個client宣稱支持TLS 1.2。


   challenge_length
      Client發送給server用於驗證自己的挑戰消息的字節長度。從歷史上看,可能的值在16和32字節之間(包括16和32)。當使用後向兼容SSLv2的握手時client應該使用一個32字節的挑戰。

   cipher_specs
      這是client願意和能夠使用的所有CipherSpecs的列表。 除了在[SSL2]中定義的2.0密碼規範之外,還包含了通常在ClientHello.cipher_suites中發送的TLS密碼套件,每個套件都以一個0字節作爲前綴。例如,TLS密碼族{0x00,0x0A}應該作爲 {0x00,0x00,0x0A}.

   session_id
      這個域必須爲空。

   challenge
      與ClientHello.random相對應。如果挑戰長度小於32,TLS server應該以0字節填充到首部(注:無拖尾)以保證長度是32字節。

   註記:恢復一個TLS會話的請求必須使用一個TLS client hello。

E.3. 避免中間人版本回滾

    當TLS client回滾到版本2兼容模式時,它必須使用特殊的PKCS#1塊格式。這樣做會使得TLS server拒絕與具備TLS能力的client進行版本2的會話。

   當一個客戶端協商SSL 2.0但也支持TLS時,它必須將PKCS填充(不包括填充的結束符null)的右手(最低位字節)的、用於RSA加密CLIENT-MASTER-KEY域的ENCRYPTED-KEY-DATA的8個隨機字節設置爲0x03(其它的填充字節是隨機的)。

   當一個由TLS能力的server協商SSL 2.0時,它應該在解密ENCRYPTED-KEY-DATA後檢查這8個填充字節是否是0x03。如果不是,server應該爲ENCRYPTED-KEY-DATA產生一個隨機值,然後繼續握手(這會最終失敗因爲密鑰不匹配)。需要注意的是將錯誤情況報告給client可能會是server易遭受[BLEI]中所描述的攻擊。

Appendix F.  安全分析

   TLS協議被設計用來在一個不安全的通信通道上爲一個client和一個server之間建立一個安全連接。本文設置了幾個傳統的假設,包括攻擊者擁有重要的計算資源,不能從協議之外的源獲取機密信息。攻擊者被假定有能力捕捉,修改,刪除,重放,和其它方式篡改消息並在通信通道上發送。本附錄概述了TLS怎樣被設計來抵禦各種攻擊。

F.1.  握手協議

   握手協議負責選擇一個密碼規範(譯註:應該理解爲密碼參數)和產生一個主密鑰,它們一起構成了與一個安全會話相關聯的主密碼學參數。握手協議也能選擇擁有由可信證書權威簽名的證書的認證方。

F.1.1.  認證和密鑰交換

   TLS支持三種認證模式:雙向認證,對server認證不認證client,和全部不認證。無論何時server被認證,通道就能夠安全地應對中間人攻擊,但完全匿名的會話本質上還是容易遭受這類攻擊。匿名server不能認證client。如果server被認證了,它的證書信息必須提供一個導向一個可接受的證書權威機構的有效證書鏈。相似地,已認證的client必須提供一個可接受的證書給server。每一方都需要負責認證對方證書是有效的且沒有過期或被吊銷。

   密鑰交換過程的總體目標是產生一個通信各方共知的預主密鑰且不能爲攻擊者所知。預主密鑰將被用於產生主密鑰(見8.1節)。主密鑰用於產生Finished消息,加密密鑰,MAC密鑰(見7.4.9和6.3節)。通過發送一個正確的Finished消息,各方就能由此證明他們知道正確的預主密鑰。

F.1.1.1.  匿名密鑰交換

   完全匿名的會話可以使用Diffie-Hellman密鑰交換來建立。Server端公鑰參數包含在server密鑰交換消息中,client的包含在client密鑰交換消息中。不知道私鑰值的竊聽者不能找到Diffie-Hellman的結果(例如,預主密鑰)。

   警告:完全匿名連接只能提供對被動竊聽的保護。除非有一個獨立的防篡改通道能驗證Finished消息沒有被一個攻擊者替換,server認證在一個存在活躍的中間人攻擊的環境中是需要的。

F.1.1.2.  RSA密鑰交換和認證

   使用RSA,密鑰交換和sever認證可以合併。公鑰包含在server的證書中。需要注意的是作爲妥協產物的server端靜態RSA證書會導致所有在靜態密鑰保護下的會話喪失機密性。想要完美前向安全的TLS用戶應使用DHE密碼套件。通過頻繁更改一方的私鑰(和證書)可以限制私鑰泄露產生的破壞。

   在認證了server的證書之後,client用server的公鑰加密一個預主密鑰。通過成功解碼預主密鑰和產生了一個正確的Finished消息,server表明它知道與server證書匹配的私鑰。

   當RSA被用於密鑰交換時,client在證書認證消息(見7.4.8節)中被認證。Client簽名一個從前面的所有握手消息中提取的值。這些握手消息包括server證書,它將簽名與server綁定;包括ServerHello.random,它將簽名與當前握手過程綁定。

F.1.1.3.  Diffie-Hellman密鑰交換和認證

   當使用Diffie-Hellman密鑰交換時,server可以提供一個包含固定Diffie-Hellman參數的證書,或使用server密鑰交換消息發送一個由DSA或RSA證書籤名的臨時Diffie-Hellman參數集合。臨時參數在簽名前會與hello.random值一起做hash以確保攻擊者不會重放舊參數。在這兩種情況下,client能夠驗證證書或簽名以確保參數屬於server。

   如果client有一個包含固定Diffie-Hellman參數的證書,它的證書會包含完成密鑰交換所需的信息。需要注意的是在這種情況下client和server在每次通信時將產生相同的Diffie-Hellman結果(例如,pre_master_secret)。爲了避免pre_master_secret在內存存在的時間過長,它應當儘快被轉換爲master_secret。Client Diffie-Hellman參數必須與server提供的相兼容以使密鑰交換機制能夠正常工作。

   如果client有一個標準的DSA或RSA證書,或clietn未經認證,它在client密鑰交換消息中發送了一個臨時參數集給server,然後可以選擇性使用一個證書驗證消息認證自己。

   如何相同的DH密鑰對被用於多次握手,或者由於client或server有一個包含一個固定DH密鑰對的證書,或者由於server重用DH密鑰,都必須多加小心以阻止小子羣攻擊(small subgroup attacks)。實現上需要遵循[SUBGROUP]中的指導。

   小子羣攻擊多可以通過使用一個DHE密碼套件並生成一個新的DH私鑰(X)給每個握手來避免。如果徐州了一個合適的基(比如:2),g^X mod p可以被快速計算;因此,性能開銷被最小化了。此外,每個會話使用一個新的密鑰提供了完美前向安全。實現上需要在使用DHE密碼套件時爲每個會話產生一個新的X。

   由於TLS允許server提供任意的DH組,client應該驗證DH組的大小是滿足本地策略定義的。Client也應該驗證DH公開指數的大小是適當的。[KEYSIZ]對於各種組大小的優點提供了有用的指導。Server可以選擇通過提供一個知名組來協助client,正如在[IKEALG]或[MODP]中定義的一樣。這些能夠通過簡單比較來驗證。

F.1.2.  版本回滾攻擊

   由於TLS包含了對SSL版本2.0的重大改進,攻擊者可以嘗試將TLS client和server回退到版本2.0。這種攻擊當(且僅當)TLS雙方使用了SSL 2.0握手時纔會發生。

   雖然解決方案使用了非隨機的PKCS #1塊類型2消息填充並不優雅,它卻爲版本3.0的server提供了一個檢測這種攻擊的合理的安全方法。這個解決方案對於能夠對密鑰進行窮舉攻擊並在應用指定的等待門限過期之前用一個新的ENCRYPTED-KEY-DATA消息包含相同的密鑰(但有正常的填充)進行替換的攻擊者來說是不安全的。改變PKCS填充中最低有效的8字節並不影響協議中使用的簽名hash長度和RSA密鑰長度的安全性,因爲這在本質上等同於將輸入塊大小增加了8字節。

F.1.3.  檢測對握手協議的攻擊

   一個攻擊者可能會試圖影響握手交互以是的握手雙方選擇與正常選擇不同的加密算法。

   對於這種攻擊,一個攻擊者必須動態地改變一個或多個握手消息。如果這樣做了,client和server將會對握手消息計算出不同的hash值。結果是,通信雙方將不會接受對端的Finished消息,這樣攻擊就會被發現。

F.1.4.  恢復會話

   當一個連接通過恢復一個會話來建立時,新的ClientHello.random和ServerHello.random值會與會話的主密鑰一起做hash。在假定主密鑰不能被破解且用於產生加密密鑰和MAC密鑰的安全hash操作的安全的條件下,連接應該是安全的並且有效地獨立於之前的連接。攻擊者在無法破解安全hash操作的條件下不能使用已知的加密密鑰或MAC密鑰破解主密鑰。

   會話不能被恢復除非client和server都同意。如果任何一方懷疑會話可能被入侵,或證書可能過期或被吊銷,它應當強制進行完全的握手。建議會話ID的生命期上限爲24小時,因爲一個得到了一個主密鑰的攻擊者可能會冒充有弱點的通信方直到相應的會話ID過期。可能在相對不安全的環境中運行的應用不應當將會話ID寫入到持久的存儲中。

F.2.  保護應用層數據

   主密鑰會與ClientHello.random和ServerHello.random一起做hash以便爲每個連接產生獨特的數據加密密鑰和MAC密鑰。

   輸出數據在傳輸之前使用一個MAC值進行保護。爲了阻止重放或修改攻擊,MAC值由MAC密鑰,序列號,消息長度,消息內容和2個固定字符串計算得來。消息類型域是必要的以確保消息按預期被一個TLS記錄層的client使用,不會被重定向爲其它的消息。序列號確保了試圖刪除或重排序消息將會被探測到。因爲序列號是64位,它不能溢出。來自一方的消息不能被插入到其它的輸出中,因爲他們使用獨立的MAC密鑰。相似地,server寫和client寫密鑰也是獨立的,這樣流密鑰只能被使用一次。

   如果一個攻擊者破解了一個加密密鑰,所有由它加密的信息都能被讀取。相似地,削弱一個MAC密鑰會是的修改消息的攻擊變得可能。因爲MAC也是被加密的,消息修改攻擊通常需要破解加密算法而不只是MAC。

   注:MAC密鑰可以比加密密鑰長,這樣即使加密密鑰被破解,消息仍然能夠防止篡改。

F.3.  顯式向量

   [CBCATT]描述了一個對TLS的選擇明文攻擊,這個攻擊依賴於得知一個記錄的向量(IV)。TLS以前的版本[TLS1.0]使用了之前記錄中的CBC剩餘數據作爲IV而因此這種攻擊能夠發生。本版本使用了一個顯式IV以抵禦這種攻擊。

F.4.  複合密碼模式的安全性

   TLS使用對稱加密和在協商的密碼套件中定義的認證函數來確保所傳輸的應用數據的安全。 目標是在網絡中的活躍攻擊者的而已行爲下保護已傳輸數據的完整性和機密性。由此產生的結果是爲了取得這個目標,加密和認證函數應用於數據的順序扮演了一個重要的角色[ENCAUTH]。

   最健壯的是被稱爲加密然後認證的方法,首先對數據進行加密然後對密文計算MAC。這種方法確保了使用任何加密和MAC函數對都能夠獲得完整性和機密性,如果前者對選擇明文攻擊是安全的且MAC對於選擇消息攻擊是安全的。TLS使用了另一種方法,稱爲認證然後加密,即先對明文計算MAC然後對明文和MAC的級聯數據進行加密。這種方法對於確定的加密函數和MAC函數的組合是安全的, 但不能保證在通常的情況下是安全的。特別是,已經能夠證明存在能夠與任何安全MAC函數結合的完美的安全加密算(甚至在信息論意義上也是安全的),但卻不能提供針對一個活躍攻擊的保密性目標。因此,TLS採納了新的密碼套件和操作模式,它們需要在“認證然後加密”的模式下被分析以驗證它們達成了規定的完整性和機密性的目標。

   當前,“認證然後加密”的方法的安全性在一些重要的案例上已經得到了證明。其中一個案例是流密碼,它的原理是用一個僞隨機數生成器產生一個與消息的長度加上MAC標記的長度的不可預測的填充,然後再與明文和MAC標籤進行異或;另一個案例是使用CBC模式的一個安全塊密碼。在這個案例中,如果能夠做到一次將一個CBC加密傳遞給明文和MAC的級聯,每對新的明文和MAC使用獨立的、不可預測的IV,就是安全的。在TLS 1.1之前的版本,CBC模式的使用是很合理的,除了以之前密文的最後一塊的形式使用了一個可預測IV。這使得LTS對選擇明文攻擊是開放的。本版本的協議對這些攻擊免疫。關於加密模式安全性證明的精確細節, 見[ENCAUTH]。

F.5.  拒絕服務

   TLS易受大量的拒絕服務(DoS)攻擊的影響。尤其是一個攻擊者發起了大量的TCP連接能導致一個服務器消耗大量CPU用於RSA解密操作的情況。然而,由於TLS通常在TCP上運行,如果TCP協議棧使用了合適的TCP SYN隨機化[SEQNUM]則攻擊者很難隱藏其源頭。

   由於TLS運行在TCP之上,它也容易遭受對個體連接的大量DoS攻擊。特別是,攻擊者能僞造RST,因此能結束連接,或僞造部分TLS記錄,因此會導致連接停滯。這些攻擊通常不能由使用TCP的協議來防範,關心這類攻擊的實現者和用戶可以使用IPsec AH [AH]或ESP [ESP]。

F.6.  最後註記

   由於TLS能夠提供一個安全的連接,client和server的系統,密鑰和應用必須是安全的。此外,實現上必須沒有安全錯誤。系統只能與最弱的密鑰交換方法和所支持的認證算法一樣強壯,且只能使用值得信任的密碼函數。使用短的公鑰和匿名server應及其小心。在決定使用那個證書和證書權威時實現者和用戶必須謹慎;一個不誠實的證書權威能進行極大的破壞。

規範性引用文件

  [AES]      National Institute of Standards and Technology,
              "Specification for the Advanced Encryption Standard (AES)"
              FIPS 197.  November 26, 2001.

   [3DES]     National Institute of Standards and Technology,
              "Recommendation for the Triple Data Encryption Algorithm
              (TDEA) Block Cipher", NIST Special Publication 800-67, May
              2004.

   [DSS]      NIST FIPS PUB 186-2, "Digital Signature Standard",
              National Institute of Standards and Technology, U.S.
              Department of Commerce, 2000.

   [HMAC]     Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
              Hashing for Message Authentication", RFC 2104, February
              1997.

   [MD5]      Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321,
              April 1992.

   [PKCS1]    Jonsson, J. and B. Kaliski, "Public-Key Cryptography
              Standards (PKCS) #1: RSA Cryptography Specifications
              Version 2.1", RFC 3447, February 2003.

   [PKIX]     Housley, R., Polk, W., Ford, W., and D. Solo, "Internet
              X.509 Public Key Infrastructure Certificate and
              Certificate Revocation List (CRL) Profile", RFC 3280,
              April 2002.

   [SCH]      B. Schneier. "Applied Cryptography: Protocols, Algorithms,
              and Source Code in C, 2nd ed.", Published by John Wiley &
              Sons, Inc. 1996.

   [SHS]      NIST FIPS PUB 180-2, "Secure Hash Standard", National
              Institute of Standards and Technology, U.S. Department of
              Commerce, August 2002.

   [REQ]      Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2434]  Narten, T. and H. Alvestrand, "Guidelines for Writing an
              IANA Considerations Section in RFCs", BCP 26, RFC 2434,
              October 1998.

   [X680]     ITU-T Recommendation X.680 (2002) | ISO/IEC 8824-1:2002,
              Information technology - Abstract Syntax Notation One
              (ASN.1): Specification of basic notation.

   [X690]     ITU-T Recommendation X.690 (2002) | ISO/IEC 8825-1:2002,
              Information technology - ASN.1 encoding Rules:
              Specification of Basic Encoding Rules (BER), Canonical
              Encoding Rules (CER) and Distinguished Encoding Rules
              (DER).

資料性引用文件

   [AEAD]     McGrew, D., "An Interface and Algorithms for Authenticated
              Encryption", RFC 5116, January 2008.

   [AH]       Kent, S., "IP Authentication Header", RFC 4302, December
              2005.

   [BLEI]     Bleichenbacher D., "Chosen Ciphertext Attacks against
              Protocols Based on RSA Encryption Standard PKCS #1" in
              Advances in Cryptology -- CRYPTO'98, LNCS vol. 1462,
              pages:  1-12, 1998.

   [CBCATT]   Moeller, B., "Security of CBC Ciphersuites in SSL/TLS:
              Problems and Countermeasures",
              http://www.openssl.org/~bodo/tls-cbc.txt.

   [CBCTIME]  Canvel, B., Hiltgen, A., Vaudenay, S., and M. Vuagnoux,
              "Password Interception in a SSL/TLS Channel", Advances in
              Cryptology -- CRYPTO 2003, LNCS vol. 2729, 2003.

   [CCM]      "NIST Special Publication 800-38C: The CCM Mode for
              Authentication and Confidentiality",
              http://csrc.nist.gov/publications/nistpubs/800-38C/
              SP800-38C.pdf

   [DES]      National Institute of Standards and Technology, "Data
              Encryption Standard (DES)", FIPS PUB 46-3, October 1999.


   [DSS-3]    NIST FIPS PUB 186-3 Draft, "Digital Signature Standard",
              National Institute of Standards and Technology, U.S.
              Department of Commerce, 2006.

   [ECDSA]    American National Standards Institute, "Public Key
              Cryptography for the Financial Services Industry: The
              Elliptic Curve Digital Signature Algorithm (ECDSA)", ANS
              X9.62-2005, November 2005.

   [ENCAUTH]  Krawczyk, H., "The Order of Encryption and Authentication
              for Protecting Communications (Or: How Secure is SSL?)",
              Crypto 2001.

   [ESP]      Kent, S., "IP Encapsulating Security Payload (ESP)", RFC
              4303, December 2005.

   [FI06]     Hal Finney, "Bleichenbacher's RSA signature forgery based
              on implementation error", [email protected] mailing
              list, 27 August 2006, http://www.imc.org/ietf-openpgp/
              mail-archive/msg14307.html.

   [GCM]      Dworkin, M., NIST Special Publication 800-38D,
              "Recommendation for Block Cipher Modes of Operation:
              Galois/Counter Mode (GCM) and GMAC", November 2007.

   [IKEALG]   Schiller, J., "Cryptographic Algorithms for Use in the
              Internet Key Exchange Version 2 (IKEv2)", RFC 4307,
              December 2005.

   [KEYSIZ]   Orman, H. and P. Hoffman, "Determining Strengths For
              Public Keys Used For Exchanging Symmetric Keys", BCP 86,
              RFC 3766, April 2004.

   [KPR03]    Klima, V., Pokorny, O., Rosa, T., "Attacking RSA-based
              Sessions in SSL/TLS", http://eprint.iacr.org/2003/052/,
              March 2003.

   [MODP]     Kivinen, T. and M. Kojo, "More Modular Exponential (MODP)
              Diffie-Hellman groups for Internet Key Exchange (IKE)",
              RFC 3526, May 2003.

   [PKCS6]    RSA Laboratories, "PKCS #6: RSA Extended Certificate
              Syntax Standard", version 1.5, November 1993.

   [PKCS7]    RSA Laboratories, "PKCS #7: RSA Cryptographic Message
              Syntax Standard", version 1.5, November 1993.

   [RANDOM]   Eastlake, D., 3rd, Schiller, J., and S. Crocker,
              "Randomness Requirements for Security", BCP 106, RFC 4086,
              June 2005.

   [RFC3749]  Hollenbeck, S., "Transport Layer Security Protocol
              Compression Methods", RFC 3749, May 2004.

   [RFC4366]  Blake-Wilson, S., Nystrom, M., Hopwood, D., Mikkelsen, J.,
              and T. Wright, "Transport Layer Security (TLS)
              Extensions", RFC 4366, April 2006.

   [RSA]      R. Rivest, A. Shamir, and L. M. Adleman, "A Method for
              Obtaining Digital Signatures and Public-Key
              Cryptosystems", Communications of the ACM, v. 21, n. 2,
              Feb 1978, pp. 120-126.

   [SEQNUM]   Bellovin, S., "Defending Against Sequence Number Attacks",
              RFC 1948, May 1996.

   [SSL2]     Hickman, Kipp, "The SSL Protocol", Netscape Communications
              Corp., Feb 9, 1995.

   [SSL3]     A. Freier, P. Karlton, and P. Kocher, "The SSL 3.0
              Protocol", Netscape Communications Corp., Nov 18, 1996.

   [SUBGROUP] Zuccherato, R., "Methods for Avoiding the "Small-Subgroup"
              Attacks on the Diffie-Hellman Key Agreement Method for
              S/MIME", RFC 2785, March 2000.

   [TCP]      Postel, J., "Transmission Control Protocol", STD 7, RFC
              793, September 1981.

   [TIMING]   Boneh, D., Brumley, D., "Remote timing attacks are
              practical", USENIX Security Symposium 2003.

   [TLSAES]   Chown, P., "Advanced Encryption Standard (AES)
              Ciphersuites for Transport Layer Security (TLS)", RFC
              3268, June 2002.

   [TLSECC]   Blake-Wilson, S., Bolyard, N., Gupta, V., Hawk, C., and B.
              Moeller, "Elliptic Curve Cryptography (ECC) Cipher Suites
              for Transport Layer Security (TLS)", RFC 4492, May 2006.

   [TLSEXT]   Eastlake, D., 3rd, "Transport Layer Security (TLS)
              Extensions:  Extension Definitions", Work in Progress,
              February 2008.


   [TLSPGP]   Mavrogiannopoulos, N., "Using OpenPGP Keys for Transport
              Layer Security (TLS) Authentication", RFC 5081, November
              2007.

   [TLSPSK]   Eronen, P., Ed., and H. Tschofenig, Ed., "Pre-Shared Key
              Ciphersuites for Transport Layer Security (TLS)", RFC
              4279, December 2005.

   [TLS1.0]   Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
              RFC 2246, January 1999.

   [TLS1.1]   Dierks, T. and E. Rescorla, "The Transport Layer Security
              (TLS) Protocol Version 1.1", RFC 4346, April 2006.

   [X501]     ITU-T Recommendation X.501: Information Technology - Open
              Systems Interconnection - The Directory: Models, 1993.

   [XDR]      Eisler, M., Ed., "XDR: External Data Representation
              Standard", STD 67, RFC 4506, May 2006.

工作組信息
略。

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