[インデックス 18204] ファイルの概要
このコミットは、Go言語のcrypto/tls
パッケージにおいて、TLSの再ネゴシエーション拡張(RFC 5746)のサポートを追加するものです。これにより、TLS再ネゴシエーション攻撃(CVE-2009-3555)に対する防御策が導入され、GoのTLS実装のセキュリティが強化されます。
コミット
commit 779ef7bd132ae4971f07baf2df8eec508a45f60c
Author: Adam Langley <agl@golang.org>
Date: Thu Jan 9 13:38:11 2014 -0500
crypto/tls: support renegotiation extension.
The renegotiation extension was introduced[1] due to an attack by Ray in
which a client's handshake was spliced into a connection that was
renegotiating, thus giving an attacker the ability to inject an
arbitary prefix into the connection.
Go has never supported renegotiation as a server and so this attack
doesn't apply. As a client, it's possible that at some point in the
future the population of servers will be sufficiently updated that
it'll be possible to reject connections where the server hasn't
demonstrated that it has been updated to address this problem.
We're not at that point yet, but it's good for Go servers to support
the extension so that it might be possible to do in the future.
[1] https://tools.ietf.org/search/rfc5746
R=golang-codereviews, mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/48580043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/779ef7bd132ae4971f07baf2df8eec508a45f60c
元コミット内容
crypto/tls: renegotiation extensionのサポート。
再ネゴシエーション拡張は、Rayによる攻撃[1]によって導入されました。この攻撃では、クライアントのハンドシェイクが再ネゴシエーション中の接続に組み込まれ、攻撃者が接続に任意のプレフィックスを挿入する能力を与えました。
Goはサーバーとして再ネゴシエーションをサポートしたことがないため、この攻撃は適用されません。クライアントとしては、将来的にサーバーの大部分がこの問題に対処するために十分に更新され、サーバーがこの問題に対処したことを示していない接続を拒否できるようになる可能性があります。
まだその段階ではありませんが、将来的に可能になるようにGoサーバーがこの拡張をサポートすることは良いことです。
[1] https://tools.ietf.org/search/rfc5746
変更の背景
このコミットの背景には、TLS/SSLプロトコルにおける再ネゴシエーションの脆弱性(CVE-2009-3555)があります。この脆弱性は、2009年に発見されたもので、攻撃者が既存のTLS接続に任意のデータを挿入できるというものでした。
具体的には、攻撃者はまずターゲットサーバーとのTLS接続を確立します。次に、その接続上で任意のプレーンテキストデータをサーバーに送信します。その後、攻撃者は正当なクライアントとサーバーの間で中間者(Man-in-the-Middle, MITM)として振る舞い、クライアントが接続を試みると、クライアントのTLSハンドシェイクを傍受し、それを自身の既存のサーバーとの接続に組み込み、再ネゴシエーションを開始させます。
サーバーはMITM攻撃に気づかず、クライアントのハンドシェイクを既存の接続上での正当な再ネゴシエーションとして扱います。その結果、サーバーは攻撃者が最初に挿入したデータが、現在通信している正当なクライアントから発信されたものだと誤解してしまいます。これにより、攻撃者はサーバーが正当なクライアントからのものと認識するアプリケーションプロトコルストリームにコマンドやデータを挿入することが可能になりました。例えば、HTTPの文脈では、攻撃者が部分的なリクエストを挿入し、サーバーがそれをクライアントのその後のリクエストと結合することで、不正な操作(例:セッションクッキーが関与する場合、攻撃者が正当なユーザーに代わって購入を行う)につながる可能性がありました。この脆弱性はSSL v3.0以降およびTLS v1.0以降に影響を与え、HTTP、IMAP、SMTPなどのプロトコルに影響を及ぼしました。
この脆弱性に対処するため、RFC 5746「TLS Renegotiation Indication Extension」が策定されました。このRFCは、再ネゴシエーションが実行されるTLS接続に暗号学的にバインドするメカニズムを導入することで、この種の攻撃を防ぐことを目的としています。
Go言語のTLS実装は、サーバーサイドでの再ネゴシエーションを元々サポートしていなかったため、この攻撃の直接的な影響は受けていませんでした。しかし、クライアントとしては、将来的にRFC 5746に対応したサーバーが増えることを考慮し、Goクライアントがこの拡張をサポートすることで、より安全な通信が可能になるという判断から、このコミットが導入されました。また、Goサーバーがこの拡張をサポートすることで、将来的にクライアントがサーバーのRFC 5746対応状況を確認し、非対応のサーバーとの接続を拒否できるようになる可能性も考慮されています。
前提知識の解説
TLS/SSLプロトコル
TLS (Transport Layer Security) およびその前身である SSL (Secure Sockets Layer) は、インターネット上で安全な通信を行うための暗号化プロトコルです。クライアントとサーバー間でデータを送受信する際に、盗聴、改ざん、なりすましを防ぐ役割を果たします。
TLS通信は、主に以下の2つのフェーズで構成されます。
- ハンドシェイクフェーズ (Handshake Phase):
- クライアントとサーバーが互いを認証し、暗号スイート(使用する暗号アルゴリズムの組み合わせ)を決定し、セッションキーを生成します。
- このフェーズで、サーバーは自身のデジタル証明書をクライアントに提示し、クライアントはそれを検証します。
- セッションキーは、その後のデータ転送フェーズで使用される対称鍵暗号の鍵となります。
- データ転送フェーズ (Data Transfer Phase):
- ハンドシェイクフェーズで確立されたセキュアなチャネルを通じて、アプリケーションデータが暗号化されて送受信されます。
TLS再ネゴシエーション
TLS再ネゴシエーションとは、確立済みのTLSセッション中に、新しいハンドシェイクを実行して、暗号スイートの変更、新しいセッションキーの生成、クライアント認証の追加などを行うプロセスです。これは、例えば、初期接続時にはクライアント認証を行わなかったが、特定の操作を行う際にクライアント認証が必要になった場合などに利用されます。
TLS再ネゴシエーション攻撃 (CVE-2009-3555)
前述の通り、この攻撃は、TLS再ネゴシエーションの際に、既存のセッションと新しいハンドシェイクの間に暗号学的な関連付けが不足していたことを悪用します。攻撃者は、自身の接続と正当なクライアントの接続を巧妙に組み合わせることで、サーバーが攻撃者のデータを正当なクライアントからのものと誤認するように仕向けました。
RFC 5746: TLS Renegotiation Indication Extension
このRFCは、TLS再ネゴシエーション攻撃に対処するために導入された拡張です。主な目的は、再ネゴシエーションを既存のTLS接続に暗号学的にバインドすることです。これにより、攻撃者が不正なデータを挿入しても、サーバーがそれを検出できるようになります。
RFC 5746は、以下の2つのメカニズムを導入しています。
- Renegotiation Info Extension (RIE):
- クライアントとサーバーがハンドシェイクメッセージ(ClientHello, ServerHello)に含める新しいTLS拡張です。
- この拡張には、以前のハンドシェイクから導出されたキー確認値(
verify_data
)が含まれます。 - 再ネゴシエーションを行う際、クライアントとサーバーは、この拡張を交換し、
verify_data
が一致するかどうかを確認します。これにより、両者が同じ過去の接続状態を認識していることを保証します。
- Signaling Cipher Suite Value (SCSV):
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
(0x00FF) という特別な暗号スイート値です。- これは、クライアントがClientHelloメッセージに含めることで、サーバーに対してRFC 5746をサポートしていることを示唆します。
- サーバーがこのSCSVを受け取った場合、サーバーもRFC 5746に対応している必要があります。
これらのメカニズムにより、再ネゴシエーションが特定の接続に暗号学的に結びつけられ、攻撃者がデータを挿入しても、その整合性が検証されるようになります。
技術的詳細
このコミットは、Go言語のcrypto/tls
パッケージにRFC 5746で定義されている再ネゴシエーション拡張のサポートを追加します。
extensionRenegotiationInfo
とscsvRenegotiation
の追加
src/pkg/crypto/tls/common.go
ファイルに、再ネゴシエーション拡張のタイプを示す定数extensionRenegotiationInfo
(0xff01) と、SCSVを示す定数scsvRenegotiation
(0x00ff) が追加されました。これらは、TLSハンドシェイクメッセージ内で再ネゴシエーション関連の情報を識別するために使用されます。
clientHelloMsg
とserverHelloMsg
の変更
src/pkg/crypto/tls/handshake_messages.go
ファイルでは、clientHelloMsg
とserverHelloMsg
構造体にsecureRenegotiation
というブール型のフィールドが追加されました。このフィールドは、クライアントまたはサーバーがセキュアな再ネゴシエーションをサポートしているかどうかを示します。
clientHelloMsg
の変更点
marshal()
メソッド:secureRenegotiation
がtrue
の場合、extensionRenegotiationInfo
拡張がClientHelloメッセージに追加されるようになりました。この拡張は、長さが1バイトで、その値は0です。これは、RFC 5746で定義されているrenegotiated_connection
フィールドが空であることを示します。- 既存の拡張(
extensionNextProtoNeg
,extensionServerName
など)のエンコーディングロジックも、バイトオーダーの修正(& 0xff
の追加)が行われています。
unmarshal()
メソッド:- 受信したClientHelloメッセージの暗号スイートリストに
scsvRenegotiation
が含まれている場合、secureRenegotiation
フィールドがtrue
に設定されます。 - また、
extensionRenegotiationInfo
拡張がメッセージ内に存在し、その形式がRFC 5746の仕様(長さが1で値が0)に準拠している場合も、secureRenegotiation
フィールドがtrue
に設定されます。
- 受信したClientHelloメッセージの暗号スイートリストに
serverHelloMsg
の変更点
marshal()
メソッド:secureRenegotiation
がtrue
の場合、extensionRenegotiationInfo
拡張がServerHelloメッセージに追加されるようになりました。ClientHelloと同様に、長さ1、値0の形式です。
unmarshal()
メソッド:- 受信したServerHelloメッセージに
extensionRenegotiationInfo
拡張が存在し、その形式がRFC 5746の仕様に準拠している場合、secureRenegotiation
フィールドがtrue
に設定されます。
- 受信したServerHelloメッセージに
クライアントハンドシェイクの変更
src/pkg/crypto/tls/handshake_client.go
ファイルでは、clientHandshake()
関数内でclientHelloMsg
を構築する際に、secureRenegotiation
フィールドが常にtrue
に設定されるようになりました。これは、Goクライアントが常にセキュアな再ネゴシエーションを試みることを意味します。
サーバーハンドシェイクの変更
src/pkg/crypto/tls/handshake_server.go
ファイルでは、サーバーがserverHelloMsg
を構築する際に、クライアントのclientHelloMsg
のsecureRenegotiation
フィールドの値を自身のserverHelloMsg
のsecureRenegotiation
フィールドにコピーするようになりました。これにより、サーバーはクライアントがセキュアな再ネゴシエーションをサポートしていることを認識し、それに応じて応答します。
テストデータの更新
このコミットでは、多数のテストデータファイル(src/pkg/crypto/tls/testdata/
以下のファイル)が更新されています。これらのファイルは、TLSハンドシェイクのバイトストリームを記録したもので、再ネゴシエーション拡張が追加されたことによって、ハンドシェイクメッセージの構造が変化したため、それに合わせて更新が必要となりました。これにより、新しい実装が既存のプロトコルバージョンや暗号スイートと正しく連携することを確認しています。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は、以下のファイルに集中しています。
src/pkg/crypto/tls/common.go
: 新しい定数の定義。src/pkg/crypto/tls/handshake_client.go
: クライアントHelloメッセージの構築ロジックの変更。src/pkg/crypto/tls/handshake_messages.go
: TLSハンドシェイクメッセージ構造体(clientHelloMsg
,serverHelloMsg
)の変更と、それらのマーシャリング/アンマーシャリングロジックの変更。src/pkg/crypto/tls/handshake_server.go
: サーバーHelloメッセージの構築ロジックの変更。src/pkg/crypto/tls/handshake_server_test.go
: テストケースの修正。src/pkg/crypto/tls/testdata/
: 多数のテストデータファイルの更新。
具体的な変更行数は以下の通りです。
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -64,7 +64,7 @@ const (
)
// TLS extension numbers
-var (
+const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
@@ -72,11 +72,17 @@ var (
extensionSignatureAlgorithms uint16 = 13
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ extensionRenegotiationInfo uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
)
// TLS Elliptic Curves
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
-var (
+const (
curveP256 uint16 = 23
curveP384 uint16 = 24
curveP521 uint16 = 25
@@ -84,7 +90,7 @@ var (
// TLS Elliptic Curve Point Formats
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
-var (
+const (
pointFormatUncompressed uint8 = 0
)
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -22,14 +22,15 @@ func (c *Conn) clientHandshake() error {
}
hello := &clientHelloMsg{
- vers: c.config.maxVersion(),
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- ocspStapling: true,
- serverName: c.config.ServerName,
- supportedCurves: []uint16{curveP256, curveP384, curveP521},
- supportedPoints: []uint8{pointFormatUncompressed},
- nextProtoNeg: len(c.config.NextProtos) > 0,
+ vers: c.config.maxVersion(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: []uint16{curveP256, curveP384, curveP521},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiation: true,
}
possibleCipherSuites := c.config.cipherSuites()
--- a/src/pkg/crypto/tls/handshake_messages.go
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -7,20 +7,21 @@ package tls
import "bytes"
type clientHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuites []uint16
- compressionMethods []uint8
- nextProtoNeg bool
- serverName string
- ocspStapling bool
- supportedCurves []uint16
- supportedPoints []uint8
- ticketSupported bool
- sessionTicket []uint8
- signatureAndHashes []signatureAndHash
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []uint16
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAndHashes []signatureAndHash
+ secureRenegotiation bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -42,7 +43,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
- eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
+ eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
+ m.secureRenegotiation == m1.secureRenegotiation
}
func (m *clientHelloMsg) marshal() []byte {
@@ -80,6 +82,10 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -114,13 +120,13 @@ func (m *clientHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
- z[1] = byte(extensionNextProtoNeg)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
// The length is always 0
z = z[4:]
}
if len(m.serverName) > 0 {
z[0] = byte(extensionServerName >> 8)
- z[1] = byte(extensionServerName)
+ z[1] = byte(extensionServerName & 0xff)
l := len(m.serverName) + 5
z[2] = byte(l >> 8)
z[3] = byte(l)
@@ -224,6 +230,13 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[2:]
}
}
+ if m.secureRenegotiation {
+ z[0] = byte(extensionRenegotiationInfo >> 8)
+ z[1] = byte(extensionRenegotiationInfo & 0xff)
+ z[2] = 0
+ z[3] = 1
+ z = z[5:]
+ }
m.raw = x
@@ -256,6 +269,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.cipherSuites = make([]uint16, numCipherSuites)
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+ if m.cipherSuites[i] == scsvRenegotiation {
+ m.secureRenegotiation = true
+ }
}
data = data[2+cipherSuiteLen:]
if len(data) < 1 {
@@ -379,6 +395,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.signatureAndHashes[i].signature = d[1]
d = d[2:]
}
+ case extensionRenegotiationInfo + 1:
+ if length != 1 || data[0] != 0 {
+ return false
+ }
+ m.secureRenegotiation = true
}
data = data[length:]
}
@@ -387,16 +408,17 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
type serverHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- compressionMethod uint8
- nextProtoNeg bool
- nextProtos []string
- ocspStapling bool
- ticketSupported bool
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiation bool
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -414,7 +436,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
m.nextProtoNeg == m1.nextProtoNeg &&
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
- m.ticketSupported == m1.ticketSupported
+ m.ticketSupported == m1.ticketSupported &&
+ m.secureRenegotiation == m1.secureRenegotiation
}
func (m *serverHelloMsg) marshal() []byte {
@@ -441,6 +464,10 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -469,7 +496,7 @@ func (m *serverHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
- z[1] = byte(extensionNextProtoNeg)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
z[2] = byte(nextProtoLen >> 8)
z[3] = byte(nextProtoLen)
z = z[4:]
@@ -494,6 +521,13 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
+ if m.secureRenegotiation {
+ z[0] = byte(extensionRenegotiationInfo >> 8)
+ z[1] = byte(extensionRenegotiationInfo & 0xff)
+ z[2] = 0
+ z[3] = 1
+ z = z[5:]
+ }
m.raw = x
@@ -573,6 +607,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.ticketSupported = true
+ case extensionRenegotiationInfo:
+ if length != 1 || data[0] != 0 {
+ return false
+ }
+ m.secureRenegotiation = true
}
data = data[length:]
}
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -152,6 +152,7 @@ Curves:
hs.hello.random[1] = byte(t >> 16)
hs.hello.random[2] = byte(t >> 8)
hs.hello.random[3] = byte(t)
+ hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
_, err = io.ReadFull(config.rand(), hs.hello.random[4:])
if err != nil {
return false, c.sendAlert(alertInternalError)
コアとなるコードの解説
common.go
extensionRenegotiationInfo
(0xff01): これは、TLS拡張のタイプを識別するための定数です。RFC 5746で定義されている再ネゴシエーション情報拡張のIANA割り当て値(0xff01)に対応します。scsvRenegotiation
(0x00ff): これは、TLSハンドシェイクのClientHelloメッセージで、クライアントがセキュアな再ネゴシエーションをサポートしていることを示すために使用される特別なシグナリング暗号スイート値(SCSV)です。RFC 5746で定義されています。var
からconst
への変更: 既存のTLS拡張番号、楕円曲線、楕円曲線点形式の定義がvar
からconst
に変更されました。これは、これらの値が実行時に変更されない定数であることをより明確にするための、コードのクリーンアップとベストプラクティスへの準拠です。
handshake_client.go
hello.secureRenegotiation = true
: クライアントがclientHelloMsg
を構築する際に、secureRenegotiation
フィールドを常にtrue
に設定するように変更されました。これは、GoクライアントがRFC 5746に準拠したセキュアな再ネゴシエーションを常に試みることを意味します。これにより、クライアントはサーバーに対して、自身が再ネゴシエーション攻撃に対する防御メカニズムをサポートしていることを明示的に伝えます。
handshake_messages.go
このファイルは、TLSハンドシェイクメッセージの構造と、それらをバイト列に変換(マーシャリング)したり、バイト列から構造体に変換(アンマーシャリング)したりするロジックを定義しています。
-
clientHelloMsg
構造体:secureRenegotiation bool
フィールドが追加されました。これは、クライアントがセキュアな再ネゴシエーションをサポートしているかどうかを示すフラグです。equal()
メソッド:secureRenegotiation
フィールドの比較が追加され、メッセージの等価性チェックが正しく行われるようになりました。marshal()
メソッド:secureRenegotiation
がtrue
の場合、extensionRenegotiationInfo
拡張がClientHelloメッセージの拡張セクションに追加されるロジックが追加されました。この拡張は、RFC 5746の仕様に従い、長さが1バイトで、その値は0です。- 既存の拡張(
extensionNextProtoNeg
,extensionServerName
など)のエンコーディングにおいて、バイト値をマスクする& 0xff
が追加されました。これは、byte()
キャストが上位ビットを切り捨てることを明示し、コードの堅牢性を高めるためのものです。
unmarshal()
メソッド:- 受信したClientHelloメッセージの暗号スイートリストを解析する際に、
scsvRenegotiation
(0x00ff) が見つかった場合、secureRenegotiation
フィールドがtrue
に設定されます。これは、サーバーがクライアントからSCSVを受け取った場合に、クライアントがセキュアな再ネゴシエーションをサポートしていると認識するためのものです。 - 受信したClientHelloメッセージの拡張セクションを解析する際に、
extensionRenegotiationInfo
拡張が見つかり、その形式がRFC 5746の仕様(長さが1で値が0)に準拠している場合、secureRenegotiation
フィールドがtrue
に設定されます。
- 受信したClientHelloメッセージの暗号スイートリストを解析する際に、
-
serverHelloMsg
構造体:secureRenegotiation bool
フィールドが追加されました。これは、サーバーがセキュアな再ネゴシエーションをサポートしているかどうかを示すフラグです。equal()
メソッド:secureRenegotiation
フィールドの比較が追加されました。marshal()
メソッド:secureRenegotiation
がtrue
の場合、extensionRenegotiationInfo
拡張がServerHelloメッセージの拡張セクションに追加されるロジックが追加されました。unmarshal()
メソッド: 受信したServerHelloメッセージの拡張セクションを解析する際に、extensionRenegotiationInfo
拡張が見つかり、その形式がRFC 5746の仕様に準拠している場合、secureRenegotiation
フィールドがtrue
に設定されます。
handshake_server.go
hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
: サーバーがserverHelloMsg
を構築する際に、クライアントから受け取ったclientHelloMsg
のsecureRenegotiation
フィールドの値を、自身のserverHelloMsg
のsecureRenegotiation
フィールドにコピーするように変更されました。これにより、サーバーはクライアントがセキュアな再ネゴシエーションをサポートしていることを認識し、それに応じて応答します。
handshake_server_test.go
TestCipherSuiteCertPreferance
関数のリネームとCipherSuitesの変更: テスト関数の名前がTestCipherSuiteCertPreferenceECDSA
に変更され、使用されるCipherSuitesもTLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
からTLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
に変更されています。これは、テストの意図をより明確にし、より堅牢なテストケースを提供するためのものです。
testdata/
- 多数のテストデータファイルが更新されています。これらのファイルは、TLSハンドシェイクの実際のバイトストリームを記録したもので、新しい再ネゴシエーション拡張がハンドシェイクメッセージに追加されたため、その変更を反映するために更新されました。これにより、GoのTLS実装がRFC 5746に準拠したハンドシェイクを正しく生成および解析できることが保証されます。
これらの変更により、Goのcrypto/tls
パッケージは、TLS再ネゴシエーション攻撃に対する防御メカニズムであるRFC 5746をサポートし、より安全なTLS通信を提供できるようになりました。
関連リンク
- Go言語の変更リスト: https://golang.org/cl/48580043
- RFC 5746: TLS Renegotiation Indication Extension: https://tools.ietf.org/search/rfc5746
参考にした情報源リンク
- ietf.org: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFZposAhmF8nlMNhek9IJFbQTs5NAekmA9AYdnbiYnKmD2E-pIYFwnask7oUdYEp3REhEMUZ2Z24s1kDq23J12VjahSWdGaJoLc-l2AfZQ4mrSO1e4-XOMluPdr2MidZw==
- hackerone.com: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEc81WaBBn0Fg7FRyt60sWCh59UtxDPf2la9RypU0scexpNYkJzzdpCR1h9YSv7gUjb3K5qqNsvLwx_zW0fWcNatSllc3KG584SnCXjv-GxHX8R4A9jXq33gBxZcNE=
- ibm.com: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEgHRoQUTRak1IaZjdM0K6RViJlVjf0IvE-9aqe-2oIRYBGlCtLDaq0cg1TJMqIXn5Y1S8w_wrmPNombxdCk75BmgaGb5rl-mk6N7U2bgIZIWGr7wRL73dMr1wLiY0P_kUtdFLF3o4V4COXKUHQX7frWV1fnsIXCUNcA0veLOalqZKV6DuYvoey8FQdq40aO9lXg9RpeyqIdaDEjcesdzDKOVZfTSnoo4AU08Fs
- amazonaws.com: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGGtz5-H-N8Uc9zcLAUBvsLzbc1HQ587NMY5Gv2uygp2Xp4I98JQFgLvea2LvFeZvvh13QnrdRx3xc4RQ29jNxLKzeXhMRtctjCnX3s2G9CtRikpiDQqZm9rCAEY6JpmnaJpY6_sftve_lVOaynDr9JRlhNUc_u40ZtDJHfA9MmqTL6g4r5FUhVmtWFQbndAcIcD3p5qw==
- stackexchange.com: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHUMJAncPCV45aTNqW0xPXcjwUP_Ba-qwg0Z3-kHE4ftf6xuZodOikyMpn3HTNduTmfjpIRbr_C4fwicUvuSZCbNDhPknUmySLAV6YguihUTFElIneHEoqoqo5YLZTP3yoQmoA9ZE_KEUMfTnt9ch2OZxuDTKdI2_HPZuHQHbEKwmGOIZuqeNSmO3oFa8U6-eAZKbw2GcQa-sag9kS4bZUD3Cs=