接上文html
正如咱們在 section-2 中討論的,TLS 使用一組通用的消息用於身份驗證,密鑰確認和握手的正確性:Certificate, CertificateVerify 和 Finished。(PSK binders 也以相似的方式進行密鑰確認)。這三條消息老是做爲握手消息的最後三條消息。Certificate 和 CertificateVerify 消息以下面描述的那樣,只在某些狀況纔會發送。Finished 的消息老是做爲認證塊的一部分發送。這些消息使用從 sender_handshake_traffic_secret 派生出來的密鑰進行加密。git
Authentication 消息的計算統一採用如下的輸入方式:github
基於這些輸入,消息包含:算法
Certificate:
用於認證的證書和鏈中任何支持的證書。請注意,基於證書的 Client 身份驗證在 PSK 握手流中不可用(包括 0-RTT)數據庫
CertificateVerify:
根據 Transcript-Hash(Handshake Context, Certificate) 的值得出的簽名緩存
Finished:
根據 Transcript-Hash(Handshake Context, Certificate, CertificateVerify) 的值得出的 MAC 。使用從 Base key 派生出來的 MAC key 計算的 MAC 值。安全
對於每一個場景,下表定義了握手上下文和 MAC Base Key性能優化
+-----------+-------------------------+-----------------------------+
| Mode | Handshake Context | Base Key |
+-----------+-------------------------+-----------------------------+
| Server | ClientHello ... later | server_handshake_traffic_ |
| | of EncryptedExtensions/ | secret |
| | CertificateRequest | |
| | | |
| Client | ClientHello ... later | client_handshake_traffic_ |
| | of server | secret |
| | Finished/EndOfEarlyData | |
| | | |
| Post- | ClientHello ... client | client_application_traffic_ |
| Handshake | Finished + | secret_N |
| | CertificateRequest | |
+-----------+-------------------------+-----------------------------+
複製代碼
TLS 中的許多加密計算都使用了哈希副本。這個值是經過級聯每一個包含的握手消息的方式進來哈希計算的,它包含握手消息頭部攜帶的握手消息類型和長度字段,可是不包括記錄層的頭部。例如:服務器
Transcript-Hash(M1, M2, ... Mn) = Hash(M1 || M2 || ... || Mn)
複製代碼
做爲此通常規則的例外,當 Server 用一條 HelloRetryRequest 消息來響應一條 ClientHello 消息時,ClientHello1 的值替換爲包含 Hash(ClientHello1)的握手類型爲 "message_hash" 的特殊合成握手消息。例如:cookie
Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) =
Hash(message_hash || /* Handshake type */
00 00 Hash.length || /* Handshake message length (bytes) */
Hash(ClientHello1) || /* Hash of ClientHello1 */
HelloRetryRequest || ... || Mn)
複製代碼
設計這種結構的緣由是容許 Server 經過在 cookie 中僅存儲 ClientHello1 的哈希值來執行無狀態 HelloRetryRequest,而不是要求它導出整個中間哈希狀態。
具體而言,哈希副本始終取自於下列握手消息序列,從第一個 ClientHello 開始,僅包括已發送的消息:ClientHello, HelloRetryRequest, ClientHello, ServerHello, EncryptedExtensions, server CertificateRequest, server Certificate, server CertificateVerify, server Finished, EndOfEarlyData, client Certificate, client CertificateVerify, client Finished。
一般上,實現方能夠下面的方法來實現哈希副本:根據協商的哈希來維持一個動態的哈希副本。請注意,隨後的握手後認證不會相互包含,只是經過主握手結束的消息。
此消息將端點的證書鏈發給對端。
每當約定的密鑰交換方法是用證書進行認證(這包括本文檔中除了 PSK 之外定義的全部密鑰交換方法)的時候,Server 就必須發送 Certificate 消息。
當且僅當 Server 經過發送 CertificateRequest 消息請求 Client 認證時,Client 必須發送 Certificate 消息。
若是 Server 請求 Client 認證但沒有合適的證書可用,則 Client 必須發送不包含證書的證書消息(例如,具備長度爲 0 的 "certificate_list" 字段)。Finished 消息必須發送,不管 Certificate 消息是否爲空。
Certificate 消息的結構體是:
enum {
X509(0),
RawPublicKey(2),
(255)
} CertificateType;
struct {
select (certificate_type) {
case RawPublicKey:
/* From RFC 7250 ASN.1_subjectPublicKeyInfo */
opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
case X509:
opaque cert_data<1..2^24-1>;
};
Extension extensions<0..2^16-1>;
} CertificateEntry;
struct {
opaque certificate_request_context<0..2^8-1>;
CertificateEntry certificate_list<0..2^24-1>;
} Certificate;
複製代碼
certificate_request_context:
若是此消息是響應 CertificateRequest 消息的,則該消息中的 certificate_request_context 的值不爲 0。不然(在 Server 認證的狀況下),該字段應爲零長度。
certificate_list:
這是一個 CertificateEntry 結構的序列(鏈),每一個結構包含單個證書和一組擴展。
extensions:
CertificateEntry 的一組擴展值。"Extension" 的格式在 [Section 4.2] 中定義了。有效的擴展包括 OCSP 狀態擴展 [RFC6066] 和 SignedCertificateTimestamp [RFC6962] 擴展。將來能夠爲此消息定義一些新的擴展。Server 的 Certificate 消息中的擴展必須對應於 ClientHello 消息中的擴展。Client 的 Certificate 消息中的擴展必須對應於 Server 的 CertificateRequest 消息中的擴展。若是一個擴展適應用於整個鏈,它應該被包括在第一個 CertificateEntry 中。
若是沒有在 EncryptedExtensions 中協商相應的證書類型擴展名 ("server_certificate_type" 或 "client_certificate_type"),或者協商了 X.509 證書類型,則每一個 CertificateEntry 都要包含 DER 編碼的 X.509 證書。發件者的證書必須位於列表中的第一個 CertificateEntry 中。以後的每一個證書都應該直接證實其前面的證書。因爲證書驗證要求信任錨獨立分發,所以能夠從鏈中省略指定信任錨的證書(前提是已知支持的對等方擁有可省略的證書)。
注意:TLS 1.3 以前的版本,"certificate_list" 排序須要每一個證書要證實緊接在其前面的證書,然而,一些實現容許一些靈活性。Server 有時爲了過渡的目的而發送當前和已棄用的中間體,而其餘的配置不正確,但這些狀況仍然能夠正確地驗證。爲了最大程度的兼容性,全部實現應該準備處理多是可有可無的證書和 TLS 版本的任意排序,但最終實體證書(排序的順序)必須是第一個。
若是協商了 RawPublicKey 證書類型,則 certificate_list 必須包含不超過一個CertificateEntry,CertificateEntry 中包含定義在 [RFC7250], Section 3 中的 ASN1_subjectPublicKeyInfo 值。
OpenPGP 證書類型禁止在 TLS 1.3 中使用。
Server 的 certificate_list 必須始終是非空的。若是 Client 沒有適當的證書要發送以響應 Server 的身份驗證請求,則會發送空的 certificate_list。
[RFC6066] 和 [RFC6961] 提供了協商 Server 向 Client 發送 OCSP 響應的擴展。 在 TLS 1.2 及如下版本中,Server 回覆空的擴展名以表示對此擴展的協商,而且在 CertificateStatus 消息中攜帶 OCSP 信息。在 TLS 1.3 中,Server 的 OCSP 信息在包含相關證書的 CertificateEntry 中的擴展中。特別的,來自 Server 的 "status_request" 擴展的主體必須是分別在 [RFC6066] 和 [RFC6960] 中定義的 CertificateStatus 結構。
注意:status_request_v2 擴展 [RFC6961] 已經廢棄了,TLS 1.3 不能根據它是否存在或者根據它的信息來出來 ClientHello 消息。特別是,禁止在 EncryptedExtensions, CertificateRequest 和 Certificate 消息中發送 status_request_v2 擴展。TLS 1.3 的 Server 必需要可以處理包含它的 ClientHello 消息,由於這條消息多是由但願在早期協議版本中使用它的 Client 發送的。
Server 能夠經過在其 CertificateRequest 消息中發送空的 "status_request" 擴展來請求 Client 使用其證書來作 OCSP 的響應。若是 Client 選擇性的發送 OCSP 響應,則其 "status_request" 擴展的主體必須是在 [RFC6966] 中定義的 CertificateStatus 結構。
相似地,[RFC6962] 爲 Server 提供了一種機制,用在 TLS 1.2 及更低版本中的,可在 ServerHello 中發送簽名證書時間戳 (SCT) 的擴展。 在 TLS 1.3 中,Server 的 SCT 信息在 CertificateEntry 的擴展中。
如下規則適用於 Server 發送的證書:
Server 的終端實體證書的公鑰(和相關限制)必須與 Client的 "signature_algorithms" 擴展(目前爲RSA,ECDSA 或 EdDSA)中的所選認證算法兼容。
證書必須容許密鑰用於簽名(即,若是存在密鑰用法擴展,則必須設置 digitalSignature 位),並在 Client 的"signature_algorithms"/"signature_algorithms_cert" 擴展中指示簽名方案。
"server_name" [RFC6066] 和 "certificate_authorities" 擴展用於指導證書選擇。因爲 Server 可能須要存在 "server_name" 擴展名,所以 Client 應該在適用時發送此擴展名。
若是 Server 可以提供證書鏈,Server 全部的證書都必須由 Client 提供的簽名算法簽名。自簽名的證書或預期爲信任錨的證書不會做爲鏈的一部分進行驗證,所以可使用任何算法進行簽名。
若是 Server 不能產生只經過所指示的支持的算法簽名的證書鏈,則它應當經過向 Client 發送其選擇的證書鏈來繼續握手,該證書鏈可能會包括 Client 不知道可否支持的算法。這個回退鏈能夠只在 Client 容許的狀況下才可使用已棄用的 SHA-1 哈希算法,其餘狀況都必須禁止使用 SHA-1 哈希算法。
若是 Client 沒法使用提供的證書構造可接受的證書鏈,那麼必須停止握手。停止握手併發送證書相關的 alert 消息(默認的,發送 "unsupported_certificate" alert 消息)
若是 Server 有多張證書,它會根據上述標準(除了其餘標準之外,如傳輸層端點,本地配置和首選項)選擇其中的一個證書。
如下的規則適用於 Client 發送的證書:
若是 CertificateRequest 消息中 "certificate_authorities" 擴展不爲空,則證書鏈中的至少一個證書應該由所列出的 CA 之一發布的。
證書必須使用可接受的簽名算法簽名,如第 4.3.2 節所述。注意,這放寬了在 TLS 的先前版本中發現的證書籤名算法的約束。
若是 CertificateRequest 消息包含非空的 "oid_filters" 擴展,則終端實體證書必須匹配 Client 識別的擴展 OID,如第 4.2.5 節中所述。
一般,詳細的證書驗證程序超出了 TLS 的範圍(參見[RFC5280])。 本節提供特定於 TLS 的要求。
若是 Server 提供空的證書消息,則 Client 必須使用 "decode_error" alert 消息停止握手。
若是 Client 沒有發送任何證書(即,它發送一個空的證書消息),Server 能夠自行決定是否在沒有 Client 認證的狀況下繼續握手,或者使用 "certificate_required" alert 消息停止握手。此外,若是證書鏈的某些方面是不可接受的(例如,它未由已知的可信 CA 簽名),則 Server 能夠自行決定是繼續握手(考慮 Client 尚未通過身份驗證)仍是停止握手。
任何端點接收任何須要使用任何簽名算法使用 MD5 哈希驗證的證書都必須使用 "bad_certificate" alert 消息停止握手。不推薦使用 SHA-1,而且建議任何接收任何使用 SHA-1 哈希使用任何簽名算法驗證的證書的端點都會使用 "bad_certificate" alert 消息停止握手。爲清楚起見,這意味着端點能夠接受這些算法用於自簽名或信任錨的證書。
建議全部端點儘快轉換爲 SHA-256 或更好的算法,以保持與當前正在逐步淘汰 SHA-1 支持的實現的互操做性。
請注意,包含一個簽名算法的密鑰的證書可使用不一樣的簽名算法進行簽名(例如,使用 ECDSA 密鑰簽名的 RSA 密鑰)。
此消息用於提供端點擁有與其證書對應的私鑰的明確證據。CertificateVerify 消息還爲到此爲止的握手提供完整性。Server 必須在經過證書進行身份驗證時發送此消息。每當經過證書進行身份驗證時(即,當證書消息非空時),Client 必須發送此消息。發送時,此消息必須在 Certificate 消息以後當即出現,而且緊接在 Finished 消息以前。
這條消息的結構體是:
struct {
SignatureScheme algorithm;
opaque signature<0..2^16-1>;
} CertificateVerify;
複製代碼
algorithm 字段指定使用的簽名算法(有關此類型的定義,請參見第 4.2.3 節)。signature 字段是使用該算法的數字簽名。簽名中涵蓋的內容是第 4.4.1 節中描述的哈希輸出,即:
Transcript-Hash(Handshake Context, Certificate)
複製代碼
計算數字簽名是級聯計算的:
設計這個結構目的是爲了防止對先前版本的 TLS 的攻擊,其中 ServerKeyExchange 格式意味着攻擊者能夠得到具備所選 32 字節前綴(ClientHello.random)的消息的簽名。 最初的 64 字節填充將清除 Server 控制的 ServerHello.random 中的前綴。
Server 簽名的上下文字符串是 "TLS 1.3,Server CertificateVerify"。Client 簽名的上下文字符串是 "TLS 1.3,Client CertificateVerify"。它用於在不一樣的上下文中提供簽名之間的分離,幫助抵禦潛在的跨協議攻擊。
例如,若是 hash副本 是 32 字節 01(這個長度對 SHA-256 有意義),Server 的 CertificateVerify 的數字簽名所涵蓋的內容將是:
2020202020202020202020202020202020202020202020202020202020202020
2020202020202020202020202020202020202020202020202020202020202020
544c5320312e332c207365727665722043657274696669636174655665726966
79
00
0101010101010101010101010101010101010101010101010101010101010101
複製代碼
在發送方,用於計算 CertificateVerify 消息的簽名字段的過程做爲輸入:
數字簽名算涵蓋的內容
與上一條消息中發送的證書對應的私有簽名密鑰
若是由 Server 發送 CertificateVerify 消息,則簽名算法必須是 Client "signature_algorithms" 擴展中提供的,除非在沒有不支持的算法的狀況下不能生成有效的證書鏈(除非當前支持的算法都不能生成有效的證書鏈)。
若是由 Client 發送,則簽名中使用的簽名算法必須是 CertificateRequest 消息中 "signature_algorithms" 擴展的 supported_signature_algorithms 字段中存在的簽名算法之一。
另外,簽名算法必須與發送者的終端實體證書中的密鑰兼容。不管 RSASSA-PKCS1-v1_5 算法是否出如今 "signature_algorithms" 中,RSA 簽名都必須使用 RSASSA-PSS 算法。SHA-1 算法禁止用於 CertificateVerify 消息的任何簽名。
本規範中的全部 SHA-1 簽名算法僅定義用於舊證書,而且對 CertificateVerify 簽名無效。
CertificateVerify 消息的接收者必須驗證簽名字段。驗證過程做爲輸入:
數字簽名所涵蓋的內容
在關聯的證書消息中找到的最終實體證書中包含的公鑰
在 CertificateVerify 消息的簽名字段中收到的數字簽名
若是驗證失敗,接收方必須經過 "decrypt_error" 警報終止握手。
Finished 消息是認證塊中的最後一條消息。它對提供握手和計算密鑰的身份驗證起了相當重要的做用。
Finished 消息的收件人必須驗證內容是否正確,若是不正確,必須使用 "decrypt_error" alert 消息終止鏈接。
一旦一方已發送其 Finished 消息並已收到並驗證來自其對端的 Finished 消息,它就能夠開始經過該鏈接發送和接收應用數據。有兩種設置容許在接收對端的 Finished 以前發送數據:
用於計算 Finished 消息的密鑰是使用 HKDF,它是從第 4.4 節中定義的 Base Key 計算而來的(參見第7.1節)。特別的:
finished_key =
HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
複製代碼
這條消息的數據結構是:
struct {
opaque verify_data[Hash.length];
} Finished;
複製代碼
verify_data 按照以下方法計算:
verify_data =
HMAC(finished_key,
Transcript-Hash(Handshake Context,
Certificate*, CertificateVerify*))
* Only included if present.
複製代碼
HMAC [RFC2104] 使用哈希算法進行握手。如上所述,HMAC 輸入一般是經過動態的哈希實現的,即,此時僅是握手的哈希。
在之前版本的 TLS 中,verify_data 的長度老是 12 個八位字節。在 TLS 1.3 中,它是用來表示握手的哈希的 HMAC 輸出的大小。
注意:警報和任何其餘非握手記錄類型不是握手消息,而且不包含在哈希計算中。
Finished 消息以後的任何記錄都必須在適當的 client_application_traffic_secret_N 下加密,如第 7.2 節所述。特別是,這包括 Server 爲了響應 Client 的 Certificate 消息和 CertificateVerify 消息而發送的任何 alert。
struct {} EndOfEarlyData;
複製代碼
若是 Server 在 EncryptedExtensions 中發送了 "early_data" 擴展,則 Client 必須在收到 Server 的 Finished 消息後發送 EndOfEarlyData 消息。 若是 Server 沒有在 EncryptedExtensions中發送 "early_data" 擴展,那麼 Client 毫不能發送 EndOfEarlyData 消息。此消息表示已傳輸完了全部 0-RTT application_data消息(若是有),而且接下來的記錄受到握手流量密鑰的保護。Server 不能發送此消息,Client 若是收到了這條消息,那麼必須使用 "unexpected_message" alert 消息終止鏈接。這條消息使用從 client_early_traffic_secret 中派生出來的密鑰進行加密保護。
TLS 還容許在主握手後發送其餘的消息。這些消息使用握手內容類型,並使用適當的應用程序流量密鑰進行加密。
在 Server 接收到 Client 的 Finished 消息之後的任什麼時候刻,它均可以發送 NewSessionTicket 消息。此消息在 ticket 值和從恢復主密鑰派生出來的 PSK 之間建立了惟一的關聯。
Client 在 ClientHello 消息中包含 "pre_shared_key" 擴展,並在擴展中包含 ticket ,那麼 Client 就可能在將來的握手中使用 PSK。Server 可能在一個鏈接中發送多個 ticket,發送時機多是一個接一個的當即發送,也多是在某個特定事件之後發送。例如,Server 可能會在握手後身份驗證以後發送新的 ticket,以封裝其餘 Client 身份驗證狀態。多個 ticket 對於 Client 來講,可用於各類目的,例如:
打開多個並行的 HTTP 鏈接
經過(例如) Happy Eyeballs [RFC8305] 或相關的技術在接口和地址簇上進行鏈接競爭
任何 ticket 必須只能使用與用於創建原始鏈接的 KDF 哈希算法相同的密碼套件來恢復會話。
Client 必須只有在新的 SNI 值對原始會話中提供的 Server 證書有效時才能恢復,而且只有在 SNI 值與原始會話中使用的 SNI 值匹配時才應恢復。後者是性能優化:一般,沒有理由指望單個證書所涵蓋的不一樣 Server 之間可以相互接受彼此的 ticket;所以,在這種狀況下嘗試恢復會話將會浪費一次性的 ticket。若是提供了這種指示(外部或經過任何其餘方式),則 Client 可能可使用不一樣的 SNI 值進行恢復會話。
在恢復會話時,若是向調用的應用程序報告 SNI 值,則實現方必須使用在恢復 ClientHello 中發送的值而不是在先前會話中發送的值。請注意,若是 Server 的實現拒絕了不一樣 SNI 值的全部 PSK 標識,則這兩個值老是相同。
注意:雖然恢復主密鑰取決於 Client 的第二次 flight,可是不請求 Client 身份驗證的 Server 能夠獨立計算轉錄哈希的剩餘部分,而後在發送 Finished 消息後當即發送 NewSessionTicket 而不是等待 Client 的 Finished 消息。這可能適用於 Client 須要並行打開多個 TLS 鏈接而且能夠從減小恢復握手的開銷中受益的狀況。
struct {
uint32 ticket_lifetime;
uint32 ticket_age_add;
opaque ticket_nonce<0..255>;
opaque ticket<1..2^16-1>;
Extension extensions<0..2^16-2>;
} NewSessionTicket;
複製代碼
ticket_lifetime:
這個字段表示 ticket 的生存時間,這個時間是以 ticket 發佈時間爲網絡字節順序的 32 位無符號整數表示以秒爲單位的時間。Server 禁止使用任何大於 604800秒(7 天)的值。值爲零表示應當即丟棄 ticket。不管 ticket_lifetime 如何,Client 都不得緩存超過 7 天的 ticket,而且能夠根據本地策略提早刪除 ticket。Server 能夠將 ticket 視爲有效的時間段短於 ticket_lifetime 中所述的時間段。
ticket_age_add:
安全的生成的隨機 32 位值,用於模糊 Client 在 "pre_shared_key" 擴展中包含的 ticket 的時間。Client 的 ticket age 以模 2 ^ 32 的形式添加此值,以計算出 Client 要傳輸的值。Server 必須爲它發出的每一個 ticket 生成一個新值。
ticket_nonce:
每個 ticket 的值,在本次鏈接中發出的全部的 ticket 中是惟一的。
ticket:
這個值是被用做 PSK 標識的值。ticket 自己是一個不透明的標籤。它能夠是數據庫查找鍵,也能夠是自加密和自我驗證的值。
extensions:
ticket 的一組擴展值。擴展格式在 4.2 節中定義的。Client 必須忽略沒法識別的擴展。
當前爲 NewSessionTicket 定義的惟一擴展名是 "early_data",表示該 ticket 可用於發送 0-RTT 數據(第4.2.10節)。 它包含如下值:
PSK 關聯的 ticket 計算方法以下:
HKDF-Expand-Label(resumption_master_secret,
"resumption", ticket_nonce, Hash.length)
複製代碼
由於 ticket_nonce 值對於每一個 NewSessionTicket 消息都是不一樣的,因此每一個 ticket 會派生出不一樣的 PSK。
請注意,原則上能夠繼續發佈新 ticket,該 ticket 無限期地延長生命週期,這個生命週期是最初從初始非 PSK 握手中(最可能與對等證書相關聯)派生獲得的密鑰材料的生命週期。
建議實現方對密鑰材料這些加上總壽命時間的限制。這些限制應考慮到對等方證書的生命週期,干預撤銷的可能性以及自從對等方在線 CertificateVerify 簽名到當前時間的這段時間。
當 Client 發送了 "post_handshake_auth" 擴展(參見第4.2.6節)時,Server 能夠在握手完成後隨時經過發送 CertificateRequest 消息來請求客戶端身份驗證。Client 必須使用適當的驗證消息進行響應(參見第4.4節)。若是 Client 選擇進行身份驗證,則必須發送 Certificate,CertificateVerify,Finished 消息。若是 Client 拒絕身份驗證,它必須發送一個 Certificate 證書消息,其中不包含證書,而後是 Finished 消息。響應 Server 的全部 Client 消息必須連續出如今線路上,中間不能有其餘類型的消息。
在沒有發送 "post_handshake_auth" 擴展的狀況下接收 CertificateRequest 消息的 Client 必須發送 "unexpected_message" alert 消息。
注意:因爲 Client 身份驗證可能涉及提示用戶,所以 Server 必須作好一些延遲的準備,包括在發送 CertificateRequest 和接收響應之間接收任意數量的其餘消息。此外,Client 若是連續接收到了多個 CertificateRequests 消息,Client 可能會以不一樣於它們的順序響應它們(certificate_request_context 值容許服務器消除響應的歧義)
KeyUpdate 握手消息用於表示發送方正在更新其本身的發送加密密鑰。任何對等方在發送 Finished 消息後均可以發送此消息。在接收 Finished 消息以前接收 KeyUpdate 消息的,實現方必須使用 "unexpected_message" alert 消息終止鏈接。發送 KeyUpdate 消息後,如第 7.2 節所描述的計算方法,發送方應使用新一代的密鑰發送其全部流量。收到 KeyUpdate 後,接收方必須更新其接收密鑰。
enum {
update_not_requested(0), update_requested(1), (255)
} KeyUpdateRequest;
struct {
KeyUpdateRequest request_update;
} KeyUpdate;
複製代碼
若是 request_update 字段設置爲 "update_requested",則接收方必須在發送其下一個應用數據記錄以前發送本身的 KeyUpdate,其中 request_update 設置爲 "update_not_requested"。此機制容許任何一方強制更新整個鏈接,但會致使一個實現方接收多個 KeyUpdates,而且它仍是靜默的響應單個更新。請注意,實現方可能在發送 KeyUpdate (把 request_update 設置爲 "update_requested") 與接收對等方的 KeyUpdate 之間接收任意數量的消息,由於這些消息可能早就已經在傳輸中了。可是,因爲發送和接收密鑰是從獨立的流量密鑰中導出的,所以保留接收流量密鑰並不會影響到發送方更改密鑰以前發送的數據的前向保密性。
若是實現方獨立地發送它們本身的 KeyUpdates,其 request_update 設置爲 "update_requested" 而且它們的消息都是傳輸中,結果是雙方都會響應,雙方都會更新密鑰。
發送方和接收方都必須使用舊密鑰加密其 KeyUpdate 消息。另外,在接受使用新密鑰加密的任何消息以前,雙方必須強制接收帶有舊密鑰的 KeyUpdate。若是不這樣作,可能會引發消息截斷攻擊。
Reference:
GitHub Repo:Halfrost-Field
Follow: halfrost · GitHub
Source: halfrost.com/TLS_1.3_Han…