要約

  • RFC 8879では、受信側が解凍可能なalgorithmを先に示した場合、TLS 1.3 endpointは通常のCertificateをCompressedCertificateへ置き換えられる。advertisementは一つの表現を許すだけで、実際の利用や無制限のresourceを証明しない。
  • uncompressed_lengthは復元後のmessage長と完全に一致し、outputはその値を超えてはならない。実装はTLSの24-bit ceilingより低いlocal limitを設定できる。この判定はcertificateがpeerを認証する前に起きる。
  • decompression成功はauthentication成功ではない。offer、選択algorithm、compressed bytes、宣言長と実長、復元hash、解析chain、validation、alert、fallback、transport outcomeを別の事実として残す必要がある。

identityより先にallocationを決める

大量の新規接続を処理するTLS terminatorを考える。clientはClientHelloでzlib、Brotli、Zstandardを提示した。serverはalgorithm 2を選び、小さなpayloadと12MBのuncompressed_lengthを返す。

serverを認証するはずのCertificate messageはまだ圧縮されたままである。receiverはCA、subject name、public keyをallocation判断の根拠にできない。まず、そのalgorithmを自らofferしたか確認し、通常Certificateと同じlocal size limitを適用し、decoderの出力を宣言値で止め、最終長が一致しなければ拒否する。

ここに運用権限がある。senderは提示された集合から表現方法を選ぶ。receiverは、どのtransformを実行し、未認証connection一つへどれだけmemoryとCPUを渡すかを決める。Brotli対応の表明は、peerへのallocation authority移譲ではない。

TLS framingの上限は16,777,215 bytesだが、RFC 8879はより低い実装上限を認める。その値はcompressed pathとordinary pathで同じでなければならない。通常なら大きすぎるCertificateを、小さいwrapperに入れたことでparserへ通してはならない。

capability、selection、resultを分離する

compress_certificateは一方向のsignalである。clientがClientHelloへ入れると、server Certificateを解凍できるalgorithmを示す。serverがCertificateRequestへ入れると、client Certificateを解凍できるalgorithmを示す。応答extensionはない。

送信側は提示されたalgorithmを一つ使ってもよいし、通常Certificateを送ってもよい。packet captureでextension 27を見ても、その後にhandshake type 25が送られた証拠にはならない。offer countを圧縮成功数として扱うdashboardは、可能性を実行結果へすり替えている。

directionも独立している。server certificateを受け取れるclientが、自分のcertificateを圧縮できるとは限らない。後者にはserverのCertificateRequestでのsignalが必要である。library buildやapplication optionにより、送信のみ、受信のみ、algorithmの部分集合という状態も生じる。

このextensionはTLS 1.3以降だけで機能し、TLS 1.2では無視される。古いTLS record compressionとは別物である。RFC 8879が変換するのは一つのhandshake messageであり、復元後のcertificate処理を弱めない。

圧縮対象はencoded Certificate messageそのもの

入力はPEM fileや個別X.509 certificateではない。本来wireへ出るencoded Certificate message全体であり、request context、certificate list、各CertificateEntryのextensionを含む。別のextensionがmessageを変えれば、その変更後bytesが入力になる。

したがってevidenceには少なくとも二つのhashが要る。compressed headerとpayloadのhashは、受信したrepresentationを示す。復元後Certificate messageのhashは、TLS parserへ渡った正確なbytesを示す。その後、leafとintermediateのfingerprintがvalidation対象を表す。

同じ入力でもalgorithmが違えば圧縮bytesは変わる。library versionが変わっても、同じmessageを異なる形に圧縮し得る。compressed payload hashだけでは、zlib、Brotli、Zstandard、uncompressed pathの間でcertificate identityを比較できない。

precompressionもmessage identityに従う。OpenSSLはserver certificateを事前圧縮して保存できる。一方、client Certificateはserverから受け取ったunique request contextを含むためon-demandになる。server cacheもhostnameだけで管理できない。chain更新、intermediate順、per-entry extensionが変われば、古いartifactとの対応を失う。

長さは安全のgateであり、scoreではない

CompressedCertificateにはalgorithm ID、24-bitのuncompressed_length、compressed bytesがある。decompression失敗、宣言値超過、実長不一致はbad_certificateでconnectionを終了させる。上限は出力中に守るべきで、終了後の比較だけでは遅い。

宣言長は早期拒否とbuffer planningに役立つが、senderの誠実さや復元内容の安全性を保証しない。protocol上は合法でも、high concurrency serviceにとって大きすぎる値はある。local limitは実測したmemory、CPU、同時接続数から決める必要がある。

また、compressed outputが常に小さいという規則もない。BoringSSL testsは意図的にshrinking、expanding、random transformを扱う。protocol validityは、選択algorithmで入力をbound内に正確に復元することにある。ratioはoptimization outcomeである。

よって宣言長、実長、peak allocation、decoder time、failure classを分けて測る。高い圧縮率がmemory spikeを隠す場合もあり、小さな改善が一つのpacketを減らす場合もある。ratioだけからsecurityやlatencyは導けない。

復元が終わってからtrust evaluationが始まる

復元したCertificateは、最初からuncompressedで来た場合と同じ処理を受ける。messageをparseし、chainを構築し、nameとtimeを確認し、local policyを適用し、TLS 1.3 transcript内のCertificateVerifyを検証する。compressionはexpired certificateやunknown CAを正当化しない。

failure taxonomyを保つべきである。未提示algorithmはnegotiation error。output overrun、decoder error、length mismatchはreconstruction error。不正なCertificate structureはparse error。nameやchainの不一致はvalidation error。CertificateVerify失敗はhandshake authentication errorである。

全てを「TLS certificate error」に潰すと、どのcontrolが拒否したか分からない。逆にdecompression_successだけを成功と呼ぶと、期待identity、private key possession、application authorizationを証明していないのに結論を先取りする。

running codeは境界を具体化する。BoringSSLは通常Certificateを組み立てて正確な長さを保持し、選択callbackで圧縮してmessageを作る。testsは異常な長さやtransformを検査する。OpenSSLはsend、receive、preference、server precompressionを別々に制御する。IANA registry、library branch、production settingは別の証拠である。

wire削減とservice outcomeを接続する

first handshakeではchainがbytesの多くを占めるため、圧縮はpacketを減らし、条件によってはtransport round tripを避ける。しかしchain、congestion window、loss、record packing、CPU、cache、共通algorithmで結果は変わる。disk上のPEM sizeをwire上Certificate lengthの代わりにしてはならない。

方向別offer、実message、algorithm、元長と圧縮長、records、packets、retransmission、CPU、memory、validation、完了時間を一つのsampleへ結ぶ。同じcertificate identityとpolicyでuncompressed controlを置く。それで初めて改善を帰属できる。

共通algorithmがなければ通常Certificateへfallbackできる。fallback増加はclient mixの変化かもしれず、decoderを失ったbuildやTLS termination位置の変更かもしれない。両pathが同じlimitとvalidationを使う限り、これはrepresentation fallbackであってtrust downgradeではない。

情報源