TLS1.3 はTLS1.2以前のバージョンの問題を踏まえ、セキュリティとパフォーマンスを両立しつつ広報互換性のあるプロトコルとして設計されました。原書では第2章の最後にまとめとしてTLS 1.3の重要な改善点が記されています。
TLS 1.3の改善点
TLS 1.3はTLS 1.2以前とは全く別な新しいプロトコルとして、TLS 1.2を精査して換骨奪胎されたものです。見通しの悪かった箇所の整理、古くて無駄な箇所の除去が行われました。重要な改善点として以下があります。(一部意訳)
ネットワーク遅延の削減
・ハンドシェイクが再設計されネットワーク遅延が1RTT(1 Round Trip Time:1往復)まで短縮された
・接続の再開ではさらに高速な0-RITが利用できる(ただしセキュリティ弱体化に注意が要)
前方秘匿性
・鍵交換が見直され全ての暗号スイートが前方秘匿性に対応しました。
・RSA鍵交換は使用不可になりました。
・TLS 1.2で強固な前方秘匿性を実現するには慎重なサーバー設定が要求されたがTLS 1.3ではこの要求レベルが下がった
・sesion resumpitonでのDH鍵交換に対応したので通信再開示にも前方秘匿性が確保できる。
・ただし0-RITでは常に前方秘匿性が有効になるとは限らないので要注意
暗号化されずに送信される情報の削減
TLS1.2以前では平文で送信されていた個所の多くが暗号化して保護されるようになりました。
・ハンドシェイクの大部分、クライアント・サーバーの証明書が暗号化されるようになった。
・RecordプトロコルでTLS 1.2以前で平文だった情報は廃止され全てのデータが暗号化できる。
・唯一保護されていないのはサーバーホスト名で、これはSNI Server Name Indication を介して外部から読み取り可能だが、TLS以外の領域で対策が進められている。
暗号技術の刷新
RC4系など古い(安全でない)暗号技術の廃止と暗号学における進展を取り入れています。
・X25519 や ChaCha20のような現代的な暗号技術へ対応した。
・従来の独自機構からAEAD、HKDFのような標準的な技術採用に変更された。
・署名の堅牢化、鍵交換のパラメーターのネゴシエーションの洗練化。
以下、TLS 1.3の具体的な説明です。
1.Recordプロトコル
TLSはアプリケーションレイヤーとTCPなど信頼性のある通信を担うレイヤーの中間に位置するレイヤーといえます。TLSの役割はアプリケーションレイヤーでは平文で送信されるアプリケーションデータに対する完全性と機密性を提供する事です。
TLSは更に2層にわかれており、よりアプリケーションレイヤーに近い上位層がRecordプロトコルです。
書式が不定のデータ(opaque data)を含むメッセージの運搬、暗号化、保護を行います。
TLSの各種機能はRecordプロトコルより下位層のサブプロトコルとして実装されています。
TLSプロトコルの仕様はC言語のコードに類似の独自形式で表現されます。原書でもこの形式でTLSの仕様は説明されています。
Recordプロトコルの形式
クライアントーサーバー間で送受信されるRecordプロトコルの構造は以下の様になります。
struct {
ContentType type;
ProtocolVersion legacy_record_version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
enum {
invalid(0),
change_cipher_spec(20),
alert(21),
handshake(22),
application_data(23),
(255)
} ContentType;
ContentType : typeでサブプロトコルの種類を指定
legacy_record_version : TLSプロトコルのバージョン
length : 後続のペイロードの長さ
fragment : ペイロードの格納されるサブプロトコルのデータ
TLS1.2以前の問題点として、プロトコルバージョンをClientHelloと個々のRecordプロトコルの2か所でセットしている点がありました。本来プロトコルバージョンは通信初期のハンドシェイクによるネゴシエーションでのみあればいいはずですが、その後の個々のRecordプロトコルでもバージョン番号をセットしていました。この仕様が発端となり通信経路中のファイアーウォールのようなミドルボックスで未知のトラフィックが破棄される問題がおきていたようです。
・上記の背景からTLS1.3ではRecordプロトコルではプロトコルバージョンは使用しないことになりました。ですが、TLS 1.2以前のRecordプロトコルとフォーマットを合わせるためにTLS1.3のメッセージにもダミーのバージョン表記としてLegacy_record_version というフィールドが用意されており、TLS1.3では 0x0303(TLS1.2と同じ値)を指定します。
ただし、互換性を考慮して通信初期に送信するClientHelloだけは0x0301(TLS 1.0を表す)を利用することも可能です。
Recordプロトコルは通信の開始時点では平文モードで行われ、必要なパラメーターのネゴシエーションが完了後は直ちに暗号化モードに移行します。ペイロードの保護が有効になった時点でのRecordプロトコルのメッセージ構造は下記のようになります。暗号化以降のメッセージタイプを秘匿する目的があります。
struct {
ContentType opaque_type = application_data; /* 23 */
ProtocolVersion legacy_record_version = 0x303; /* TLS 1.2 */
uint16 length;
opaque encrypted_record[TLSCiphertext.length];
} TLSCiphertext;
**暗号化された後のメッセージ構造では平文モードではtypeフィールドだったものがopaque_typeに変化しています。
これはTLS1.2以前では、サブプロトコルの種類を示すフィールドの暗号化がされておらず、プロファイリング攻撃などに利用可能な場合があったこと、ファイアーウォールなどミドルボックスでの(意図しない)トラフィックのフィルタリングへの対処です。
以上の結果、平文で交換されるサブプロトコルの種類を表す typeは単なる文字列で利用はされなくなりました。サブプロトコルの種類を示すtypeは、以下の様に暗号化されたメッセージ上でコンテンツ、パディングと一緒に送信されます。**
struct {
opaque content[TLSPlaintext.length];
ContentType type;
unit8 zeros[length_of_Padding];
} TLSInnerPlaintext;
上記のメッセージ構造にはコンテンツの長さを示すフィールドはありません。暗号化されたデータを受信した側では、1. 暗号文を平文に復号します。
2. 復号した平文の末尾から前方に向かって処理を行い、まず末尾のパディング=NUL=ゼロだけのバイト列 を取り除きます。
3. パディングと取り除いた際末尾のデータ1バイトがサブプロトコルの種類を示します。(サブプロトコルアゼロ以外で表現される)
4. サブプロトコルの1バイトを除いた残りの前方のデータすべてがコンテンツの本体になります。
2.1.2 暗号化
Recordプトコルの主目的の1つはペイロードのデータを保護して機密性・完全性を確保する事です。このためにTLS 1.3ではAEAD(認証付き暗号)を利用しています。
AEADにより機密性と完全性が同時に確保できるので、Recordプロトコル(TLS1.3)より上位層のプロトコル、アプリケーションなどはペイロードのデータを安全なものとみなして処理する事が出来ます。
TLS1.2以前などではAEAD以外の手段を用いて機密性・完全性を確保していました。たとえば認証付きで無い暗号もサポートしていましたがこの場合、TLS1.2(以前)と別な層(より上位層?)で完全性を検証する必要があり結果プロトコルの設計が複雑になる、数々の脆弱性が内在する等の弱点が発生しました。
AEADによる暗号化データのフォーマットは以下の様になります。
AEADEncrypted = AEAD-Encrypt(write_key, nonce, plaintext, addtional_data)
write_key : 暗号鍵
nonce(ナンス): 各通信で1回だけ使われる値。ナンスの値は使い回さないようにすることが必須(暗号鍵が破られないようにするための処置として)。TLSでは64ビット超のメッセージカウンターが送信側・受信側で用意されているのでこれをナンスの生成に利用します。(利用可能です。)。メッセージカウンターは通信では曹純されず、サーバーのローカルで保持して暗号化処理に利用するので、リプレイス攻撃やメッセージを間違った順番で処理されることを抑止します。
additional_data : 送信されるTLSメッセージ中暗号化されない全てのフィールドを以下の様に単純に結合したデータ。ほとんどのフィールドは使われないがAIADの暗号化に含めることで完全性の検証が可能になり、改竄の恐れが無くせます。
additional_data = TLSCiphertext.opaque_type ||
TLSCiphertext.legacy_record_version ||
TLSCiphertext.length
1つの暗号鍵を使って暗号化できるデータ量は上限があると考えられます(安全性上、という意味だと思います)。このためTLS 1.3では通信の途中で暗号鍵を更新して暗号化に使うパラメーターをリセットする機構も用意されています。
メッセージの長さを隠す
TLSの基本機能ではメッセージの長さを隠す機能は提供されません。 攻撃者が暗号化された情報を観察すれば、暗号化されたメッセージの長さから平文の長さを予測できてしまいます。例えばTLSで暗号化したパスワードの長さを観察すると平文のパスワード長も推測されてしまう事ができます。
一つの対策としては送信すべきデータが無いときにも常時送信を続けることでメッセージ長を隠すことができますが、コストやサーバー・ネットワーク負荷等の条件が許容できる場合に限られます。
HTTPのように双方向のやり取りが伴うプロトコルは攻撃者が偽のトラフィックを生成した場合など影響を受けるので脆弱性が高いと言えます。さらにHTTPは攻撃者が用意した偽のリンク先へブラウザーで簡単に移動させられる危険性も高くなります。
TLS 1.3は旧バージョンに比べれば改善されており、必要に応じてメッセージ長を隠すために利用できる機能が提供されています。
・平文の長さは隠されている
前述のように平文の長さは暗号化されています。TLS 1.2以前ではメッセージ長の情報を平文で取得できていました。TLS 1.3ではネットワーク上のトラフィックを観察するなどでメッセージ長を推測する事しかできません。
・メッセージにパディングを付加できる
Recordプロトコルのメッセージは任意の長さのパディングを追加可能で、プログラム的な追加実装は必要ですが、本来必要なメッセージ長を隠すことができます。例えばプロトコルのメッセージをすべて同じ長さに揃えることで攻撃者にプロファイル攻撃をできにくくする防御策とできるかもしれません。
・長さゼロのプロトコルメッセージを送れる
本来のデータを全く含まないダミーのメッセージを送信できます。これにパディングを付加して本来必要なデータの様に見せかけることもできます。これにより攻撃者はトラフィックのプロファイリングが困難になるかもしれません。
TLS 1.3のサブプロトコル(4種類)
TLS 1.3のRecordプロトコルの下で具体的な処理を実装するサブプロトコルとして以下の4つが定義されています。基本的な動作はTLS 1.2以前と共通ですが、細かい部分では様々に違いがあります。
Aleartプロトコル
シグナリングおよび例外的な状況で使われるサブプロトコル。例えばハンドシェイクを完遂出来ない場合に接続が切れる事を相手に通知する場合に使われます。
Application Data プロトコル
アプリケーションデータの転送に使われるサブプロトコル。書式の無いバイト列として一方から他方へデータを送るためのサブプロトコル。送信するメッセージだけからなる最も単純なプロトコルです。
Change Cipher Spec プロトコル
TLS 1.3では廃止されたプロトコルです。TLS 1.2以前ではこのプロトコルを使ってネゴシエーション時に決定した暗号方式を変更する事が出来ました。ですが、実際的には安全性を確保して実装する事が難しく結果的に様々な脆弱性を引き起こす原因でした。
TLS 1.3では以前のバージョンとの互換性維持のために残されており、サーバー、クライアントともこのプロトコルを送信できますが、受信側ではメッセージは無視されます。
Handshakeプロトコル
おそらくは最も重要なサブプロトコル。接続時利用することになるセキュリティパラメーターはこのサブプロトコルを使ってネゴシエーションを実行します。
メッセージのフラグメンテーション
Recordプロトコルのペイロードは最大長16,384バイト と定義されていますが、その中に収めるさププロトコルのデータの形式は指定がありません。
例として以下のような構成はすべて可能です。
・1つのレコードにサブプロトコルのメッセージを複数格納する
・1つのメッセージを分割して複数のレコードにまたがって送信する
・異なるサブプロトコルのメッセージを1つのレコードに格納して送信する
ただし、Handshakeプロトコルで使うメッセージに他のサブプロトコルのメッセージは含められない、後述のAlertプロトコルのメッセージは分割できない、などの個別のルールはあります。
※TLS 1.3関連では以下の説明がこの後続きます。
2.Handshakeプロトコル
3.認証
4.Alertプロトコル
5.暗号に関する計算
6.拡張
7.暗号スイート
8.0-RTT
