[12]
内容符号化 aes128gcm
>>6 2.
は、
HTTPメッセージで転送するデータを暗号化するものです。
[9] HTTPメッセージ (HTTP要求、 HTTP応答) の内容を暗号化し、適切な鍵を持つ者のみが閲覧可能とし、 ときにサーバーすらその内容を閲覧できなくしたいようなとき、 使えるものです。 >>6 1.
[135] Web Push で使われます。 アプリケーションサーバーからプッシュサービスへ、そして利用者エージェントへとデータが転送されるので、 本手法により末端対末端の暗号化が実現できます。
[136] 理論上他にもいろいろ用途はあり得ますが、実用例があるのか不明です。
[65]
ある
HTTPメッセージにおける
aes128gcm
で符号化されたデータは、
ヘッダーブロックと、
それに続く1個以上のレコードで構成されます。
>>6 2., >>2.1.
[45] ヘッダーブロック (内容符号化ヘッダー、 encrypted content coding header >>137 2.) は、 次の4つの引数を順に並べたものです。 >>6 2.1.
[66] レコードは、 暗号文、 詰め区切子オクテット、 詰めの順に構成されます。 詰め区切子オクテットは、 最終レコードでは 0x02、 途中のレコードでは 0x01 です。 詰めは、 0個以上の 0x00 のバイト列です。 >>6 2.
[17] HTTPメッセージごとに、 レコードサイズは固定です。 途中のレコードのバイト長は、 必ずレコードサイズです。 最終レコードのバイト長は、 レコードサイズ以下です。 >>6 2. 詰めは、 レコードサイズに満たないデータを送るときに適宜挿入するものです。
[11] 本手法は、 JWE その他各種既存のメッセージベースの暗号化形式を採用せず、 RFC 5116 のより低レベルな構造に依っています。 既存の形式ではストリーミング処理に適しません。 >>6 1. 本手法はレコード構造により、 範囲要求やランダムアクセスが、 レコードサイズ粒度で可能となります。 >>6 2.
[44] 適切なレコードサイズは、状況により異なります。 小さくすると解読済みバイトを早めに解放できるので、 応答性が重要な応用に適しています。 小さいほどランダムアクセス時に解読が必要な余分なデータが少なくて済みます。 逆に大きいほど処理やデータのオーバーヘッドは小さくなるので、 ストリーミング処理やランダムアクセスや任意の詰めが不要な応用は、 レコードサイズを大きくできます。 極端な場合は全体を1レコードにできます。 >>6 2.
[63]
レコードサイズを記述する
rs
引数は32ビット符号無し整数なので、
AEAD_AES_128_GCM
の平文の上限 236 - 31 は超え得ません。
>>6 2.1.
さらに、
IND-CPA の 2-40 の確率を防ぐため、
同じ IKM と salt
で暗号化される平文の総量は
16バイトの
244.5
ブロック未満でなければなりません。
レコードサイズが
16バイトの倍数のとき、
これはすなわち詰めとオーバーヘッドを含めて
398テラバイトまで安全に暗号化できることを表します。
16バイトの倍数でないときは更に少なくなり、
最悪ケースは高々74テラバイトになります。
>>6 4.4.
[59] レコードシーケンス番号 (SEQ) は、 0 から始まる、 ネットワークバイト順の 96ビット符号無し整数です。 >>6 2.3. 最初のレコードが 0 で、以後 1、2 と順に増やしていきます 仕様書になし。 96ビット符号無し整数なので、 レコード数は 296 を超えられないことになります。
[13]
aes128gcm
は、
RFC 5116 5.1 節
AEAD_AES_128_GCM
(AES GCM、128ビット内容暗号化鍵利用)
で暗号化するものです。
>>6 2.
[15]
暗号化の primitive はこの通り固定化されています。
他の手法への対応 (cipher agility)
は、別の内容符号化を定義することによって実現し、
折衝は Accept-Encoding
を使うことになっています。
>>6 2.
[16] こういうとき、これまでの IETF のプロトコルだともう1段階抽象化と折衝の仕組みを導入していたところでしょうが、 既存の内容符号化の折衝を流用して統合することで、 仕組みが簡単になって、既存の HTTP の実装と統合しやすくなっているのは優れた設計です。
[14] 本手法では、 暗号化時と解読時に鍵が必要となります。 両者で共有する input-keying material (keying material、IKM) と、 HTTPメッセージごとの内容暗号化キー (CEK) の2段階となっています。 これは1つの IKM を複数の HTTPメッセージで再利用するためです >>6 2.2.。
[100] 送信時に IKM を取得するには、 次のようにします。
[72] 受信時に IKM を取得するには、 鍵識別子について、 次のようにします。 >>6 2.1.
[76] 鍵の取得の方法は、 仕様書では定義されていません >>6 2.。 受信者はその方法を知っていることが期待されます >>6 2.1.。 取得のために鍵識別子を使うことができます >>6 2.1. (が使わなければならないわけでもありません)。 鍵の共通方法は、応用ごとに別途定めておく必要があります。
[77]
鍵識別子をテキストとしてレンダリングする場合の規定がある (>>45)
ので、
利用者に提示して鍵を入力させる方式も採り得るようです。
しかしそれも1つの方法に過ぎず、 keyid
がテキストであるとも保証されていません。一般にはバイト列として扱わなければなりません。
[169] 具体的には Web Push の場合が規定されています (>>142)。
[46]
内容暗号化鍵 (CEK)
は、
IKM と salt
から、
HTTPメッセージごとに求めます。
その方法として、
RFC 5869 HKDF
で
SHA-256
を使ったものを用います。
>>6 2.2.
[89] CEK の取得は、 PRK について次のようにします。 >>6 2.2.
[87] 疑似乱数鍵 (PRK) の取得は、 salt、IKM について、 次のようにします。 >>6 2.2.
[90] PRK は、CEK や nonce の取得に使います。
[82]
salt
は、
暗号化時にHTTPメッセージごとに準備し、
ヘッダーブロックに入れて解読者へと引き渡します。
解読者はヘッダーブロックから取り出して使います。
[54] nonce の取得は、 PRK、 SEQ について次のようにします。 >>6 2.3.
[60] nonce は、 レコードの削除や順序入れ替えを防ぐものです。 >>6 2.3.
[146] 利用者エージェントは、 プッシュ購読プッシュ購読の作成時に、 次のようにします。
[256] プッシュ購読の鍵ペアの秘密鍵は、 アプリケーションに提供してはなりません。 >>255
[257] プッシュ購読の鍵ペアの公開鍵は、
getKey
メソッドを通じてアプリケーションから取得可能です。
[158]
symmetric authentication secret
である
プッシュ購読の authentication secret
は、
プッシュメッセージが正しく認証されるようにするものです。
>>137 3.2.
authentication secret
は、
getKey
メソッドを通じてアプリケーションから取得可能です。
[141] プッシュ購読の鍵ペアの公開鍵と プッシュ購読の authentication secret は、 他の必要な情報と共に、 アプリケーションに引き渡します >>137 2.。 アプリケーションは、 これらをアプリケーションサーバーに引き渡します >>137 2.1.。
[144] アプリケーションは、 認可されたアプリケーションサーバーに対して、 認証された秘密が保持される通信媒体を使って、 これらを引き渡さなければなりません。 これは RFC 8030 に述べられた理由に加え、 authentication secret が漏れるとプッシュメッセージを送れてしまうからです。 ほとんどのアプリケーションは予め決められたアプリケーションサーバーとの関係を持っていて、 HTTPS のような方法でこの条件を満たせます。 >>137 2.1.
[162] IKM の取得は、 RFC 5869 HKDF で SHA-256 を使ったものを用います。 >>137 3.3. このとき、 アプリケーションサーバー (プッシュメッセージ送信者) は利用者エージェントから引き渡されたプッシュ購読の情報を使い、 利用者エージェント (プッシュメッセージ受信者) は生成して保持していたプッシュ購読の情報を使います。
[142] プッシュ購読における IKM の取得は、 鍵識別子について、 次のようにします。
[181] 利用者エージェントやアプリケーションサーバーは、 受信した公開鍵が P-256 curve 上にあることを検証しなければなりません。 >>137 7.
[250] それ以前の大前提として、公開鍵や authentication secret として与えられたものが適切な入力の形であるかも検証しなければなりません。
[97] 符号化は、平文のバイト列を入力とし、 暗号化されたバイト列を出力とする操作です。 符号化の処理たる符号化器は、 次の状態を保持します。
[95] 符号化器による符号化の開始時には、 非負整数レコードサイズについて、 次のようにします。 >>6 2.1.
[102] 符号化器による符号化の過程、 バイト列データを、 これがバイト列全体の末尾に当たるかどうかを表す真偽値最後について送信するには、 次のようにします。 >>6 2.1.
[171] Web Push アプリケーションサーバーは、 プッシュメッセージをレコード 1つで暗号化しなければなりません。 レコードサイズは、 入力バイト列の長さ + 17 以上 (仕様書では greater than) の値としなければなりません。 >>137 4.
[172]
プッシュサービスは、
RFC 8030 7.2節により、
4096バイトを超える payload body
に対応する必要はありません。
AEAD_AES_128_GCM
の追加が16バイトなので、
平文に使えるのは高々3993バイトです。
>>137 4.
[173]
Web Push
アプリケーションサーバーは、
aes128gcm
以外の内容符号化を使ってはなりません。
aes128gcm
を複数回適用することはできません。
>>137 4.
[227] Web Push 用に簡略化された符号化は、 バイト列データを次のようにします。
AEAD_AES_128_GCM
の暗号化を実行した結果に設定します。[28] 復号は、暗号化されたバイト列を入力とし、 解読されたバイト列を出力とする操作です。 復号の処理たる復号器は、 次の状態を保持します。
[26] 復号器による復号は、 真偽値単一レコードについて、 次のようにします。
null
の場合、AEAD_AES_128_GCM
の解読を実行した結果に設定します。[118] 仕様書はエラー処理をほとんど曖昧に濁しています。 レコードを失敗とみなすべき条件がいくつか定められていますが、 そのときまでに得られた結果バイト列をそのまま使って良いのかどうか、 失敗したレコードから得られた情報を結果バイト列に含めて良いのか、 仕様書からは読み取れません。
[132] 特に問題なのは、詰め区切子オクテットが最終レコードなら 0x02、 それ以外なら 0x01 でなければ失敗としなければならない >>6 2. との条件です。ストリーミング処理でこの要件を満たすためには、 次のレコード (または入力の末端) まで処理を進める必要があります。 仕様書がどうとでも解釈できるので、 実装によって、あるいはネットワークからのバイトの到着タイミング次第で、 挙動が変わってくるおそれがあります。
[62] 途中で途切れたメッセージでも本手法は処理できますが、 完全なメッセージであるものとして処理してはなりません。 途中までのメッセージでも処理する受信者は、 攻撃者によりメッセージが途中で切られた可能性も考慮する必要があります。 >>6 4.2. この規定の存在が、失敗の扱いの解釈を難しくします。 途切れたメッセージやランダムアクセスの処理では、 入力中最後のレコードの詰め区切子オクテットが 0x02 でなくても認めなければなりません。 このような実装方針次第でいかようにもなりそうな曖昧な規定方法は、 セキュリティー問題の温床でしかありません。
[157] 途中のレコードで解読に失敗した場合、 無視して次のレコードに進むべきなのか、停止するべきなのか不明です。
[61]
本手法を使って内容の起源を認証する受信者は、
aes128gcm
内容符号化を含まないHTTPメッセージを拒絶しなければなりません。
内容符号化が自動的に除去されて、最終的な受信者がそれに気づかないおそれがあります。
>>6 4.1.
[174]
Web Push
利用者エージェントは、
複数のレコードに対応する必要はありません。
利用者エージェントは
rs
を無視して構いません。
(レコードサイズを検査しなくても、
妥当な場合に解読は高い確率で失敗します。)
しかし詰め区切子オクテットは検査しなければなりません。
0x02 以外の詰め区切子オクテットがある場合、
メッセージを捨てなければなりません。
>>137 4.
つまり単一レコードを真として実行しなければなりません。
[177]
とひどい規定があります。そんなことが許されるなら、
実際のレコードサイズと矛盾する
rs
が指定されても受け入れられる可能性と拒絶される可能性があるわけで、
相互運用性のリスクでしかありません。
[178]
しかも、複数レコードに対応する必要がないということは、
対応してもいいように聞こえますが、
0x02 かどうか検査しなければならないということは、
複数レコードに対応してはいけないということです。
このような制限が認められることが
aes128gcm
の仕様書に一言も触れられていないのも問題です。
[176]
Web Push
では
aes128gcm
をちょうど1回だけ適用することが求められていますが、
受信者がどうするべきか定められていません。
内容符号化が使われていない場合や、
他の内容符号化が使われている場合にどう処理するべきかは不明です。
[183] Web Push 専用に簡略化した復号は、 次のようにします。
AEAD_AES_128_GCM
の解読を実行した結果に設定します。[1] Encrypted Content-Encoding for HTTP ( 版) http://httpwg.org/http-extensions/draft-ietf-httpbis-encryption-encoding.html
[2] draft-ietf-webpush-encryption-08 - Message Encryption for Web Push () https://tools.ietf.org/html/draft-ietf-webpush-encryption-08
[3] IANA登録簿に aes128gcm
が登録されました。
[4] Add PushManager.supportedContentEncodings (#252) (beverloo著, ) https://github.com/w3c/push-api/commit/813f9af75d59e3fa1522db9aeeaa2bd158ff10bf
[5] encrypted-content-encoding/ece.js at master · web-push-libs/encrypted-content-encoding () https://github.com/web-push-libs/encrypted-content-encoding/blob/master/nodejs/ece.js
[134] 古い案では内容符号化
aesgcm
,
内容符号化 aesgcm128
,
HTTPヘッダー Encryption:
,
HTTPヘッダー Encryption-Key:
,
HTTPヘッダー Crypto-Key:
が提案されていました。
[8]
、
aes128gcm
の仕様書が
IETF
の提案標準
RFC 8188
が出版されました
>>6。
[133] それにしてもこの時代に出版されたとは思えない、古き悪しき時代を思わせる曖昧な仕様書です。 構文、生成側処理、解釈側処理のどれなのかはっきりしない曖昧な規定、 事実の文ベースで実装の要件がはっきりしない上に、 用語の表記がその場その場で少しずつ揺れていて意図的かどうかわかりにくい、 挙動が用語のイメージの暗黙の了解によって規定され明文化されていない、 といった IETF にありがちな空気を読まないといけない仕様書。 こんなもので相互運用性は維持できるのでしょうか。
[139] 、 Web Push での暗号化方式の仕様書が IETF の提案標準 RFC 8291 として出版されました >>137。