數據報傳輸層安全(DTLS)1.2版

1. 介紹

   TLS [TLS]是使用最廣泛的網絡流量安全協議。它被廣泛用於保護網頁流量和電子郵件協議如IMAP [IMAP]和POP [POP]。TLS的主要優勢是它提供了一個透明的有向通道。因此,它容易通過在應用側鞥和傳輸層插入TLS來保護應用層協議。然而,TLS必須運行與一個可靠的傳輸信道 -- 典型的是TCP [TCP]。因此,它不能被用於保護不可靠的數據報流量。

   使用UDP傳輸的應用層協議的數量在增加。特別是像會話發起協議(SIP)[SIP]和電子遊戲協議這樣的協議越發流行。(需要注意的是SIP能既能運行於TCP也能運行於UDP之上,但有一些情況用UDP更合適)當前,這些應用的設計者面臨着大量的不能令人滿意的選擇。首先,他們可以使用IPsec [RFC4301]。然而,由於在[WHYIPSEC]中詳細列出的原因,這個方案只能對一些應用適用。第二,他們可以設計一個定製的應用層安全協議。不幸的是,雖然應用層安全協議通常提供較好的安全特性(例如,在S/MIME應用場景中的端到端安全),他們通常需要做大量的工作進行設計 -- 相對比將協議運行在TLS上需要相對小的工作量。

   在很多情況下,保證client/server應用安全的最好方法是使用TLS;然而,數據報語義的需求自動禁止了使用TLS。本文描述了一種協議來實現這種給你:數據報傳輸層安全(DTLS)。DTLS是特意設計成儘可能與TLS相似,這樣既能最小化新的安全發明也能最大化重用代碼和基礎設施。

   DTLS 1.0 [DTLS1]最初被定義爲[TLS11]的一個增量。本文介紹了DTLS的一個新版本,DTLS 1.2,它被定義爲TLS 1.2 [TLS12]的一個增量系列。沒有DTLS 1.1;這個版本被跳過以便與TLS的版本號相協調。這個版本也會澄清一些與DTLS 1.0的規範相混淆的點。

   同時支持DTLS 1.2和DTLS的實現能與聲明支持只支持DTLS 1.0的協議互操作 (當然要使用DTLS 1.0), 正如TLS 1.2的實現能與之前的TLS版本(詳見[TLS12]的Appendix E.1)互操作一樣。例外的是沒有SSLv2和SSLv3的DTLS,所以對這些協議並沒有應用後向兼容。

1.1. 需求術語

   略。

2. 使用模式

   DTLS協議被設計用來保證應用通信數據的安全。它被設計在應用層運行,不需要對內核做任何修改。

   數據報傳輸不要求或提供可靠的或有序的數據傳輸。DTLS協議爲負載數據保留了這特性。諸如流媒體,網絡電話和在線遊戲這樣的應用使用數據報進行通信本質上是由於對傳輸數據的延遲敏感。當使用DTLS進行安全通信時這類應用的行爲不會改變,因爲DTLS協議不會補償丟失或重排序數據流量。

3. DTLS概覽

   設計DTLS的基本思想是構建“數據報傳輸之上的TLS”。TLS不能直接用於數據報環境的原因只是包可能會丟失或重排序。TLS沒有內部機制能處理這種不可靠性;因此,當移植到數據報傳輸上之後TLS實現就會崩潰。DTLS的目的是對TLS做最小的變更來解決這個問題。最大程度的可能是DTLS與TLS相同。無論何時我們需要發明新的機制時,我們都會試圖保留TLS的風格。

   不可靠性對TLS產生了兩個方面的問題:

      1. TLS不運行對單個記錄進行獨立解密。因爲完整性檢查依賴於序列號,如果記錄N沒有收到,對記錄N+1的完整性檢查會基於錯誤的序列號進行從而會失敗。(需要注意的是對於TLS 1.1之前的版本沒有顯式IV,而且這樣解密也會錯誤。——

      2. TLS握手層假定握手消息是可靠投遞的,如果消息丟失則會中斷。

   本節的其餘部分描述了DTLS用來解決這些問題的方法。

3.1. 丟失不敏感報文發送

   在TLS的流量加密層(被稱爲TLS記錄層),記錄並不是獨立的。有兩種記錄間依賴:
      1. 密碼學上下文(流密碼密鑰流)在記錄間保留。
      2. 抗重放和消息亂序保護由一個包含了序列號的MAC來提供,但序列號在記錄中是隱藏的。

   DTLS通過禁止流密碼解決了第一個問題。DTLS通過增加顯式序列號解決了第二個問題。

3.2. 爲握手提供可靠性

   TLS握手是一個古板的密碼學握手。消息必須以確定的順序被傳輸和接收;任何其它的順序都是錯誤的。很明顯,這與重排序和消息丟失不兼容。此外,TLS握手消息潛在地比任何給定的數據報大,因此會產生IP分片問題。DTLS必須解決這些問題。

3.2.1. 包丟失

   DTLS使用了一個簡單的重傳定時器來處理包丟失。下圖使用了DTLS握手的第一階段表明基本流程:

         Client                                   Server
         ------                                   ------
         ClientHello           ------>

                                 X<-- HelloVerifyRequest
                                                  (lost)

         [Timer Expires]

         ClientHello           ------>
         (retransmit)

   一旦client傳輸了ClientHello消息,它會期望看到從server發來的一個 HelloVerifyRequest。然而,如果這個server的消息丟失了,client就會知道ClientHello或者HelloVerifyRequest已經丟失,然後重傳。當server收到重傳包時,它就會知道重傳發生了。Server也維持了一個重傳定時器,當其超時後會重傳。
   需要注意的是超時和重傳並不應用於HelloVerifyRequest,因爲這需要在server上創建狀態。HelloVerifyRequest被設計的足夠小以避免自身被分片,因此可以不用考慮多個HelloVerifyRequest交叉的情況。

3.2.2. 重排序

   在DTLS中,每個握手消息會在握手中被分配一個明確的序列號。當一個對端收到一個握手消息時,它能快速確定這個消息是否是它所期望接收的下一個消息。如果是,它會進行處理。如果不是,它會將其放入隊列中,在將來一旦所有缺失的消息都收到後再進行處理。

3.2.3. 消息大小

   TLS和DTLS握手消息可能會相當大(理論上可以達到的上限是2^24-1字節,實際上是很多個K字節);相比值之下,UDP報文通常被限制在小於1500字節,如果不想要
分片的話。爲了補償這個限制,每個DTLS握手消息可以在幾個DTLS記錄中進行分片,每個DTLS記錄都會試圖適應一個單個IP數據報。每個DTLS握手消息包含一個分片偏移和分片長度。因此,一個擁有一個握手消息所有字節的接受者能夠重組原始的未分片消息。

3.3. 重放保護

   DTLS選擇性地支持記錄重放探測。所使用的技術與IPsec AH/ESP相同,是通過維護接收記錄的一個位圖窗口實現的。因爲太老而不適合窗口的記錄和以前接收過的記錄都會被悄悄地丟棄。重放探測特性是可選的,因爲包的重複並不總是惡意的,可能會因爲路由錯誤而出現。應用可以可信地探測重複報文並相應地修改它們的數據重傳策略。

4. 與TLS的差異

    正如第3節所說,DTLS本質上與TLS十分相似。因此,我們把DTLS作爲TLS 1.2 [TLS12]的一個補充,而非作爲一個新的協議提出。在我們沒有顯式指出差異的地方,DTLS與[TLS12]相同。

4.1 記錄層  

DTLS記錄層與TLS 1.2及其相似。唯一的變化是在記錄中包含了一個顯式序列號。這個序列號允許接收者正確地驗證TLS MAC。DTLS記錄格式顯示如下:

      struct {
           ContentType type;
           ProtocolVersion version;
           uint16 epoch;                                    // New field
           uint48 sequence_number;                          // New field
           uint16 length;
           opaque fragment[DTLSPlaintext.length];
         } DTLSPlaintext;

   類型
      與TLS 1.2記錄層的type域相同。

   version
      協議所使用的版本。本文描述了DTLS 1.2版本,其使用的版本是{ 254, 253 }。254.253的版本值是DTLS版本1.2的第一個補碼。TLS和DTLS版本號之間的最大化空間保證了兩個協議的記錄能夠很容易地區分。需要注意的是將來DTLS發送到網絡上的版本在數值上是遞減的(而其真實的值是遞增的)。

   epoch
      一個計數值,每次密碼狀態變化都會增加。

   sequence_number
      本記錄的序列號。

   length
      與TLS 1.2記錄層的length域相同。如TLS 1.2中一樣,這個長度不超過2^14

   fragment
      與TLS 1.2記錄層的fragment域相同。

   DTLS使用了一個顯式序列號,而不是一個隱式的,這個序列號位於記錄中的sequence_number域。對於每個epoch序列號都單獨維護,對於每個epoch每個sequence_number都會被初始化爲0.例如,如果一個epoch爲0的握手消息被重傳了,它可能會擁有一個在一個epoch 1的消息之後的序列號,即使epoch 1的消息被首先重傳。需要注意的是在握手階段需要多加關注以確保重傳消息使用了正確的epoch和密鑰材料。

   如果多次握手是密切連續進行,可能會在線路上產生多個相同序列號但不同密碼狀態的記錄。Epoch域允許接收者區別這樣的包。Epoch號初始化爲0且在每次發送一個ChangeCipherSpec時增長。爲了確保任何給定的序列號/epoch對是獨特的,實現上必須不能允許相同的epoch值在兩個TCP最大報文段生命週期被重用。實際上,TLS實現很少重新握手;因此我們不期望這會成爲一個問題。


   需要注意的是由於DTLS記錄可以被重排序,一個來自epoch 1的記錄可能會在eopch 2開始後被收到。通常,實現上應該丟棄更早epoch的包,但如果包丟失會導致需要引起注意的問題,實現上可以選擇保留以前epoch中的密鑰材料直到TCP [TCP]所指定的默認最大報文段生存時間(MSL),以允許包的重新排序。(需要注意的是此處的意圖是實現者使用IETF當前關於MSL的指導,而不是讓實現者嘗試獲取系統TCP協議棧正在使用的數值)。握手完成後,實現必須接受來自舊的epoch的包。

   相反,對於由最新協商的上下文保護的記錄,在一個握手完成之前被接受是可能的。例如,server可以發送它的Finished消息,然後開始傳輸數據。實現上可以緩存或者丟棄這樣的包,雖然當DTLS運行於可靠傳輸協議(如:SCTP)之上時,這些消息應該被緩存,一旦握手完成就應該被處理。需要注意的是TLS對何時發送數據包的限制仍然有效,接收者會將它們做爲按照正確順序發送的包一樣對待。特別地,在完成第一個模式之前發送數據仍然是不允許的。

   需要注意的是在一個現存連接的重握手的特殊情況下,立即處理數據包會是安全的,即使ChangeCipherSpec或Finished消息沒有被收到。這種情況是或者重握手消息恢復現存會話或使用與現存連接完全相同的安全參數。在任意其它情況下,實現上必須等待接收Finished消息以阻止降級攻擊。

   在TLS中,實現上必須拋棄一個連接或在允許序列號迴繞之前重握手。相似地,實現上必須不能允許eopch迴繞,但作爲替代必須建立一個新的連接,像4.2.8節描述的那樣終止舊的連接。在實踐上,實現上很少在一條通道上重複進行重握手,所以這不太可能會成爲一個問題。

4.1.1. 傳輸層映射

   每個DTLS記錄必須能夠放入單個數據報內。爲了避免IP分片,DTLS記錄層的client應該嘗試改變記錄的大小以使其能適應從記錄層獲得的任何路徑MTU的估算值。
   需要注意的是與IPsec不同,DTLS記錄不包含任何連接標識符。應用必須在多個連接之間實現標誌多路複用。在使用UDP時,這個功能很可能由host/port號來實現。

   多個DTLS記錄可以被放入單個數據報內。它們會被簡單地進行連續編碼。DTLS記錄框架足以確定邊界。需要注意的是,數據報負載的第一個字節必須是一個記錄的開頭。記錄可能不會跨越數據報。

   一些傳輸層協議,如DCCP [DCCP]會提供他們自己的序列號。當運行在這些傳輸層協議之上時,DTLS和傳輸層序列號都會出現。雖然這樣導致了少量的效率損失,但傳輸層和DTLS序列號的作用是不同的。因此,爲了概念的簡單性,DTLS會優先使用這兩種序列號。在將來,DTLS的擴展可能會確定只允許使用一種序列號用於在受限的環境中部署。

   一些傳輸層協議,如DCCP,爲它們所承載的流量提供了擁塞控制。如果擁塞窗口足夠小,DTLS握手的重傳可能會阻塞而不是立即傳輸,潛在地導致超時和假重傳。當DTLS被用於這類傳輸層協議時,必須多加小心不要超過可能的擁塞窗口。[DCCPDTLS]定義了一個DTLS到DCCP的映射,已將這些問題考慮在內。

4.1.1.1. 路徑MTU問題

  通常,DTLS的哲學是將PMTU發現留給應用。然而,基於以下原因DTLS不能完全忽略PMTU:
   -  DTLS記錄結構擴展了數據報大小,因此從應用的角度看會降低PMTU的效率。
   -  在一些實現中,應用可能不會直接與網絡進行交互,這種情況下DTLS協議棧可以In some implementations, the application may not directly talk to
      the network, in which case the DTLS stack may 使用ICMP [RFC1191] "數據報太大" 標識或ICMPv6 [RFC4443] "包太大"標識。
   -  DTLS握手消息可以超過PMTU。

   爲了處理前兩個問題,DTSL記錄層應該按照如下描述進行處理。

   如果PMTU估計值能從其使用的傳輸層協議獲取,他們也從能被上層協議處理。特別地:

   -  對於DTLS over UDP, 上層協議應該被允許獲取IP層維護的PMTU估計值。

   -  對於DTLS over DCCP, 上層協議應該被允許獲取當前的的PMTU估計值。

   -  對於DTLS over TCP或SCTP, 它們會自動分配和重組報文,沒有PMTU限制。然而,上層協議寫任何記錄都不能超過最大記錄大小2^14字節。

   DTLS記錄層應允許上層協議發現DTLS處理所期望的記錄擴展的數量。需要注意的是這個數量僅僅是一個估計,因爲塊填充或可能使用DTLS壓縮。

   如果有一個傳輸層協議表明(或者通過ICMP協議或者通過一個拒絕消息;按照第14章中的[DCCP]),然後DTLS記錄層必須告知處理錯誤的上層協議。

   DTLS記錄層不應該與上層協議進行交互來實現PMTU發現(通過RFC1191]或[RFC4821])。特別地:

   -  在下面的傳輸層協議中允許這樣做, 上層協議應該被允許設置DF位的狀態(在IPv4中) 或者禁止本地分配(在IPv6中)。

   -  如果下面的傳輸層協議允許應用層請求PMTU探測(例如,DCCP),DTLS記錄層應該尊重這種請求。

   最後的問題是DTLS握手協議。從DTLS記錄層的角度考慮,這僅僅是另外一種上層協議。然而,DTLS握手並不頻繁發生而且僅產生了一點往返時延;因此,握手協議對PMTU的處理是在精確的PMTU發現之上設置了一個快速完成的保險機制。爲了允許在這些條件下建立連接,DTLS實現應該遵循以下規則:
   
   -  如果DTLS記錄層告知DTLS握手層一個消息太大了,它應該立即嘗試使用任何關於PMTU的信息對其進行分片。

   -  如果重複的重傳沒有得到響應,且PMTU未知,隨後的重傳應該回退到一個更小的記錄尺寸,合適地對握手消息進行分片。這個標準沒有指定一個精確的回退之前嘗試重傳的次數,但2-3次看起來合適。

4.1.2. 記錄負載保護

   像TLS一樣,Like TLS, DTLS將數據作爲被保護記錄的一個序列進行傳輸。本節的其餘部分會描述這個格式的細節。

4.1.2.1. MAC

    DTLS MAC與TLS1.2的相同。然而,不同於TLS使用隱式序列號,用於計算MAC的序列號是64位的值,是由epoch和數據出現在線路上的序列號級聯而成。需要注意的是DTLS epoch + 序列號與TLS序列號的長度相同。

    TLS MAC計算在協議版本號上是參數化的。對於DTLS,是線路上的版本,如:對於TLS 1.2是{254,253}。

    需要注意的是DTLS與TLS MAC處理方法的一個重要差別是在TLS中,MAC錯誤必須導致連接中斷。對於DTLS,接收的實現可以簡單地丟棄不想要的記錄然後繼續維持連接。這個變化可能是由於DTLS記錄並不像TLS的記錄那樣彼此依賴。
    通常,DTLS實現上應該默默丟棄MAC錯誤或其它部分無效的記錄。它可以將錯誤信息記錄成一條日誌。如果一個DTLS實現在收到一個MAC無效的消息時選擇生成一個警報,它必須生成一個bad_record_mac alert。

    需要注意的是DTLS與TLS MAC處理方法的一個重要差別是在TLS中,MAC錯誤必須導致連接中斷。對於DTLS,接收的實現可以簡單地丟棄不想要的記錄然後繼續維持連接。這個變化可能是由於DTLS記錄並不像TLS的記錄那樣彼此依賴。
    通常,DTLS實現上應該默默丟棄MAC錯誤或其它部分無效的記錄。它可以將錯誤記錄一條日誌。如果一個DTLS實現在收到一個MAC無效的消息時選擇生成一個警報,它必須生成一個fatal級別的bad_record_mac alert並且中止它的連接。需要注意的是由於錯誤並不會導致連接中止,DTLS棧是比TLS棧更高效的錯誤類型顯示(oracles)。因此,尤其重要的是TLS12 6.2.3.2節的建議應該被遵循。

4.1.2.2. 空或標準流密碼

   DTLS空密碼的作用與TLS 1.2的空密碼完全相同
   在TLS 1.2中描述的唯一一個流密碼是RC4, 它不能被隨機訪問。RC4不能用於DTLS。

4.1.2.3.  塊密碼

   DTLS塊密碼加密和解密的操作與TLS 1.2完全相同。

4.1.2.4.  帶額外數據的認證加密

   TLS 1.2介紹了帶額外數據的認證加密(AEAD)密碼族。現存的AEAD密碼族(在[ECCGCM]和[RSAGCM]中定義,能夠像TLS 1.2中的那樣被用於DTLS。

4.1.2.5. 新密碼族

   在註冊時,新的密碼族必須標明它們是否適用於DTLS,並且應當做何種適配(如果有)。見第7節 IANA的考慮。

4.1.2.6. 抗重放

    DTLS記錄包含一個序列號以提供重放保護。序列號的校驗應遵循下面的滑動窗口流程,借鑑自3.4.3節。
會話的接收報文的計數必須在會話建立時被初始化爲0.對於每個已接收到的記錄,接收者必須驗證記錄中包含的序列號沒有與在這個會話的生命週期內接收到的任何其它記錄的序列號重複。這應該是在與會話匹配後應用於數據包的第一個檢查,以加快對重複記錄的拒絕。

    丟棄重複數據通過一個滑動接收窗口來實現(這個窗口如何實現是一個局部的事情,但下面的文字描述了實現上必須展示的功能)。必須支持最小爲32的窗口大小,但大小是64的窗口更被推薦且應該被設置爲默認值。其它的窗口大小(大於最小值)可以由接收者選擇。(接收者不能告知發送者窗口的大小)

    窗口的右邊緣代表着當前會話接收到的最高有效序列號的值。序列號比窗口左邊緣低的記錄會被丟棄。落入窗口範圍內的包會依據在窗口中接收到的包的列表進行檢查。執行這種檢查的一個有效的方法(基於使用位掩碼)在3.4.3節中描述。

    如果接收到的記錄落入窗口中且是新的,或者包處於窗口的右邊緣,接收者會進行MAC驗證。如果MAC驗證失敗,接收者必須丟棄接收到的非法記錄。僅當MAC驗證成功時接收窗口才能更新。

4.1.2.7. 處理非法記錄

    與TLS不同,在面對非法記錄時DTLS更容易恢復(例如:非法的格式,長度,MAC等等)。通常,非法的記錄應該被靜悄悄地丟棄,因此保持了當前連接。然而,一個錯誤可以被記錄日誌用於診斷。實現上如果選擇了生成一個警報來替代日誌,則必須產生fatal級別的警報以避免攻擊者重複探測實現來觀察其對各種錯誤類型的反應。需要注意的是如果DTLS運行在UDP之上,任何執行這個操作(生成警報)的實現都極易遭受拒絕服務(DoS)攻擊,因爲僞造UDP報文十分容易。因此,這個功能並不推薦應用於這樣的傳輸層協議。

    如果DTLS是被一個抗僞造的傳輸層協議(例如,帶SCTP-AUTH的SCTP)所承載,則發送警報會更安全因爲一個攻擊者很難僞造一個不會被傳輸層丟棄的報文。

4.2. DTLS握手協議

    DTLS使用的所有握手消息與TLS相同,但有3個主要的區別:
1.增加了一個無狀態的cookie交換以防止拒絕服務攻擊。
2.修改了握手報文頭以處理消息丟失、亂序和DTLS消息分片(爲了避免IP分片)
3.設置了重傳定時器以處理消息丟失。

    除了上述區別,DLS消息格式,流,和邏輯與TLS 1.2一樣。

4.2.1.拒絕服務的對策

    數據報安全協議極容易遭受各種DoS攻擊。有兩種攻擊尤其需要考慮:
    1. 一個攻擊者可以傳送一系列握手初始化請求給server,導致server分配資源且有可能執行高資源消耗的密碼學操作,從而導致server消耗大量的資源。
    2. 一個攻擊者可以發送使用受害者源地址僞造的連接初始化消息給server,這樣就能將server用作放大器。Server隨後會發送下一條消息(在DTLS中,一個證書消息可能相當大)給受害者的機器,從而導致泛洪攻擊。

    爲了應對者兩種攻擊,TLS借鑑了由Photuris [PHOTURIS] 和IKE[IKEv2]所使用的無狀態cookie技術。當client發送它的ClientHello消息給server時,server可以用HelloVerifyRequest消息來響應。這個消息包含了一個由[PHOTURIS]技術生成的無狀態cookie。Client必須重傳添加這個cookie的ClientHello消息。然後server驗證cookie,僅當cookie有效時纔會繼續進行握手處理。這個機制強迫攻擊者/client能夠接收cookie,這樣會使得使用虛假IP地址的DoS攻擊難以進行。這個機制不能防禦從用合法IP地址進行的DoS攻擊。

    交互流程顯示如下:
      Client                                   Server
      ------                                   ------
      ClientHello           ------>

                            <----- HelloVerifyRequest
                                   (contains cookie)

      ClientHello           ------>
      (with cookie)

      [握手的其餘流程]

    由此DTLS修改了ClientHello消息來添加cookie。
struct {
     ProtocolVersion client_version;
     Random random;
     SessionID session_id;
     opaque cookie<0..2^8-1>;                             // New field
     CipherSuite cipher_suites<2..2^16-1>;
           CompressionMethod compression_methods<1..2^8-1>;
   } ClientHello;

    當我們發送第一個ClientHello消息時,client還沒有cookie;這種情況下,cookie域留空(0長度)。

    HelloVerifyRequest的定義如下:
struct {
     ProtocolVersion server_version;
     opaque cookie<0..2^8-1>;
   } HelloVerifyRequest;

    HelloVerifyRequest消息的類型是hello_verify_request(3)。

    Server_version域與TLS中的語法結構一樣。然而,爲了避免在初始握手過程中進行版本號的協商,DTLS 1.2 server實現應當使用DTLS 1.0版本而不理會TLS期望協商的版本號是什麼。DTLS 1.2和1.0 client必須僅能將版本號用於顯示包的格式(這對於DTLS 1.2和1.0是相同的),不能作爲版本協商的一部分。特別地,DTLS 1.2 client必須不能假定由於server在HelloVerifyRequest中使用了版本1則server不會是DTLS 1.2或最終一定協商出 DTLS 1.0而不是DTLS 1.2。

    當響應一個HelloVerifyRequest時,client必須使用與原始的ClientHello相同的參數值(版本,隨機數,會話ID,密碼族,壓縮算法)。Server應該使用這些值來生成它的cookie且使用收到的cookie來驗證這些值是否正確。Server必須使用與HelloVerifyRequest中使用的相同的版本號來發送一個ServerHello。在收到ServerHello時,client必須驗證server版本號是否匹配。爲了避免序列號在多個HelloVerifyRequest中重複,server必須將ClientHello中的記錄序列號用作HelloVerifyRequest中的記錄序列號。
注:本規範將cookie的大小增加到255字節以增加將來的靈活性。對於以前版本的DTLS仍限制在32.

    DTLS Server應該以一種方式來生成cookie,以至於它們可以不在server端保存任何每client的狀態的情況下也可以被驗證。一種技術是用一個隨機產生的機密數據並用如下的方式產生cookie:
    Cookie = HMAC(Secret, Client-IP, Client-Parameters)

    當收到第二個ClientHello時,server可以驗證Cookie是否合法,client能夠基於設定的IP接收數據包。爲了避免序列號在交換多個cookie時重複,server必須將ClientHello中的記錄序列號用作它發起的ServerHello中的記錄序列號。隨後ServerHello僅在sever產生了狀態之後才能發生,且必須正常遞增。

    對於這個方案的一個潛在的攻擊是攻擊者收集大量來自不同地址的cookie然後重新使用它們來攻擊server。Server可以通過頻繁改變cookie的值從而使這些cookie失效來防禦這種攻擊。如果server希望合法的client能通過這個改變過程實現握手(例如,它們接收到了一個帶有機密1的cookie然後在server改變爲機密2之後發送第二個ClientHello),server可以限制它接受這兩個機密的窗口大小。[IKEv2]建議添加一個版本號到cookie中以檢測這種情況。一個另外的方法是簡單地帶着這兩個機密進行驗證。

    DTLS Server應該在任何時候執行握手時進行cookie的交互。如果server在一個擴大不成問題的環境中被操作,server可以被配置爲不執行cookie交換。然而默認是執行交換。此外,server可以選擇當一個會話被恢復後不執行cookie交換。Client必須準備好在任何握手中執行cookie交換。

    如果使用了HelloVerifyRequest,初始的ClientHello和HelloVerifyRequest不會被包含在handshake_message(包含CertificateVerify消息)和verify_data(對應Finished消息)的計算中。

    如果一個server收到了一個帶有無效cookie的ClientHello消息,它應當將其當做無cookie的ClientHello消息處理。這樣避免了競爭/死鎖的條件,如果client某種程度上獲得了一個壞的cookie(例如,由於server改變了cookie的簽名密鑰)。

    實現者需要注意:這可能會導致client接收到多個帶有不同cookie的HelloVerifyRequest消息。Client應當這樣處理:發送一個帶有一個cookie新的ClientHello以響應新的HelloVerifyRequest。

4.2.2. 握手消息格式

    爲了支持消息丟失,亂序和消息分片,DTLS修改了TLS 1.2握手頭:
   struct {
     HandshakeType msg_type;
     uint24 length;
     uint16 message_seq;                               // New field
     uint24 fragment_offset;                           // New field
     uint24 fragment_length;                           // New field
     select (HandshakeType) {
       case hello_request: HelloRequest;
       case client_hello:  ClientHello;
       case hello_verify_request: HelloVerifyRequest;  // New type
       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;

    兩邊在每次握手時傳輸的第一個消息message_seq一直是0.無論何時每個新消息被生成時,message_seq的值都會加1.需要注意的是在重握手的情況,這意味着HelloRequest將會設置message_seq爲0,ServerHello的message_seq爲1.當一個消息被重傳時,會使用相同的message_seq。例如:
         Client                             Server
         ------                             ------
         ClientHello (seq=0)  ------>

                                 X<-- HelloVerifyRequest (seq=0)
                                                 (lost)

         [Timer Expires]

         ClientHello (seq=0)  ------>
         (retransmit)

                              <------ HelloVerifyRequest (seq=0)

         ClientHello (seq=1)  ------>
         (with cookie)

                              <------        ServerHello (seq=1)
                              <------        Certificate (seq=2)
                              <------    ServerHelloDone (seq=3)

         [Rest of handshake]

    注意,然而,從DTLS記錄層的角度來看,重傳是一個新的記錄。這個記錄將會有一個新的DTLSPlaintext.sequence_number值。

    DTLS實現維持(至少是想象的)一個next_receive_seq計數器。這個計數器初始化爲0.當接收到一個消息時,如果序列號與next_receive_seq匹配,則next_receive_seq遞增並且消息被處理。如果序列號小於next_receive_seq,消息必須被丟棄。如果序列號大於next_receive_seq,實現上應當將這個消息放入隊列但可以丟棄。(這是一個簡單的空間/帶寬折衷)。

4.2.3. 握手消息分片與重組

    正如4.1.1節中所記,每個DTLS消息必須在單個傳輸層報文內。然而,握手消息極可能比最大記錄大小大。因此,DTLS提供另一種機制用於將一個握手消息分片爲多個記錄,每個記錄可以被分別傳送,從而避免了IP分片。

    當傳輸握手消息時,發送者將消息分爲N個連續的數據序列。這些序列不能大於最大握手分片大小且必須共同地包含整個握手消息。這些序列不應重疊。發送者隨後產生了N個握手消息,它們都擁有與原始的握手消息相同的message_seq。每個新消息都由fragment_offset(前一個分片包含的字節數)和fragment_length(這個分片的長度)來標識。所有消息的length域都與原始的消息相同。一個未分片的消息是一種退化的情況:fragment_offst=0且fragment_length=length。

    當一個DTLS實現收到一個握手分片時,它必須緩存它直到它收到整個握手消息。DTLS實現必須能夠處理重疊的分片序列。這允許發送者在PMTU估計值發生變化時使用更小的分片大小重傳握手消息。

    需要注意的是與TLS相同,多個握手消息可以被放置於相同的DTLS記錄中,條件是有空間且它們是一次傳送的一部分。因此,有兩種方式可以將兩個DTLS消息打包到相同的報文中:在相同的記錄中或在分開的記錄中。

4.2.4. 超時和重傳

    DTLS消息可以組入到一系列消息傳送(Flight)中,如下圖所顯示的。雖然每次消息的傳送可能有多個消息組成,但從超時和重傳的角度它們應當被看做是整體的。
Client                                          Server
   ------                                          ------

   ClientHello             -------->                           Flight 1

                           <-------    HelloVerifyRequest      Flight 2

   ClientHello             -------->                           Flight 3

                                              ServerHello    \
                                             Certificate*     \
                                       ServerKeyExchange*      Flight 4
                                      CertificateRequest*     /
                           <--------      ServerHelloDone    /

   Certificate*                                              \
   ClientKeyExchange                                          \
   CertificateVerify*                                          Flight 5
   [ChangeCipherSpec]                                         /
   Finished                -------->                         /

                                       [ChangeCipherSpec]    \ Flight 6
                           <--------             Finished    /

               Figure 1. 整個握手的消息傳送


   Client                                           Server
   ------                                           ------

   ClientHello             -------->                          Flight 1

                                              ServerHello    \
                                       [ChangeCipherSpec]     Flight 2
                            <--------             Finished    /

   [ChangeCipherSpec]                                         \Flight 3
   Finished                 -------->                         /

         Figure 2. 會話恢復握手的消息傳送(無Cookie交換)

    DTLS使用了基於下面的狀態機的一個簡單的超時和重傳機制。由於DTLS client發送第一個消息(ClientHello),它們從PREPARING狀態開始。DTLS Server在WAITING狀態開始,但緩衝區爲空且無重傳定時器。


          Figure 3. DTLS超時和重傳狀態機

    這個狀態機有三個基本狀態。

    在PREPARING狀態,實現上會做所有備消息的內容所必須的計算。然後它會將它們緩存起來用於傳輸(首先將緩存清空)並進入SENDING狀態。

    在SENDING狀態,實現會傳輸緩存的消息。一旦消息發送出去了,如果是握手的最後一個消息實現就會進入FINISHED狀態。或者,如果實現希望收到更多消息,它會設置一個重傳定時器然後進入WAITING狀態。

    有三種方式退出WAITING狀態:

    1.重傳定時器超時:實現轉換到SENDING狀態,在那裏它重傳已發送的包,重置重傳定時器,然後回到WAITING狀態。
    2.實現從對端讀取了一個重傳的包:實現轉換到SENDING狀態,在那裏它重傳已發送的包,重置重傳定時器,然後回到WAITING狀態。這裏的理論是收到一個重複的包可能是對端的定時器超時所導致,因此標明以前發送的包的一部分已經丟失。
    3.實現收到了下一個發送的消息:如果這是最後一個消息,實現轉換到FINISHED。如果實現需要發送一個新的包,它轉換到PREPARING狀態。部分讀取(或者是部分消息或者只是已發送消息中的一些)不好導致狀態機轉換或定時器重置。

    由於DTLS client發送了第一個消息(ClientHello),它們開始於PREPARING狀態。DTLS Server開始於WAITING狀態,但緩存爲空且沒有重傳定時器。

    當server需要重新握手時,它從FINISHED狀態轉換到PREPARING狀態以傳送HelloRequest。當client收到一個HelloRequest時,它從FINISHED狀態轉換到PREPARING狀態以傳送ClientHello。

    此外,在FINISHED狀態達到至少兩個默認的TCP MSL時間時,傳輸最後一個報文的節點(處於普通握手過程中的server或處於握手恢復過程中的client)必須重傳最後一個報文來響應對端最後一個報文的重傳。這樣可以避免當最後一個報文丟失時產生死鎖。這個要求也適用於DTLS 1.0,雖然在[DTLS1]中沒有明確要求,但對狀態機能正常工作的要求一直都有。如果要了解爲什麼這樣是必要的,考慮下在一個通常的握手過程中如果server的結束消息丟失:server相信握手完成了但實際上沒有。在client等待結束消息時,client的重傳定時器會啓動並且會重傳client的結束消息。這將會導致server用自己的結束消息來響應,完成握手。同樣的邏輯也適用於恢復握手過程中的server端。

    需要注意的是由於報文丟失,一端可能會發送應用數據即使對端並沒有收到它的結束消息。實現上必須或者丟棄或者緩存所有用於新epoch的應用數據報文直到它們收到這個epoch的結束消息。實現上可以將收到應用數據的epoch在其對應的結束消息的epoch之前看做是亂序或包丟失的證據,立即重傳它們的最後一個報文,從而簡化重傳定時器。

4.2.4.1. 定時器數值

    雖然定時器的數值是實現上的選擇,但定時器的錯誤處理能導致嚴重的擁塞問題;例如,如果一個DTLS的很多實例過早超時並在一條擁塞的鏈路上過快重傳。實現上應該使用1秒作爲定時器初始值(最小值定義於RFC 6298[RFC6298]中)每次重傳使該值加倍,直到不少於RFC 6298的最大60秒。需要注意的是我們推薦1秒的定時器而不是3秒的RFC 6298默認值以提升對時間敏感應用的延遲性能。由於DTLS只對握手使用重傳而對數據流不使用,對擁塞的影響應該會很小。

    實現應該維持當前定時器的值直到出現沒有丟失的傳輸,這時這個值應當重置爲初始值。在經過一個長的空閒週期(不少於10倍的當前定時器數值)後,實現可以將定時器重置爲初始值。可能發生這種情況的一種場景是在重要的數據傳輸之後產生了一次重握手。

4.2.5. ChangeCipherSpec

    在TLS中,ChangeCipherSpec消息從技術上並非是一個握手消息,但出於超時和重傳考慮,必須將其被作爲相關Finished消息的一部分來進行處理。這樣會產生一個潛在的模糊性,是因爲ChangeCipherSpec不能明確地建立與在消息丟失的情況下的握手消息之間的順序。

    這對於當前的TLS模式並不是問題,因爲邏輯上在ChangeCipherSpec之前的期望的握手消息集從握手的其餘狀態中就能預測出來。然而,將來的模式必須小心以避免產生模糊性。

4.2.6 CertificateVerify和Finished消息

    CertificateVerify和Finished消息的格式與TLS中的相同。Hash計算包含了整個握手消息,包括DTLS-specific域:message_seq,fragment_offset和fragment_length。然而,爲了消除對握手消息分片的敏感,Finished MAC必須在將每個握手消息當做都在一個分片中發送出去的情況下進行計算。需要注意的是當使用了cookie交換時,初始的ClientHello和HelloVerifyRequest必須不能被包含在CertificateVerify或Finished的MAC計算中。

4.2.7 警報消息

    需要注意的是警報消息完全不能重傳,即使它們在握手的過程中出現。然而,一個能夠發起一個警報消息的DTLS實現在再次收到不合法的記錄(例如,一個重傳的握手消息)時應該產生一個新的警報消息。實現應該探測到一個對端持續發送非法消息並且在這種非法行爲被探測到之後中止本地連接。

4.2.8.用現存參數建立新的關聯

    如果一個DTLS client-server對被配置爲重複的連接發生在相同的主機/端口四元組時,client可能會靜靜地丟棄連接然後以相同參數(例如,重啓之後)發起另一個連接。當一個新的握手中的epoch爲0時對於server可能會出現這種情況。如果一個server確信在一個給定的主機/端口四元組上存在着一個關聯且它收到了一個epoch爲0的ClientHello,它應該繼續新的握手但不能銷燬這個存在的關聯,直到client通過完成了一個cookie交換或通過完成一個包括傳輸一個可驗證的Finished消息在內的一個完整的握手來表明了可達性。在收到一個正確的Finished消息後,server必須廢棄之前的關聯以避免在兩個有效的且epoch重疊的聯之間產生衝突。可達性的要求阻止了off-path/blind攻擊者僅僅通過發送僞造的ClientHello就能夠摧毀關聯。

4.3.新語法的總結

    本節包含了在TLS1.2和DTLS1.2之間產生了變化的數據結構的規範。語法的定義見[TLS12]。

4.3.1.記錄層

struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        opaque fragment[DTLSPlaintext.length];
      } DTLSPlaintext;

      struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        opaque fragment[DTLSCompressed.length];
      } DTLSCompressed;

      struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        select (CipherSpec.cipher_type) {
          case block:  GenericBlockCipher;
          case aead:   GenericAEADCipher;                 // New field
        } fragment;
      } DTLSCiphertext;

4.3.2.握手協議

enum {
     hello_request(0), client_hello(1), server_hello(2),
     hello_verify_request(3),                          // New field
     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;
     uint16 message_seq;                               // New field
     uint24 fragment_offset;                           // New field
     uint24 fragment_length;                           // New field
     select (HandshakeType) {
       case hello_request: HelloRequest;
       case client_hello:  ClientHello;
       case server_hello:  ServerHello;
       case hello_verify_request: HelloVerifyRequest;  // New field
       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;

   struct {
     ProtocolVersion client_version;
     Random random;
     SessionID session_id;
     opaque cookie<0..2^8-1>;                             // New field
     CipherSuite cipher_suites<2..2^16-1>;
     CompressionMethod compression_methods<1..2^8-1>; } ClientHello;

   struct {
     ProtocolVersion server_version;
     opaque cookie<0..2^8-1>; } HelloVerifyRequest;

5.安全考慮

    本文描述了一個TLS 1.2的變體;因此,大多數安全考慮與TLS 1.2[TLS12]中的一致,附錄D, E, F中有描述。

    由DTLS引發的主要的額外安全考慮是拒絕服務。DTLS包含了一個交換cookie其設計用來應對拒絕服務。然而,不使用cookie交換的實現對於DoS仍然是脆弱的。尤其是,不能使用這個cookie交換的DTLS server可能會被用作攻擊放大器,即使它們自身並不經歷DoS。因此,DTLS server應該使用cookie交換除非有好的理由相信放大器對於它們的環境並不是威脅。Client必須準備好對每個握手進行cookie交換。

    與TLS實現不同,DTLS實現不應該對非法記錄用終結連接的方式進行響應。細節見4.1.2.7節。

6.致謝

(略)

7.IANA考慮

    本文使用了與TLS [TLS12]相同的標識符空間,所以不需要新的IANA記錄。當新的標識符分配給TLS時,作者必須明確它們是否適用於DTLS。IANA已經修改了所有的TLS參數記錄來增加DTLS-OK標識,表明規範是否可以被用於DTLS。在發佈時,所有的[TLS12]記錄除了下面的都適用於DTLS。記錄的全部表格可以在[IANA]獲得。

    來自TLS 密碼套件記錄:
      0x00,0x03 TLS_RSA_EXPORT_WITH_RC4_40_MD5        [RFC4346]
      0x00,0x04 TLS_RSA_WITH_RC4_128_MD5              [RFC5246]
      0x00,0x05 TLS_RSA_WITH_RC4_128_SHA              [RFC5246]
      0x00,0x17 TLS_DH_anon_EXPORT_WITH_RC4_40_MD5    [RFC4346]
      0x00,0x18 TLS_DH_anon_WITH_RC4_128_MD5          [RFC5246]
      0x00,0x20 TLS_KRB5_WITH_RC4_128_SHA             [RFC2712]
      0x00,0x24 TLS_KRB5_WITH_RC4_128_MD5             [RFC2712]
      0x00,0x28 TLS_KRB5_EXPORT_WITH_RC4_40_SHA       [RFC2712]
      0x00,0x2B TLS_KRB5_EXPORT_WITH_RC4_40_MD5       [RFC2712]
      0x00,0x8A TLS_PSK_WITH_RC4_128_SHA              [RFC4279]
      0x00,0x8E TLS_DHE_PSK_WITH_RC4_128_SHA          [RFC4279]
      0x00,0x92 TLS_RSA_PSK_WITH_RC4_128_SHA          [RFC4279]
      0xC0,0x02 TLS_ECDH_ECDSA_WITH_RC4_128_SHA       [RFC4492]
      0xC0,0x07 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA      [RFC4492]
      0xC0,0x0C TLS_ECDH_RSA_WITH_RC4_128_SHA         [RFC4492]
      0xC0,0x11 TLS_ECDHE_RSA_WITH_RC4_128_SHA        [RFC4492]
      0xC0,0x16 TLS_ECDH_anon_WITH_RC4_128_SHA        [RFC4492]
      0xC0,0x33 TLS_ECDHE_PSK_WITH_RC4_128_SHA        [RFC5489]

    來自TLS輸出者標識記錄:
      client EAP encryption       [RFC5216]
      ttls   keying material      [RFC5281]
      ttls   challenge            [RFC5281]

    本文定義了一個新的握手消息,hello_verify_request,它的值已經從定義在[TLS12]的TLS HandshakeType記錄中分配出來。IANA已經指定的值是3.

8.從DTLS1.0開始的變化

    本文反映了從DTLS1.0開始的如下變化:
- 更新以適應TLS 1.2 [TLS12];
- 在4.1.2.3節(跟隨TLS1.2中的變化)中增加了AEAD密碼;
- 關於4.1節中的序列號和epoch的澄清,以及爲4.2.8節中處理狀態丟失給出了一個明確的步驟;
- 澄清和關於4.1.1.1節中關於路徑MTU問題的更詳細的規則。分片文本的輸出的澄清;
- 對4.1.2.7節中處理非法記錄的澄清;
- 在4.2.1節的末尾增加了一個新的段落描述對非法cookie的處理;
- 在4.2.4節的末尾增加了一些新的文字來描述如何避免握手死鎖條件;
- 在4.2.6節增加了一些新的關於CertificateVerify消息的文字;
- 4.1節防止epoch迴繞的方法;
- IANA需求的澄清和對每個參數的一個新的IANA記錄標誌的明確需求;
- 增加了一個記錄序列號鏡像技術來處理重複的ClientHello消息;
- 爲HelloVerifyRequest推薦了一個固定的版本號;
- 大量編輯上的修改。

9.參考文獻

9.1 標準參考文獻


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

   [RFC1191]   Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
               November 1990.

   [RFC4301]   Kent, S. and K. Seo, "Security Architecture for the
               Internet Protocol", RFC 4301, December 2005.

   [RFC4443]   Conta, A., Deering, S., and M. Gupta, Ed., "Internet
               Control Message Protocol (ICMPv6) for the Internet
               Protocol Version 6 (IPv6) Specification", RFC 4443, March
               2006.

   [RFC4821]   Mathis, M. and J. Heffner, "Packetization Layer Path MTU
               Discovery", RFC 4821, March 2007.

   [RFC6298]   Paxson, V., Allman, M., Chu, J., and M. Sargent,
               "Computing TCP's Retransmission Timer", RFC 6298, June
               2011.

   [RSAGCM]    Salowey, J., Choudhury, A., and D. McGrew, "AES Galois
               Counter Mode (GCM) Cipher Suites for TLS", RFC 5288,
               August 2008.

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

   [TLS12]     Dierks, T. and E. Rescorla, "The Transport Layer Security
               (TLS) Protocol Version 1.2", RFC 5246, August 2008.

9.2 信息性參考文獻

   [DCCP]      Kohler, E., Handley, M., and S. Floyd, "Datagram
               Congestion Control Protocol (DCCP)", RFC 4340, March
               2006.

   [DCCPDTLS]  Phelan, T., "Datagram Transport Layer Security (DTLS)
               over the Datagram Congestion Control Protocol (DCCP)",
               RFC 5238, May 2008.

   [DTLS]      Modadugu, N. and E. Rescorla, "The Design and
               Implementation of Datagram TLS", Proceedings of ISOC NDSS
               2004, February 2004.

   [DTLS1]     Rescorla, E. and N. Modadugu, "Datagram Transport Layer
               Security", RFC 4347, April 2006.

   [ECCGCM]    Rescorla, E., "TLS Elliptic Curve Cipher Suites with
               SHA-256/384 and AES Galois Counter Mode (GCM)", RFC 5289,
               August 2008.

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

   [IANA]      IANA, "Transport Layer Security (TLS) Parameters",
               http://www.iana.org/assignments/tls-parameters.

   [IKEv2]     Kaufman, C., Hoffman, P., Nir, Y., and P. Eronen,
               "Internet Key Exchange Protocol Version 2 (IKEv2)", RFC
               5996, September 2010.

   [IMAP]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
               4rev1", RFC 3501, March 2003.

   [PHOTURIS]  Karn, P. and W. Simpson, "Photuris: Session-Key
               Management Protocol", RFC 2522, March 1999.

   [POP]       Myers, J. and M. Rose, "Post Office Protocol - Version
               3", STD 53, RFC 1939, May 1996.

   [SIP]       Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston,
               A., Peterson, J., Sparks, R., Handley, M., and E.
               Schooler, "SIP: Session Initiation Protocol", RFC 3261,
               June 2002.

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

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

   [WHYIPSEC]  Bellovin, S., "Guidelines for Specifying the Use of IPsec
               Version 2", BCP 146, RFC 5406, February 2009.


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