[インデックス 16494] ファイルの概要
このコミットは、Go言語のcrypto/tls
パッケージにTLS 1.1のサポートを追加するものです。TLS 1.1は、TLS 1.0と比較して特にCBC (Cipher Block Chaining) モードにおけるInitialization Vector (IV) の扱いが変更されており、これによりセキュリティが向上しています。この変更は、TLS 1.2のサポートを可能にするための前提条件でもあります。
コミット
commit 2112fed7437c73d76fe514a0ff5082d56cb69e6b
Author: Adam Langley <agl@golang.org>
Date: Tue Jun 4 20:02:22 2013 -0400
crypto/tls: support TLS 1.1.
The significant change between TLS 1.0 and 1.1 is the addition of an explicit IV in the case of CBC encrypted records. Support for TLS 1.1 is needed in order to support TLS 1.2.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7880043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2112fed7437c73d76fe514a0ff5082d56cb69e6b
元コミット内容
crypto/tls
パッケージにTLS 1.1のサポートを追加します。TLS 1.0と1.1の間の重要な変更点は、CBC暗号化レコードにおける明示的なIVの追加です。TLS 1.2をサポートするためには、TLS 1.1のサポートが必要です。
変更の背景
このコミットの主な背景は、TLS 1.0に存在するセキュリティ上の脆弱性、特にBEAST (Browser Exploit Against SSL/TLS) 攻撃への対策と、将来的なTLS 1.2サポートへの道を開くことです。
TLS 1.0では、CBCモードで暗号化されたレコードのInitialization Vector (IV) が、前のレコードの最後の暗号文ブロックから導出されていました。この「暗黙的なIV」の生成方法は、攻撃者がIVを予測可能にしてしまい、特定の条件下で平文の一部を推測できる可能性がありました。BEAST攻撃は、このIVの予測可能性と、特定のパディングスキームを悪用して、HTTPクッキーなどの機密情報を復元するものでした。
TLS 1.1では、この脆弱性に対処するため、各レコードに対して新しい予測不可能なIVを生成し、それを暗号文の前に含めて送信する「明示的なIV」の概念が導入されました。これにより、IVのランダム性が保証され、BEASTのようなCBC関連の攻撃に対する耐性が向上しました。
Go言語のcrypto/tls
パッケージが最新のセキュリティ標準に準拠し、より安全な通信を提供するためには、このTLS 1.1のサポートが不可欠でした。また、TLS 1.2はTLS 1.1をベースにしているため、TLS 1.1のサポートはTLS 1.2を実装するための前提条件となります。
前提知識の解説
TLS (Transport Layer Security)
TLSは、インターネット上で安全な通信を行うための暗号化プロトコルです。ウェブブラウジング(HTTPS)、電子メール、VoIPなど、様々なアプリケーションで利用されています。TLSは、クライアントとサーバー間でデータの機密性、完全性、認証を保証します。
CBC (Cipher Block Chaining) モード
CBCは、ブロック暗号の運用モードの一つです。各ブロックの暗号化は、前のブロックの暗号文と現在の平文ブロックをXORすることで行われます。これにより、同じ平文ブロックが繰り返されても、異なる暗号文ブロックが生成されるため、パターン攻撃を防ぐことができます。 CBCモードでは、最初のブロックを暗号化するためにInitialization Vector (IV) と呼ばれるランダムな値が必要です。後続のブロックでは、前のブロックの暗号文がIVとして機能します。
Initialization Vector (IV)
IVは、暗号化プロセスを開始するために使用されるランダムなビット列です。CBCモードのようなブロック暗号モードでは、同じ鍵で同じ平文を複数回暗号化しても、異なる暗号文が生成されるようにするためにIVが使用されます。
- 暗黙的なIV (Implicit IV): TLS 1.0以前では、CBCモードのIVは前のレコードの最後の暗号文ブロックから導出されていました。これは、攻撃者がIVを予測できる可能性があり、セキュリティ上の問題を引き起こしました。
- 明示的なIV (Explicit IV): TLS 1.1以降では、各レコードごとに新しいランダムなIVが生成され、暗号文の前に平文で送信されます。これにより、IVの予測可能性が排除され、セキュリティが向上します。
BEAST (Browser Exploit Against SSL/TLS) 攻撃
BEAST攻撃は、TLS 1.0およびSSL 3.0のCBCモードにおける暗黙的なIVの脆弱性を悪用したサイドチャネル攻撃です。攻撃者は、既知の平文と暗号文のペアを利用し、IVの予測可能性とパディングの特性を組み合わせて、暗号化された通信からクッキーなどの機密情報を推測します。この攻撃は、特にブラウザとウェブサーバー間のHTTPS通信で有効でした。
技術的詳細
このコミットは、Go言語のcrypto/tls
パッケージにおいて、TLS 1.1の主要な変更点である「明示的なIV」のサポートを実装しています。
TLS 1.0とTLS 1.1の最も重要な違いは、CBCモードにおけるIVの扱いです。
- TLS 1.0: IVは前のレコードの最後の暗号文ブロックから導出される(暗黙的IV)。これにより、IVが予測可能になり、BEAST攻撃のような脆弱性が生じました。
- TLS 1.1: 各レコードごとに新しいランダムなIVが生成され、暗号文の前に平文で送信される(明示的IV)。これにより、IVの予測可能性が排除され、CBCモードのセキュリティが大幅に向上しました。
このコミットでは、以下の技術的な変更が行われています。
-
バージョン定数の追加と更新:
src/pkg/crypto/tls/common.go
において、VersionTLS11
(0x0302) が新しいプロトコルバージョンとして追加されました。minVersion
とmaxVersion
の定数が更新され、maxVersion
がVersionTLS11
を指すようになりました。これにより、GoのTLS実装がデフォルトでTLS 1.1をサポートするようになります。
-
CBCモードインターフェースの拡張:
src/pkg/crypto/cipher/cbc.go
に、cbcEncrypter
とcbcDecrypter
構造体にSetIV([]byte)
メソッドが追加されました。これは、CBCモードの暗号化器/復号化器が外部からIVを設定できるようにするためのものです。src/pkg/crypto/tls/conn.go
にcbcMode
インターフェースが定義され、cipher.BlockMode
とSetIV([]byte)
メソッドを持つ型がこのインターフェースを満たすようにしました。これにより、TLSレイヤーがCBC暗号化器のIVを動的に設定できるようになります。
-
レコード暗号化/復号化ロジックの変更:
src/pkg/crypto/tls/conn.go
のdecrypt
関数とencrypt
関数が、TLS 1.1の明示的IVを処理するように修正されました。decrypt
関数では、explicitIVLen
という変数が導入され、TLS 1.1以上のバージョンではブロックサイズ分のIVがペイロードの先頭から読み取られるようになりました。このIVはcbcMode.SetIV
を使って設定され、実際の暗号文はIVの後に続くデータとして処理されます。encrypt
関数では、TLS 1.1以上のバージョンでCBCモードが使用される場合、暗号化前にランダムなIVが生成され、レコードヘッダーと実際のペイロードの間に挿入されるようになりました。このIVもcbcMode.SetIV
を使って設定されます。
-
ハンドシェイクプロセスのバージョンネゴシエーションの更新:
src/pkg/crypto/tls/common.go
に(*Config).minVersion()
,(*Config).maxVersion()
,(*Config).mutualVersion()
メソッドが追加されました。これにより、TLS設定に基づいて許容される最小/最大バージョンと、ピアとの間で合意されるバージョンをより柔軟に決定できるようになりました。src/pkg/crypto/tls/handshake_client.go
とsrc/pkg/crypto/tls/handshake_server.go
において、クライアントとサーバーのハンドシェイク時に、これらの新しいバージョンネゴシエーションロジックが使用されるようになりました。これにより、TLS 1.1のネゴシエーションが可能になります。
-
テストケースの追加:
src/pkg/crypto/tls/handshake_client_test.go
とsrc/pkg/crypto/tls/handshake_server_test.go
に、TLS 1.1のハンドシェイクをテストするための新しいテストケースが追加されました。これにより、TLS 1.1のサポートが正しく機能することを確認できます。
これらの変更により、GoのTLS実装はTLS 1.1のセキュリティ強化に対応し、より堅牢な通信を提供できるようになりました。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
doc/go1.2.txt
: Go 1.2のリリースノートにTLS 1.1サポートが追加されたことを記載。src/pkg/crypto/cipher/cbc.go
: CBC暗号化器/復号化器にIVを設定するメソッドを追加。src/pkg/crypto/tls/cipher_suites.go
: MAC計算関数のシグネチャ変更(ヘッダーとデータが分離)。src/pkg/crypto/tls/common.go
: TLSバージョン定数(TLS 1.1)の追加と、バージョンネゴシエーションロジックの改善。src/pkg/crypto/tls/conn.go
: TLSレコードの暗号化/復号化ロジックをTLS 1.1の明示的IVに対応させる変更。src/pkg/crypto/tls/handshake_client.go
: クライアントハンドシェイクにおけるバージョンネゴシエーションの更新。src/pkg/crypto/tls/handshake_client_test.go
: TLS 1.1クライアントハンドシェイクのテストケース追加。src/pkg/crypto/tls/handshake_server.go
: サーバーハンドシェイクにおけるバージョンネゴシエーションの更新。src/pkg/crypto/tls/handshake_server_test.go
: TLS 1.1サーバーハンドシェイクのテストケース追加。src/pkg/crypto/tls/key_agreement.go
: 鍵合意プロセスのバージョンチェックの更新。src/pkg/crypto/tls/prf.go
: PRF (Pseudo-Random Function) のバージョンチェックの更新。src/pkg/crypto/tls/prf_test.go
: PRFテストのバージョン定数更新。
特に、src/pkg/crypto/tls/conn.go
におけるdecrypt
およびencrypt
関数の変更と、src/pkg/crypto/cipher/cbc.go
へのSetIV
メソッドの追加が、明示的IVサポートの核心部分です。
コアとなるコードの解説
src/pkg/crypto/cipher/cbc.go
func (x *cbcEncrypter) SetIV(iv []byte) {
if len(iv) != len(x.iv) {
panic("cipher: incorrect length IV")
}
copy(x.iv, iv)
}
func (x *cbcDecrypter) SetIV(iv []byte) {
if len(iv) != len(x.iv) {
panic("cipher: incorrect length IV")
}
copy(x.iv, iv)
}
この変更は、CBCモードの暗号化器と復号化器が、外部からInitialization Vector (IV) を設定できるようにするためのものです。TLS 1.1では、各レコードの暗号化/復号化に新しいランダムなIVが使用されるため、この機能が必要となります。SetIV
メソッドは、提供されたIVを内部のIVバッファにコピーします。
src/pkg/crypto/tls/common.go
const (
VersionSSL30 = 0x0300
VersionTLS10 = 0x0301
VersionTLS11 = 0x0302
)
const (
// ...
minVersion = VersionSSL30
maxVersion = VersionTLS11
)
// ...
func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
minVersion := c.minVersion()
maxVersion := c.maxVersion()
if vers < minVersion {
return 0, false
}
if vers > maxVersion {
vers = maxVersion
}
return vers, true
}
VersionTLS11
という新しい定数が追加され、maxVersion
がVersionTLS11
に更新されました。これにより、GoのTLS実装がデフォルトでTLS 1.1をサポートするようになります。
mutualVersion
関数は、クライアントとサーバー間で合意可能なTLSプロトコルバージョンを決定するためのロジックをカプセル化しています。これは、Config
構造体のMinVersion
とMaxVersion
設定を考慮し、ピアが提示したバージョンと自身のサポート範囲を比較して、最適なバージョンを選択します。
src/pkg/crypto/tls/conn.go
type cbcMode interface {
cipher.BlockMode
SetIV([]byte)
}
func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) {
// ...
explicitIVLen := 0
// ...
case cbcMode:
blockSize := c.BlockSize()
if hc.version >= VersionTLS11 {
explicitIVLen = blockSize
}
if explicitIVLen > 0 {
c.SetIV(payload[:explicitIVLen])
payload = payload[explicitIVLen:]
}
c.CryptBlocks(payload, payload)
// ...
return true, recordHeaderLen + explicitIVLen, 0
}
func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
// ...
case cbcMode:
blockSize := c.BlockSize()
if explicitIVLen > 0 {
c.SetIV(payload[:explicitIVLen])
payload = payload[explicitIVLen:]
}
// ...
c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
// ...
}
func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
// ...
explicitIVLen := 0
var cbc cbcMode
if c.out.version >= VersionTLS11 {
if cbc, ok = c.out.cipher.(cbcMode); ok {
explicitIVLen = cbc.BlockSize()
}
}
b.resize(recordHeaderLen + explicitIVLen + m)
// ...
if explicitIVLen > 0 {
explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
break
}
}
copy(b.data[recordHeaderLen+explicitIVLen:], data)
c.out.encrypt(b, explicitIVLen)
// ...
}
cbcMode
インターフェースが定義され、cipher.BlockMode
に加えてSetIV
メソッドを持つ型を扱うことができるようになりました。
decrypt
関数では、TLS 1.1以上のバージョンでCBCモードが使用される場合、レコードの先頭からブロックサイズ分のデータが明示的IVとして読み取られ、cbcMode.SetIV
を使って設定されます。これにより、復号化器は正しいIVで動作します。
encrypt
関数とwriteRecord
関数では、TLS 1.1以上のバージョンでCBCモードが使用される場合、ランダムなIVが生成され、レコードヘッダーと実際の暗号化データの間(recordHeaderLen
とペイロードの間)に挿入されます。このIVはcbcMode.SetIV
を使って暗号化器に渡され、その後のデータが暗号化されます。
これらの変更により、GoのTLS実装はTLS 1.1の明示的IVの要件を満たし、BEAST攻撃のような脆弱性から保護されるようになりました。
関連リンク
参考にした情報源リンク
- TLS 1.1 vs TLS 1.0 (Explicit IVs): https://www.keycdn.com/support/tls-1-1-vs-tls-1-0
- TLS 1.1 Explicit IVs: https://security.stackexchange.com/questions/10062/what-is-the-difference-between-tls-1-0-and-tls-1-1-in-terms-of-iv-handling
- BEAST Attack Explained: https://www.invicti.com/blog/web-security/beast-attack-tls-1-0/
- TLS 1.1 Padding Error Handling: https://www.wolfssl.com/docs/tls11/
- BEAST Attack and IVs: https://www.virtuesecurity.com/blog/beast-attack-explained/
- NIST SP 800-52 Rev. 1 (TLS Guidelines): https://csrc.nist.gov/publications/detail/sp/800-52/rev-1/final (General reference for TLS security)
- RFC 4346 (TLS 1.1): https://datatracker.ietf.org/doc/html/rfc4346 (Official TLS 1.1 specification)
- RFC 5246 (TLS 1.2): https://datatracker.ietf.org/doc/html/rfc5246 (Official TLS 1.2 specification, mentions TLS 1.1 as a precursor)
- Padding Oracle Attacks: https://deepsec.net/docs/Slides/2012/Padding_Oracle_Attacks_on_TLS.pdf (Relevant for understanding padding vulnerabilities)
- CERT Advisory VU#652086: https://www.kb.cert.org/vuls/id/652086 (BEAST attack advisory)
- StackExchange on TLS 1.1 improvements: https://security.stackexchange.com/questions/10062/what-is-the-difference-between-tls-1-0-and-tls-1-1-in-terms-of-iv-handling
- StackExchange on TLS 1.1 and BEAST: https://security.stackexchange.com/questions/10062/what-is-the-difference-between-tls-1-0-and-tls-1-1-in-terms-of-iv-handling
- StackExchange on TLS 1.1 and Lucky Thirteen: https://security.stackexchange.com/questions/29304/is-tls-1-1-vulnerable-to-lucky-thirteen-attack