1.2 KB 問題:後量子如何撐破 ClientHello

開啟後量子金鑰交換,部分連線就開始失敗。不是密碼學錯誤—而是交握進行到一半就卡住、或被重置,發生在昨天還好端端的路徑上。原因不在密碼學。是 ClientHello 變得太大,塞不進一個封包。

到底有多大

一個傳統的 TLS 1.3 ClientHello 很小。X25519 金鑰交換是 32 bytes,整個訊息大約落在 300 bytes—舒舒服服地待在單一個 TCP 區段裡。加上後量子,這就以數量級的幅度改變:光是 ML-KEM-768 的封裝金鑰就有 1184 bytes,X25519MLKEM768 的金鑰交換是 1216,整個 ClientHello 突破 1.5 KB。

# 傳統 ClientHello(僅 X25519)
  key_share: X25519             32 bytes
  整個 ClientHello           ~  300 bytes     # 永遠是一個 TCP 區段

# 後量子 ClientHello(X25519MLKEM768,代碼點 0x11ec)
  key_share: ML-KEM-768 ek    1184 bytes
           + X25519              32 bytes
           = key_exchange      1216 bytes
  整個 ClientHello           ~ 1600 bytes     # 超過 1500-byte MTU -> 2 個以上區段

這些數字來自一次即時交握,不是規範表格。其中最關鍵的是最後一行:ClientHello 不再塞得進單一個 ~1500-byte 的乙太網路訊框,於是它分裂成兩個或更多 TCP 區段抵達。

為什麼「一個封包」曾經很重要

TLS 跑在 TCP 之上,那是一道位元組流—沒有任何保證一筆記錄會在一個區段裡抵達,而一個正確的實作會在解析前先重組。但二十五年來,傳統的 ClientHello 確實幾乎總是塞得進一個區段。於是大量的網路設備,就是假設它會如此而寫成的。

那些依伺服器名稱路由或過濾的中介設備—負載平衡器、SNI 路由器、檢測型防火牆—會解析 ClientHello 來讀取 SNI。其中許多只讀第一個 TCP 區段:一條不做完整 TCP 重組的快速路徑。當 ClientHello 跨越兩個區段,那條快速路徑看到的是一個被截斷的訊息—沒有 SNI,或一筆殘缺的記錄—然後依實作的不同,它會丟棄連線、逾時,或路由錯誤。這個 bug 一直都在。後量子只是把跨區段的 ClientHello 從「從不發生」變成「家常便飯」,於是潛伏的 bug 就成了每天的故障。

它在實際環境裡的樣子

症狀會誤導人。交握就在 ClientHello 之後卡住或重置;它對某些目的地失敗、對其他的卻沒事;而且它與路徑上某個特定設備相關,而非與任一端點相關。它讀起來像網路不穩,而不是密碼學問題—這正是它吃掉診斷時間的原因。密碼學沒事。是那些位元組從未完整抵達。

為什麼填充救不了你

ClientHello 大小的 bug 有前例,而且方向相反。填充擴充(RFC 7685)之所以存在,是因為某些伺服器曾對 256–511 bytes 範圍內的 ClientHello 出問題;當時的修法是把它向填充過 512。後量子是相反的問題—太大,而非太小。你無法靠填充脫離 1.2 KB。唯一的槓桿,是讓更大的訊息塞得進去、或讓路徑能正確處理它。

為什麼這是遷移的金絲雀

故障不在你的端點—兩端都能完美協商出 ML-KEM。它在路徑上:兩端之間那些你往往並不擁有的設備—雲端負載平衡器、合作夥伴的防火牆、ISP 的透明代理。這正是任何 PQC 遷移之難處的第一個具體實例:那些你無法控制的系統。而它之所以最先發作,正因為 ClientHello 是第一個跨越網路的後量子位元組—開場的那一回合,在任何密鑰被算出來之前。

找出一個分裂的 ClientHello 死在哪裡,再一次,是個封包問題:你必須觀察交握,看哪一跳吞掉了第二個區段。它是更廣遷移路徑中的一步—另見為什麼金鑰交換一開始就是 1.2 KB,以及完整的逐位元組解析。當一次 PQC 推行「在實驗室裡可行」卻在生產環境失敗時,這就是我們第一個會查的東西—那就是我們登場之處

← 所有文章