Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18465] ファイルの概要

このコミットは、Go言語の crypto/subtle パッケージ内の ConstantTimeCompare 関数に、入力スライスの長さが異なる場合にパニックを引き起こすチェックを追加するものです。これにより、この関数の誤用による潜在的なタイミング攻撃のリスクを排除し、セキュリティを強化します。

コミット

commit 384f4380e8a4fee35ac5ba8449b9fd5cf0865069
Author: Adam Langley <agl@golang.org>
Date:   Wed Feb 12 11:58:48 2014 -0500

    crypto/subtle: panic if slices of different lengths are passed to ConstantTimeCompare.
    
    ConstantTimeCompare has always been documented to take equal length
    slices but perhaps this is too subtle, even for 'subtle'.
    
    Fixes #7304.
    
    LGTM=hanwen, bradfitz
    R=golang-codereviews, hanwen, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/62190043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/384f4380e8a4fee35ac5ba8449b9fd5cf0865069

元コミット内容

crypto/subtle: ConstantTimeCompare に異なる長さのスライスが渡された場合にパニックを起こすように変更。

ConstantTimeCompare は常に同じ長さのスライスを受け取るようにドキュメント化されていましたが、これは「subtle」というパッケージ名に反して、あまりにも「subtle(微妙)」すぎたのかもしれません。

Fixes #7304.

LGTM=hanwen, bradfitz R=golang-codereviews, hanwen, bradfitz CC=golang-codereviews https://golang.org/cl/62190043

変更の背景

この変更の背景には、暗号学的比較関数におけるセキュリティ上の重要な考慮事項があります。crypto/subtle パッケージは、サイドチャネル攻撃、特にタイミング攻撃を防ぐための関数を提供します。ConstantTimeCompare 関数は、2つのバイトスライスが等しいかどうかを、その内容に依存しない一定の時間で比較することを保証します。これにより、攻撃者が比較にかかる時間を測定することで、秘密情報(例えばパスワードや暗号鍵)に関する情報を推測することを防ぎます。

しかし、この関数は「常に同じ長さのスライスを受け取る」という前提で設計され、ドキュメントにもそのように記載されていました。もし異なる長さのスライスが渡された場合、関数の内部動作がスライスの長さに依存してしまい、比較にかかる時間が変化する可能性があります。例えば、len(x)len(y) が異なる場合、ループの回数が min(len(x), len(y)) になるか、あるいは何らかの形で長さの差が処理時間に影響を与える可能性があります。このような挙動は、タイミング攻撃の新たな経路を開くことになりかねません。

コミットメッセージにある Fixes #7304 は、この問題がGoのIssueトラッカーで報告されたことを示しています。Issue #7304では、ConstantTimeCompare が異なる長さのスライスに対してどのように振る舞うか、そしてそれがセキュリティ上の懸念を引き起こす可能性が議論されたと考えられます。開発者は、ドキュメントに記載されているにもかかわらず、誤って異なる長さのスライスを渡してしまう可能性を考慮し、より堅牢な防御策として、実行時に明示的にパニックを引き起こすように変更することを決定しました。これにより、開発者が意図しない形でセキュリティ上の脆弱性を生み出すことを防ぎます。

前提知識の解説

1. タイミング攻撃 (Timing Attack)

タイミング攻撃は、コンピュータシステムの操作にかかる時間を測定することで、秘密情報(暗号鍵、パスワードなど)を推測しようとするサイドチャネル攻撃の一種です。例えば、パスワードの比較処理において、正しい文字が入力されるたびに処理時間がわずかに長くなるような実装になっている場合、攻撃者は総当たり攻撃を行う際に、各文字の正誤を処理時間の差から判断し、効率的にパスワードを特定できてしまう可能性があります。

2. 定数時間操作 (Constant-Time Operation)

定数時間操作とは、その操作にかかる時間が入力データの内容や秘密情報に依存せず、常に一定であるか、あるいは入力データの公開された属性(例えば、比較対象の文字列の長さなど)のみに依存することを保証する操作です。暗号学的アルゴリズムや秘密情報の比較処理においては、タイミング攻撃を防ぐために定数時間操作が必須とされます。

3. crypto/subtle パッケージ

Go言語の標準ライブラリ crypto/subtle パッケージは、暗号学的プリミティブを実装する際に発生しうるサイドチャネル攻撃(特にタイミング攻撃)を防ぐための低レベルなユーティリティ関数を提供します。このパッケージの関数は、入力データの内容に依存しない一定の時間で処理を完了するように慎重に実装されています。例えば、ConstantTimeCompare は2つのバイトスライスを比較する際に、バイトが一致するかどうかにかかわらず、常に同じ数の操作を実行するように設計されています。

4. panic とは

Go言語における panic は、回復不能なエラーが発生した際にプログラムの実行を停止させるメカニズムです。通常、プログラムが続行できないような深刻なエラー(例: nilポインタのデリファレンス、配列の範囲外アクセス)が発生した場合に用いられます。panic が発生すると、現在のゴルーチンは実行を停止し、遅延関数(defer)が実行され、その後呼び出しスタックを遡ってパニックが伝播します。もしどこでも recover されなければ、プログラム全体が終了します。このコミットでは、ConstantTimeCompare の契約違反(異なる長さのスライスが渡されること)を「回復不能なエラー」とみなし、早期に問題を検出してプログラムを停止させるために panic が選択されました。これは、誤った入力がセキュリティ上の脆弱性につながる可能性を考慮した、厳格な設計判断です。

技術的詳細

ConstantTimeCompare 関数は、2つのバイトスライス xy を受け取り、それらが等しい場合に 1 を、異なる場合に 0 を返します。この関数の核心は、比較処理が入力データの「内容」に依存しない一定の時間で完了することです。これは、例えば bytes.Equal のような通常の比較関数が、不一致が見つかった時点で早期に終了する可能性がある(つまり、比較にかかる時間が不一致の位置に依存する)のとは対照的です。

このコミット以前の ConstantTimeCompare の実装は、内部的にループを使ってスライスを比較していました。そのループは len(x) または len(y) のいずれか短い方に合わせて実行されるか、あるいは何らかの形で両方の長さに依存する形で動作していました。ドキュメントでは xy が同じ長さであることを前提としていましたが、コードレベルでの明示的なチェックはありませんでした。

今回の変更は、この前提が破られた場合に何が起こるかを明確にするものです。もし len(x) != len(y) であった場合、たとえ内部の比較ループが定数時間で動作するように設計されていても、ループの回数自体が入力スライスの長さに依存することになります。例えば、len(x) = 10len(y) = 5 の場合と、len(x) = 5len(y) = 10 の場合では、処理時間が異なる可能性があります。これは、タイミング攻撃の新たなベクトルとなり得ます。

このコミットでは、関数が実行される前に len(x) != len(y) のチェックを追加し、この条件が真であれば即座に panic を発生させます。これにより、以下の効果が得られます。

  1. セキュリティの強化: 異なる長さのスライスが渡された場合に、タイミング攻撃の可能性を完全に排除します。このような誤用は、開発者が意図せずセキュリティ上の脆弱性を導入する原因となり得ます。
  2. 早期エラー検出: ConstantTimeCompare の契約(同じ長さのスライスを受け取る)が破られたことを、実行時に即座に開発者に通知します。これにより、デバッグが容易になり、本番環境での潜在的な問題を未然に防ぐことができます。
  3. 明確な契約違反: panic を使用することで、この条件が「回復不能なエラー」であり、プログラムの続行が不適切であることを明確に示します。これは、単にエラーを返すよりも強いシグナルとなります。

この変更は、crypto/subtle パッケージの目的である「微妙な(subtle)セキュリティ上の問題を扱う」という性質をより堅牢にするための、重要な改善と言えます。

コアとなるコードの変更箇所

--- a/src/pkg/crypto/subtle/constant_time.go
+++ b/src/pkg/crypto/subtle/constant_time.go
@@ -10,6 +10,10 @@ package subtle
 // and y, have equal contents. The time taken is a function of the length of
 // the slices and is independent of the contents.
 func ConstantTimeCompare(x, y []byte) int {
+\tif len(x) != len(y) {\n+\t\tpanic("subtle: slices have different lengths")\n+\t}\n+\n 	var v byte
 
 	for i := 0; i < len(x); i++ {

コアとなるコードの解説

変更は ConstantTimeCompare 関数の冒頭に4行追加された部分です。

func ConstantTimeCompare(x, y []byte) int {
	if len(x) != len(y) { // ここでxとyの長さが異なるかをチェック
		panic("subtle: slices have different lengths") // 異なる場合はパニックを発生させる
	}

	var v byte

	for i := 0; i < len(x); i++ {
		// ... 既存の比較ロジック ...
	}
	// ...
}
  1. if len(x) != len(y) { ... }: この行は、入力として渡された2つのバイトスライス xy の長さが等しいかどうかをチェックしています。len() はスライスの要素数を返す組み込み関数です。

  2. panic("subtle: slices have different lengths"): もし len(x)len(y) が異なる場合(つまり、if 文の条件が真の場合)、この行が実行されます。panic() はGoの組み込み関数で、引数として渡された文字列をパニックメッセージとしてプログラムの実行を停止させます。 このパニックメッセージ "subtle: slices have different lengths" は、crypto/subtle パッケージ内で発生したエラーであり、具体的に「スライスの長さが異なる」という問題を示しています。

この変更により、ConstantTimeCompare 関数は、その設計上の前提条件(入力スライスが同じ長さであること)が満たされない場合に、実行時エラーとして明確に問題を報告するようになりました。これにより、開発者は誤った使い方をしていることに気づき、修正することができます。これは、セキュリティ上の脆弱性を未然に防ぐための、非常に重要な防御的プログラミングの実践です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント: crypto/subtle パッケージ
  • タイミング攻撃に関する一般的な情報源 (例: Wikipedia, OWASP)
  • Go言語のIssueトラッカー (Issue #7304 の詳細)
  • Go言語のコードレビューシステム (CL 62190043 の詳細)
  • Go言語の panicrecover に関するドキュメント
  • Go言語の len() 組み込み関数に関するドキュメント
  • Go言語の bytes.Equal 関数に関するドキュメント (比較対象として)# [インデックス 18465] ファイルの概要

このコミットは、Go言語の crypto/subtle パッケージ内の ConstantTimeCompare 関数に、入力スライスの長さが異なる場合にパニックを引き起こすチェックを追加するものです。これにより、この関数の誤用による潜在的なタイミング攻撃のリスクを排除し、セキュリティを強化します。

コミット

commit 384f4380e8a4fee35ac5ba8449b9fd5cf0865069
Author: Adam Langley <agl@golang.org>
Date:   Wed Feb 12 11:58:48 2014 -0500

    crypto/subtle: panic if slices of different lengths are passed to ConstantTimeCompare.
    
    ConstantTimeCompare has always been documented to take equal length
    slices but perhaps this is too subtle, even for 'subtle'.
    
    Fixes #7304.
    
    LGTM=hanwen, bradfitz
    R=golang-codereviews, hanwen, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/62190043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/384f4380e8a4fee35ac5ba8449b9fd5cf0865069

元コミット内容

crypto/subtle: ConstantTimeCompare に異なる長さのスライスが渡された場合にパニックを起こすように変更。

ConstantTimeCompare は常に同じ長さのスライスを受け取るようにドキュメント化されていましたが、これは「subtle」というパッケージ名に反して、あまりにも「subtle(微妙)」すぎたのかもしれません。

Fixes #7304.

LGTM=hanwen, bradfitz R=golang-codereviews, hanwen, bradfitz CC=golang-codereviews https://golang.org/cl/62190043

変更の背景

この変更の背景には、暗号学的比較関数におけるセキュリティ上の重要な考慮事項があります。crypto/subtle パッケージは、サイドチャネル攻撃、特にタイミング攻撃を防ぐための関数を提供します。ConstantTimeCompare 関数は、2つのバイトスライスが等しいかどうかを、その内容に依存しない一定の時間で比較することを保証します。これにより、攻撃者が比較にかかる時間を測定することで、秘密情報(例えばパスワードや暗号鍵)に関する情報を推測することを防ぎます。

しかし、この関数は「常に同じ長さのスライスを受け取る」という前提で設計され、ドキュメントにもそのように記載されていました。もし異なる長さのスライスが渡された場合、関数の内部動作がスライスの長さに依存してしまい、比較にかかる時間が変化する可能性があります。例えば、len(x)len(y) が異なる場合、ループの回数が min(len(x), len(y)) になるか、あるいは何らかの形で長さの差が処理時間に影響を与える可能性があります。このような挙動は、タイミング攻撃の新たな経路を開くことになりかねません。

コミットメッセージにある Fixes #7304 は、この問題がGoのIssueトラッカーで報告されたことを示しています。Issue #7304では、ConstantTimeCompare が異なる長さのスライスに対してどのように振る舞うか、そしてそれがセキュリティ上の懸念を引き起こす可能性が議論されたと考えられます。開発者は、ドキュメントに記載されているにもかかわらず、誤って異なる長さのスライスを渡してしまう可能性を考慮し、より堅牢な防御策として、実行時に明示的にパニックを引き起こすように変更することを決定しました。これにより、開発者が意図しない形でセキュリティ上の脆弱性を生み出すことを防ぎます。

前提知識の解説

1. タイミング攻撃 (Timing Attack)

タイミング攻撃は、コンピュータシステムの操作にかかる時間を測定することで、秘密情報(暗号鍵、パスワードなど)を推測しようとするサイドチャネル攻撃の一種です。例えば、パスワードの比較処理において、正しい文字が入力されるたびに処理時間がわずかに長くなるような実装になっている場合、攻撃者は総当たり攻撃を行う際に、各文字の正誤を処理時間の差から判断し、効率的にパスワードを特定できてしまう可能性があります。

2. 定数時間操作 (Constant-Time Operation)

定数時間操作とは、その操作にかかる時間が入力データの内容や秘密情報に依存せず、常に一定であるか、あるいは入力データの公開された属性(例えば、比較対象の文字列の長さなど)のみに依存することを保証する操作です。暗号学的アルゴリズムや秘密情報の比較処理においては、タイミング攻撃を防ぐために定数時間操作が必須とされます。

3. crypto/subtle パッケージ

Go言語の標準ライブラリ crypto/subtle パッケージは、暗号学的プリミティブを実装する際に発生しうるサイドチャネル攻撃(特にタイミング攻撃)を防ぐための低レベルなユーティリティ関数を提供します。このパッケージの関数は、入力データの内容に依存しない一定の時間で処理を完了するように慎重に実装されています。例えば、ConstantTimeCompare は2つのバイトスライスを比較する際に、バイトが一致するかどうかにかかわらず、常に同じ数の操作を実行するように設計されています。

4. panic とは

Go言語における panic は、回復不能なエラーが発生した際にプログラムの実行を停止させるメカニズムです。通常、プログラムが続行できないような深刻なエラー(例: nilポインタのデリファレンス、配列の範囲外アクセス)が発生した場合に用いられます。panic が発生すると、現在のゴルーチンは実行を停止し、遅延関数(defer)が実行され、その後呼び出しスタックを遡ってパニックが伝播します。もしどこでも recover されなければ、プログラム全体が終了します。このコミットでは、ConstantTimeCompare の契約違反(異なる長さのスライスが渡されること)を「回復不能なエラー」とみなし、早期に問題を検出してプログラムを停止させるために panic が選択されました。これは、誤った入力がセキュリティ上の脆弱性につながる可能性を考慮した、厳格な設計判断です。

技術的詳細

ConstantTimeCompare 関数は、2つのバイトスライス xy を受け取り、それらが等しい場合に 1 を、異なる場合に 0 を返します。この関数の核心は、比較処理が入力データの「内容」に依存しない一定の時間で完了することです。これは、例えば bytes.Equal のような通常の比較関数が、不一致が見つかった時点で早期に終了する可能性がある(つまり、比較にかかる時間が不一致の位置に依存する)のとは対照的です。

このコミット以前の ConstantTimeCompare の実装は、内部的にループを使ってスライスを比較していました。そのループは len(x) または len(y) のいずれか短い方に合わせて実行されるか、あるいは何らかの形で両方の長さに依存する形で動作していました。ドキュメントでは xy が同じ長さであることを前提としていましたが、コードレベルでの明示的なチェックはありませんでした。

今回の変更は、この前提が破られた場合に何が起こるかを明確にするものです。もし len(x) != len(y) であった場合、たとえ内部の比較ループが定数時間で動作するように設計されていても、ループの回数自体が入力スライスの長さに依存することになります。例えば、len(x) = 10len(y) = 5 の場合と、len(x) = 5len(y) = 10 の場合では、処理時間が異なる可能性があります。これは、タイミング攻撃の新たなベクトルとなり得ます。

このコミットでは、関数が実行される前に len(x) != len(y) のチェックを追加し、この条件が真であれば即座に panic を発生させます。これにより、以下の効果が得られます。

  1. セキュリティの強化: 異なる長さのスライスが渡された場合に、タイミング攻撃の可能性を完全に排除します。このような誤用は、開発者が意図せずセキュリティ上の脆弱性を導入する原因となり得ます。
  2. 早期エラー検出: ConstantTimeCompare の契約(同じ長さのスライスを受け取る)が破られたことを、実行時に即座に開発者に通知します。これにより、デバッグが容易になり、本番環境での潜在的な問題を未然に防ぐことができます。
  3. 明確な契約違反: panic を使用することで、この条件が「回復不能なエラー」であり、プログラムの続行が不適切であることを明確に示します。これは、単にエラーを返すよりも強いシグナルとなります。

この変更は、crypto/subtle パッケージの目的である「微妙な(subtle)セキュリティ上の問題を扱う」という性質をより堅牢にするための、重要な改善と言えます。

コアとなるコードの変更箇所

--- a/src/pkg/crypto/subtle/constant_time.go
+++ b/src/pkg/crypto/subtle/constant_time.go
@@ -10,6 +10,10 @@ package subtle
 // and y, have equal contents. The time taken is a function of the length of
 // the slices and is independent of the contents.
 func ConstantTimeCompare(x, y []byte) int {
+\tif len(x) != len(y) {\n+\t\tpanic("subtle: slices have different lengths")\n+\t}\n+\n 	var v byte
 
 	for i := 0; i < len(x); i++ {\n```

## コアとなるコードの解説

変更は `ConstantTimeCompare` 関数の冒頭に4行追加された部分です。

```go
func ConstantTimeCompare(x, y []byte) int {
	if len(x) != len(y) { // ここでxとyの長さが異なるかをチェック
		panic("subtle: slices have different lengths") // 異なる場合はパニックを発生させる
	}

	var v byte

	for i := 0; i < len(x); i++ {
		// ... 既存の比較ロジック ...
	}
	// ...
}
  1. if len(x) != len(y) { ... }: この行は、入力として渡された2つのバイトスライス xy の長さが等しいかどうかをチェックしています。len() はスライスの要素数を返す組み込み関数です。

  2. panic("subtle: slices have different lengths"): もし len(x)len(y) が異なる場合(つまり、if 文の条件が真の場合)、この行が実行されます。panic() はGoの組み込み関数で、引数として渡された文字列をパニックメッセージとしてプログラムの実行を停止させます。 このパニックメッセージ "subtle: slices have different lengths" は、crypto/subtle パッケージ内で発生したエラーであり、具体的に「スライスの長さが異なる」という問題を示しています。

この変更により、ConstantTimeCompare 関数は、その設計上の前提条件(入力スライスが同じ長さであること)が満たされない場合に、実行時エラーとして明確に問題を報告するようになりました。これにより、開発者は誤った使い方をしていることに気づき、修正することができます。これは、セキュリティ上の脆弱性を未然に防ぐための、非常に重要な防御的プログラミングの実践です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント: crypto/subtle パッケージ
  • タイミング攻撃に関する一般的な情報源 (例: Wikipedia, OWASP)
  • Go言語のIssueトラッカー (Issue #7304 の詳細)
  • Go言語のコードレビューシステム (CL 62190043 の詳細)
  • Go言語の panicrecover に関するドキュメント
  • Go言語の len() 組み込み関数に関するドキュメント
  • Go言語の bytes.Equal 関数に関するドキュメント (比較対象として)