[インデックス 11602] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto
パッケージにおける複数の変更をまとめたものです。特に、バグ2841で提起された問題の一部に対処することを目的としています。主な変更点としては、OpenPGP CFB (OCFB) モードの実装の削除、ハッシュ関数の利用可能性チェックとエラーハンドリングの改善、およびTLSリスナーの実装に関する内部的な変更が含まれます。
コミット
commit 005686ff9711287ac97c294cb55a014bce6fbac0
Author: Adam Langley <agl@golang.org>
Date: Fri Feb 3 15:08:53 2012 -0500
crypto/...: changes to address some of bug 2841.
This change addresses a subset of the issues raised in bug 2841.
R=rsc
CC=golang-dev
https://golang.org/cl/5629044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/005686ff9711287ac97c294cb55a014bce6fbac0
元コミット内容
crypto/...: changes to address some of bug 2841.
This change addresses a subset of the issues raised in bug 2841.
R=rsc
CC=golang-dev
https://golang.org/cl/5629044
変更の背景
このコミットの主な背景は、Go言語の crypto
パッケージにおけるセキュリティと堅牢性の向上です。コミットメッセージに明記されている「bug 2841」は、GoのIssueトラッカーにおける「crypto: various issues」というタイトルのバグ報告を指しています。このバグ報告では、crypto
パッケージ内の様々な潜在的な問題点や改善点が指摘されており、その中にはOCFBモードのセキュリティ上の懸念や、ハッシュ関数の利用可能性に関するAPIの振る舞いに関する議論が含まれていました。
特に、OpenPGP CFB (OCFB) モードは、その設計上の複雑さや、特定の状況下での脆弱性の可能性が指摘されていました。暗号モードは、ブロック暗号をより大きなデータストリームに適用するための方法ですが、その実装には細心の注意が必要です。OCFBモードは、OpenPGP標準の一部として定義されていましたが、Goの crypto
パッケージでは、より一般的で安全性が確立された他の暗号モード(例: CBC, CTR, GCM)が推奨される傾向にありました。このコミットでは、OCFBモードの削除を通じて、ライブラリの複雑性を減らし、潜在的な攻撃ベクトルを排除することを目的としています。
また、crypto/crypto.go
におけるハッシュ関数の New
メソッドの変更は、利用できないハッシュ関数が要求された場合の振る舞いを改善するためのものです。以前は nil
を返していましたが、これは呼び出し元が nil
チェックを怠るとパニックを引き起こす可能性がありました。この変更により、明示的にパニックを発生させることで、開発者が問題を早期に発見し、対処できるように促しています。
crypto/tls/tls.go
における Listener
の変更は、主に内部的なリファクタリングであり、APIの公開インターフェースには影響を与えずに、コードの整合性と保守性を向上させることを目的としています。
前提知識の解説
暗号モード (Cipher Modes)
暗号モードとは、ブロック暗号(例: AES, DES)を、ブロックサイズよりも大きなデータ(メッセージ)全体に適用するための手順を定めたものです。ブロック暗号は固定長のデータブロックを暗号化・復号化しますが、実際のアプリケーションでは通常、可変長のデータを扱う必要があります。暗号モードは、このギャップを埋める役割を果たします。
- CBC (Cipher Block Chaining): 各ブロックが前のブロックの暗号文とXORされるモード。初期ベクトル (IV) を使用し、同じ平文でも異なる暗号文を生成できるため、パターンを隠蔽するのに役立ちます。
- CFB (Cipher Feedback): ブロック暗号をストリーム暗号のように動作させるモード。前の暗号文ブロックが次の鍵ストリーム生成に使用されます。
- OCFB (OpenPGP CFB): OpenPGP標準で定義されているCFBモードの特定のバリアント。RFC 4880のセクション13.9で詳細が記述されています。このモードは、他の一般的なCFBモードとは異なる特定の「再同期ステップ」を持つことが特徴です。
ハッシュ関数 (Hash Functions)
ハッシュ関数は、任意の長さの入力データ(メッセージ)を受け取り、固定長の短い出力(ハッシュ値、メッセージダイジェスト、フィンガープリントなどと呼ばれる)を生成する一方向性の関数です。主な特性として、以下の点が挙げられます。
- 一方向性: ハッシュ値から元のメッセージを効率的に復元することは困難です。
- 衝突耐性: 異なるメッセージから同じハッシュ値が生成されること(衝突)が非常に困難です。
- 決定性: 同じ入力に対しては常に同じハッシュ値が生成されます。
暗号学的ハッシュ関数は、データの完全性検証、デジタル署名、パスワードの保存などに利用されます。Go言語の crypto
パッケージには、MD5, SHA-1, SHA-256, SHA-512などの様々なハッシュ関数が実装されています。
TLS (Transport Layer Security)
TLSは、インターネット上で安全な通信を行うためのプロトコルです。ウェブブラウジング(HTTPS)、電子メール、VoIPなど、様々なアプリケーションで利用されています。TLSは、通信の機密性、完全性、認証を提供します。
- Listener: ネットワークプログラミングにおいて、特定のネットワークアドレスとポートで着信接続を待ち受けるオブジェクトまたはインターフェース。TLSの文脈では、TLSハンドシェイクを処理し、安全な接続を確立する役割を担います。
Go言語のパッケージとインポートパス
Go言語では、コードはパッケージにまとめられ、他のパッケージからインポートして利用されます。標準ライブラリのパッケージは通常、crypto/md5
のように直接パッケージ名でインポートされます。しかし、一部のパッケージは、Goのメインリポジトリとは別に開発され、code.google.com/p/go.crypto/md4
のような外部パスで提供されることがあります。これは、Goのモジュールシステムが導入される前のGoのパッケージ管理の慣習を反映しています。
技術的詳細
OCFBモードの削除 (src/pkg/crypto/cipher/ocfb.go
, src/pkg/crypto/cipher/ocfb_test.go
)
このコミットの最も大きな変更点は、src/pkg/crypto/cipher/ocfb.go
と src/pkg/crypto/cipher/ocfb_test.go
ファイルが完全に削除されたことです。これにより、Goの標準ライブラリからOpenPGP CFB (OCFB) モードの暗号実装が取り除かれました。
OCFBモードは、OpenPGP (RFC 4880) で定義されている特定の暗号フィードバックモードです。しかし、このモードは一般的なCFBモードとは異なり、特定の「再同期ステップ」を持つなど、その複雑性から実装が難しく、潜在的な脆弱性の温床となる可能性がありました。また、Goの crypto
パッケージでは、より広く利用され、セキュリティが十分に検証された他の暗号モード(例: CBC, CTR, GCM)が提供されており、OCFBモードの必要性が薄れていました。
この削除は、ライブラリのコードベースを簡素化し、メンテナンスの負担を軽減するとともに、潜在的なセキュリティリスクを排除するための決定と考えられます。Goの設計哲学の一つに「シンプルさ」があり、あまり利用されず、かつ複雑性や潜在的リスクを伴う機能は、標準ライブラリから削除されることがあります。
ハッシュ関数のAPI変更 (src/pkg/crypto/crypto.go
)
src/pkg/crypto/crypto.go
では、ハッシュ関数の取り扱いに関する重要な変更が行われました。
-
インポートパスのコメント変更:
MD4
とRIPEMD160
のハッシュ関数に関するコメントが、// in package crypto/md4
から// import code.google.com/p/go.crypto/md4
のように変更されました。これは、これらのハッシュ関数がGoのメインリポジトリではなく、go.crypto
サブプロジェクト(現在はgolang.org/x/crypto
に移行)で提供されていることを明示するためのものです。これにより、ユーザーはこれらのハッシュ関数を利用するために、追加のインポートが必要であることを理解しやすくなります。 -
Hash.New()
メソッドの振る舞い変更: 以前のHash.New()
メソッドは、要求されたハッシュ関数がバイナリにリンクされていない場合(つまり、RegisterHash
で登録されていない場合)にnil
を返していました。このコミットでは、この振る舞いが変更され、nil
を返す代わりにpanic("crypto: requested hash function is unavailable")
を発生させるようになりました。 この変更の意図は、利用できないハッシュ関数が要求された場合に、プログラムが予期せぬnil
ポインタ参照エラーでクラッシュするのではなく、より明確なエラーメッセージとともに早期に失敗するようにすることです。これにより、開発者は問題をデバッグしやすくなります。 -
Hash.Available()
メソッドの追加: 新たにHash.Available() bool
メソッドが追加されました。このメソッドは、特定のハッシュ関数が現在のバイナリにリンクされており、利用可能であるかどうかをtrue
またはfalse
で返します。 このメソッドの追加により、開発者はHash.New()
を呼び出す前に、ハッシュ関数が利用可能かどうかを事前にチェックできるようになりました。これにより、Hash.New()
がパニックを発生させるのを回避し、より優雅なエラーハンドリングを実装することが可能になります。
TLSリスナーの内部変更 (src/pkg/crypto/tls/tls.go
)
src/pkg/crypto/tls/tls.go
では、TLSリスナーの実装に関する内部的な変更が行われました。
Listener
型の名称変更と非公開化: 公開されていたtype Listener struct
がtype listener struct
に変更され、構造体名が小文字で始まることで、パッケージ外部からは直接アクセスできない非公開(unexported)な型になりました。net.Listener
の埋め込み: 以前はlistener net.Listener
というフィールドでnet.Listener
を保持していましたが、変更後はnet.Listener
を直接埋め込む形になりました。これにより、listener
型はnet.Listener
インターフェースのメソッド(Accept()
,Close()
,Addr()
)を自動的に継承し、コードが簡潔になります。NewListener
関数の戻り値の変更:NewListener
関数の戻り値の型が*Listener
からnet.Listener
インターフェースに変更されました。これにより、NewListener
は具体的な実装型ではなく、インターフェースを返すようになり、APIの柔軟性が向上します。
これらの変更は、主に内部的なリファクタリングであり、crypto/tls
パッケージの公開APIの振る舞いを大きく変えるものではありません。目的は、コードの構造を改善し、Goのインターフェースの利用を促進することで、保守性と拡張性を高めることにあります。
その他のファイルにおけるコメントの修正
src/pkg/crypto/cipher/cbc.go
, src/pkg/crypto/des/cipher.go
, src/pkg/crypto/rsa/pkcs1v15.go
, src/pkg/crypto/rsa/rsa.go
, src/pkg/crypto/x509/pkix/pkix.go
の各ファイルでは、主にコメントの修正や追加が行われています。これらは、コードの可読性を向上させたり、特定のアルゴリズムや構造に関する参照情報を提供したりするためのものです。例えば、cbc.go
では iv
の説明がより明確になり、rsa.go
では DecryptOAEP
の rand
パラメータ名が random
に修正され、コメントもそれに合わせて更新されています。pkix.go
では AttributeTypeAndValue
構造体に関するASN.1のRFCへの参照が追加されています。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下の通りです。
-
src/pkg/crypto/cipher/ocfb.go
およびsrc/pkg/crypto/cipher/ocfb_test.go
の削除: これらのファイルは完全に削除されており、OCFBモードの実装がGoの標準ライブラリから取り除かれました。 -
src/pkg/crypto/crypto.go
の変更:--- a/src/pkg/crypto/crypto.go +++ b/src/pkg/crypto/crypto.go @@ -14,15 +14,15 @@ import ( type Hash uint const ( - MD4 Hash = 1 + iota // in package crypto/md4 - MD5 // in package crypto/md5 - SHA1 // in package crypto/sha1 - SHA224 // in package crypto/sha256 - SHA256 // in package crypto/sha256 - SHA384 // in package crypto/sha512 - SHA512 // in package crypto/sha512 + MD4 Hash = 1 + iota // import code.google.com/p/go.crypto/md4 + MD5 // import crypto/md5 + SHA1 // import crypto/sha1 + SHA224 // import crypto/sha256 + SHA256 // import crypto/sha256 + SHA384 // in package crypto/sha512 + SHA512 // in package crypto/sha512 MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA - RIPEMD160 // in package crypto/ripemd160 + RIPEMD160 // import code.google.com/p/go.crypto/ripemd160 maxHash ) @@ -50,8 +50,8 @@ func (h Hash) Size() int { var hashes = make([]func() hash.Hash, maxHash) -// New returns a new hash.Hash calculating the given hash function. If the -// hash function is not linked into the binary, New returns nil. +// New returns a new hash.Hash calculating the given hash function. New panics +// if the hash function is not linked into the binary. func (h Hash) New() hash.Hash { if h > 0 && h < maxHash { f := hashes[h] @@ -59,7 +59,12 @@ func (h Hash) New() hash.Hash { return f() } } - return nil + panic("crypto: requested hash function is unavailable") +} + +// Available reports whether the given hash function is linked into the binary. +func (h Hash) Available() bool { + return h < maxHash && hashes[h] != nil } // RegisterHash registers a function that returns a new instance of the given
-
src/pkg/crypto/tls/tls.go
の変更:--- a/src/pkg/crypto/tls/tls.go +++ b/src/pkg/crypto/tls/tls.go @@ -33,16 +33,16 @@ func Client(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config, isClient: true} } -// A Listener implements a network listener (net.Listener) for TLS connections. -type Listener struct { - listener net.Listener - config *Config +// A listener implements a network listener (net.Listener) for TLS connections. +type listener struct { + net.Listener + config *Config } // Accept waits for and returns the next incoming TLS connection. // The returned connection c is a *tls.Conn. -func (l *Listener) Accept() (c net.Conn, err error) { - c, err = l.listener.Accept() +func (l *listener) Accept() (c net.Conn, err error) { + c, err = l.Listener.Accept() if err != nil { return } @@ -50,28 +50,22 @@ func (l *Listener) Accept() (c net.Conn, err error) { return } -// Close closes the listener. -func (l *Listener) Close() error { return l.listener.Close() } - -// Addr returns the listener's network address. -func (l *Listener) Addr() net.Addr { return l.listener.Addr() } - // NewListener creates a Listener which accepts connections from an inner // Listener and wraps each connection with Server. // The configuration config must be non-nil and must have // at least one certificate. -func NewListener(listener net.Listener, config *Config) (l *Listener) { - l = new(Listener) - l.listener = listener +func NewListener(inner net.Listener, config *Config) net.Listener { + l := new(listener) + l.Listener = inner l.config = config - return + return l } // Listen creates a TLS listener accepting connections on the // given network address using net.Listen. // The configuration config must be non-nil and must have // at least one certificate. -func Listen(network, laddr string, config *Config) (*Listener, error) { +func Listen(network, laddr string, config *Config) (net.Listener, error) { if config == nil || len(config.Certificates) == 0 { return nil, errors.New("tls.Listen: no certificates in configuration") }
コアとなるコードの解説
src/pkg/crypto/crypto.go
の変更点
このファイルの変更は、Goの crypto
パッケージにおけるハッシュ関数の利用方法とエラーハンドリングのパラダイムシフトを示しています。
-
コメントの更新:
MD4
とRIPEMD160
のインポートパスに関するコメントが修正されました。これは、これらのハッシュ関数がGoの標準ライブラリのコア部分ではなく、golang.org/x/crypto
のような外部モジュールとして提供されていることを明確にするためです。これにより、ユーザーはこれらのハッシュ関数を使用するために、適切なモジュールをインポートする必要があることを認識できます。 -
Hash.New()
のパニックへの変更: 以前は、利用できないハッシュ関数がHash.New()
に渡された場合、関数はnil
を返していました。これは、呼び出し元がnil
チェックを怠ると、後続の操作でランタイムパニック(nil
ポインタ参照)を引き起こす可能性がありました。 変更後、Hash.New()
は、利用できないハッシュ関数が指定された場合にpanic("crypto: requested hash function is unavailable")
を発生させるようになりました。この変更は、Goの「失敗は早く」という哲学に沿ったものです。これにより、開発者はコンパイル時ではなく、プログラムの実行初期段階で問題を特定し、修正することができます。これは、セキュリティ関連のコードにおいては特に重要であり、予期せぬ動作を防ぐのに役立ちます。 -
Hash.Available()
の追加:Hash.New()
がパニックを発生させるようになったため、開発者がハッシュ関数が利用可能かどうかを事前に確認できるメカニズムが必要になりました。そこで、Hash.Available() bool
メソッドが追加されました。このメソッドは、特定のハッシュ関数が現在のバイナリにリンクされており、Hash.New()
を呼び出してもパニックが発生しないことを保証するために使用できます。これにより、開発者はより堅牢なコードを記述し、利用できないハッシュ関数に対するエラーを適切に処理できるようになります。
src/pkg/crypto/tls/tls.go
の変更点
このファイルの変更は、Goの crypto/tls
パッケージにおけるTLSリスナーの実装に関する内部的なリファクタリングです。
-
Listener
からlistener
への変更:Listener
構造体の名前がlistener
に変更され、小文字で始まることで、この型がパッケージの外部からは直接アクセスできない非公開(unexported)な型になりました。これは、Goの慣習に従い、内部実装の詳細を隠蔽し、公開APIをより安定させるためのものです。 -
net.Listener
の埋め込み: 以前はlistener net.Listener
というフィールドとしてnet.Listener
を保持していましたが、変更後はnet.Listener
を直接listener
構造体に埋め込む形になりました。Goの埋め込み(embedding)機能により、listener
型は自動的にnet.Listener
インターフェースのすべてのメソッド(Accept
,Close
,Addr
)を継承します。これにより、コードがより簡潔になり、l.listener.Accept()
のような冗長な記述がl.Accept()
のように直接呼び出せるようになります。また、Close()
とAddr()
メソッドは、埋め込みによって自動的に提供されるため、明示的な実装が不要になり、削除されました。 -
NewListener
およびListen
関数の戻り値の変更:NewListener
およびListen
関数の戻り値の型が、具体的な実装型である*Listener
からnet.Listener
インターフェースに変更されました。これは、Goのインターフェースの強力な利用例です。これにより、これらの関数は、net.Listener
インターフェースを満たす任意の型を返すことができ、将来的な実装の変更に対してより柔軟になります。呼び出し元は、具体的な実装の詳細に依存することなく、インターフェースを通じて操作を行うことができます。
これらの変更は、crypto/tls
パッケージの内部構造を改善し、Goの言語機能をより効果的に活用することで、コードの保守性と拡張性を高めることを目的としています。
関連リンク
- Go Issue 2841: https://github.com/golang/go/issues/2841 (このコミットが対処したバグの元の報告)
- Go CL 5629044: https://golang.org/cl/5629044 (このコミットに対応するGoのコードレビューシステム上のチェンジリスト)
- RFC 4880 - OpenPGP Message Format: https://tools.ietf.org/html/rfc4880 (OCFBモードが定義されているOpenPGPの仕様)
- Go言語の
crypto
パッケージドキュメント: https://pkg.go.dev/crypto - Go言語の
crypto/cipher
パッケージドキュメント: https://pkg.go.dev/crypto/cipher - Go言語の
crypto/tls
パッケージドキュメント: https://pkg.go.dev/crypto/tls
参考にした情報源リンク
- Go Issue 2841の議論内容
- Goの公式ドキュメントおよびソースコード
- RFC 4880 (OpenPGP Message Format)
- Go言語のインターフェースと埋め込みに関する一般的な情報
- Go言語のエラーハンドリングとパニックに関する一般的な情報
- 暗号モードに関する一般的な情報 (CBC, CFBなど)
- ハッシュ関数に関する一般的な情報 (MD4, RIPEMD160など)
- TLSプロトコルに関する一般的な情報
- Goの
golang.org/x/crypto
プロジェクトに関する情報```markdown
[インデックス 11602] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto
パッケージにおける複数の変更をまとめたものです。特に、バグ2841で提起された問題の一部に対処することを目的としています。主な変更点としては、OpenPGP CFB (OCFB) モードの実装の削除、ハッシュ関数の利用可能性チェックとエラーハンドリングの改善、およびTLSリスナーの実装に関する内部的な変更が含まれます。
コミット
commit 005686ff9711287ac97c294cb55a014bce6fbac0
Author: Adam Langley <agl@golang.org>
Date: Fri Feb 3 15:08:53 2012 -0500
crypto/...: changes to address some of bug 2841.
This change addresses a subset of the issues raised in bug 2841.
R=rsc
CC=golang-dev
https://golang.org/cl/5629044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/005686ff9711287ac97c294cb55a014bce6fbac0
元コミット内容
crypto/...: changes to address some of bug 2841.
This change addresses a subset of the issues raised in bug 2841.
R=rsc
CC=golang-dev
https://golang.org/cl/5629044
変更の背景
このコミットの主な背景は、Go言語の crypto
パッケージにおけるセキュリティと堅牢性の向上です。コミットメッセージに明記されている「bug 2841」は、GoのIssueトラッカーにおける「crypto: various issues」というタイトルのバグ報告を指しています。このバグ報告では、crypto
パッケージ内の様々な潜在的な問題点や改善点が指摘されており、その中にはOCFBモードのセキュリティ上の懸念や、ハッシュ関数の利用可能性に関するAPIの振る舞いに関する議論が含まれていました。
特に、OpenPGP CFB (OCFB) モードは、その設計上の複雑さや、特定の状況下での脆弱性の可能性が指摘されていました。暗号モードは、ブロック暗号をより大きなデータストリームに適用するための方法ですが、その実装には細心の注意が必要です。OCFBモードは、OpenPGP標準の一部として定義されていましたが、Goの crypto
パッケージでは、より一般的で安全性が確立された他の暗号モード(例: CBC, CTR, GCM)が推奨される傾向にありました。このコミットでは、OCFBモードの削除を通じて、ライブラリの複雑性を減らし、潜在的な攻撃ベクトルを排除することを目的としています。
また、crypto/crypto.go
におけるハッシュ関数の New
メソッドの変更は、利用できないハッシュ関数が要求された場合の振る舞いを改善するためのものです。以前は nil
を返していましたが、これは呼び出し元が nil
チェックを怠るとパニックを引き起こす可能性がありました。この変更により、明示的にパニックを発生させることで、開発者が問題を早期に発見し、対処できるように促しています。
crypto/tls/tls.go
における Listener
の変更は、主に内部的なリファクタリングであり、APIの公開インターフェースには影響を与えずに、コードの整合性と保守性を向上させることを目的としています。
前提知識の解説
暗号モード (Cipher Modes)
暗号モードとは、ブロック暗号(例: AES, DES)を、ブロックサイズよりも大きなデータ(メッセージ)全体に適用するための手順を定めたものです。ブロック暗号は固定長のデータブロックを暗号化・復号化しますが、実際のアプリケーションでは通常、可変長のデータを扱う必要があります。暗号モードは、このギャップを埋める役割を果たします。
- CBC (Cipher Block Chaining): 各ブロックが前のブロックの暗号文とXORされるモード。初期ベクトル (IV) を使用し、同じ平文でも異なる暗号文を生成できるため、パターンを隠蔽するのに役立ちます。
- CFB (Cipher Feedback): ブロック暗号をストリーム暗号のように動作させるモード。前の暗号文ブロックが次の鍵ストリーム生成に使用されます。
- OCFB (OpenPGP CFB): OpenPGP標準で定義されているCFBモードの特定のバリアント。RFC 4880のセクション13.9で詳細が記述されています。このモードは、他の一般的なCFBモードとは異なる特定の「再同期ステップ」を持つことが特徴です。
ハッシュ関数 (Hash Functions)
ハッシュ関数は、任意の長さの入力データ(メッセージ)を受け取り、固定長の短い出力(ハッシュ値、メッセージダイジェスト、フィンガープリントなどと呼ばれる)を生成する一方向性の関数です。主な特性として、以下の点が挙げられます。
- 一方向性: ハッシュ値から元のメッセージを効率的に復元することは困難です。
- 衝突耐性: 異なるメッセージから同じハッシュ値が生成されること(衝突)が非常に困難です。
- 決定性: 同じ入力に対しては常に同じハッシュ値が生成されます。
暗号学的ハッシュ関数は、データの完全性検証、デジタル署名、パスワードの保存などに利用されます。Go言語の crypto
パッケージには、MD5, SHA-1, SHA-256, SHA-512などの様々なハッシュ関数が実装されています。
TLS (Transport Layer Security)
TLSは、インターネット上で安全な通信を行うためのプロトコルです。ウェブブラウジング(HTTPS)、電子メール、VoIPなど、様々なアプリケーションで利用されています。TLSは、通信の機密性、完全性、認証を提供します。
- Listener: ネットワークプログラミングにおいて、特定のネットワークアドレスとポートで着信接続を待ち受けるオブジェクトまたはインターフェース。TLSの文脈では、TLSハンドシェイクを処理し、安全な接続を確立する役割を担います。
Go言語のパッケージとインポートパス
Go言語では、コードはパッケージにまとめられ、他のパッケージからインポートして利用されます。標準ライブラリのパッケージは通常、crypto/md5
のように直接パッケージ名でインポートされます。しかし、一部のパッケージは、Goのメインリポジトリとは別に開発され、code.google.com/p/go.crypto/md4
のような外部パスで提供されることがあります。これは、Goのモジュールシステムが導入される前のGoのパッケージ管理の慣習を反映しています。
技術的詳細
OCFBモードの削除 (src/pkg/crypto/cipher/ocfb.go
, src/pkg/crypto/cipher/ocfb_test.go
)
このコミットの最も大きな変更点は、src/pkg/crypto/cipher/ocfb.go
と src/pkg/crypto/cipher/ocfb_test.go
ファイルが完全に削除されたことです。これにより、Goの標準ライブラリからOpenPGP CFB (OCFB) モードの暗号実装が取り除かれました。
OCFBモードは、OpenPGP (RFC 4880) で定義されている特定の暗号フィードバックモードです。しかし、このモードは一般的なCFBモードとは異なり、特定の「再同期ステップ」を持つなど、その複雑性から実装が難しく、潜在的な脆弱性の温床となる可能性がありました。また、Goの crypto
パッケージでは、より広く利用され、セキュリティが十分に検証された他の暗号モード(例: CBC, CTR, GCM)が提供されており、OCFBモードの必要性が薄れていました。
この削除は、ライブラリのコードベースを簡素化し、メンテナンスの負担を軽減するとともに、潜在的なセキュリティリスクを排除するための決定と考えられます。Goの設計哲学の一つに「シンプルさ」があり、あまり利用されず、かつ複雑性や潜在的リスクを伴う機能は、標準ライブラリから削除されることがあります。
ハッシュ関数のAPI変更 (src/pkg/crypto/crypto.go
)
src/pkg/crypto/crypto.go
では、ハッシュ関数の取り扱いに関する重要な変更が行われました。
-
インポートパスのコメント変更:
MD4
とRIPEMD160
のハッシュ関数に関するコメントが、// in package crypto/md4
から// import code.google.com/p/go.crypto/md4
のように変更されました。これは、これらのハッシュ関数がGoのメインリポジトリではなく、go.crypto
サブプロジェクト(現在はgolang.org/x/crypto
に移行)で提供されていることを明示するためのものです。これにより、ユーザーはこれらのハッシュ関数を利用するために、追加のインポートが必要であることを理解しやすくなります。 -
Hash.New()
メソッドの振る舞い変更: 以前のHash.New()
メソッドは、要求されたハッシュ関数がバイナリにリンクされていない場合(つまり、RegisterHash
で登録されていない場合)にnil
を返していました。このコミットでは、この振る舞いが変更され、nil
を返す代わりにpanic("crypto: requested hash function is unavailable")
を発生させるようになりました。 この変更の意図は、利用できないハッシュ関数が要求された場合に、プログラムが予期せぬnil
ポインタ参照エラーでクラッシュするのではなく、より明確なエラーメッセージとともに早期に失敗するようにすることです。これにより、開発者は問題をデバッグしやすくなります。 -
Hash.Available()
メソッドの追加: 新たにHash.Available() bool
メソッドが追加されました。このメソッドは、特定のハッシュ関数が現在のバイナリにリンクされており、利用可能であるかどうかをtrue
またはfalse
で返します。 このメソッドの追加により、開発者はHash.New()
を呼び出す前に、ハッシュ関数が利用可能かどうかを事前にチェックできるようになりました。これにより、Hash.New()
がパニックを発生させるのを回避し、より優雅なエラーハンドリングを実装することが可能になります。
TLSリスナーの内部変更 (src/pkg/crypto/tls/tls.go
)
src/pkg/crypto/tls/tls.go
では、TLSリスナーの実装に関する内部的な変更が行われました。
Listener
型の名称変更と非公開化: 公開されていたtype Listener struct
がtype listener struct
に変更され、構造体名が小文字で始まることで、パッケージ外部からは直接アクセスできない非公開(unexported)な型になりました。net.Listener
の埋め込み: 以前はlistener net.Listener
というフィールドでnet.Listener
を保持していましたが、変更後はnet.Listener
を直接埋め込む形になりました。これにより、listener
型はnet.Listener
インターフェースのメソッド(Accept()
,Close()
,Addr()
)を自動的に継承し、コードが簡潔になります。NewListener
関数の戻り値の変更:NewListener
関数の戻り値の型が*Listener
からnet.Listener
インターフェースに変更されました。これにより、NewListener
は具体的な実装型ではなく、インターフェースを返すようになり、APIの柔軟性が向上します。
これらの変更は、主に内部的なリファクタリングであり、crypto/tls
パッケージの公開APIの振る舞いを大きく変えるものではありません。目的は、コードの構造を改善し、Goのインターフェースの利用を促進することで、保守性と拡張性を高めることにあります。
その他のファイルにおけるコメントの修正
src/pkg/crypto/cipher/cbc.go
, src/pkg/crypto/des/cipher.go
, src/pkg/crypto/rsa/pkcs1v15.go
, src/pkg/crypto/rsa/rsa.go
, src/pkg/crypto/x509/pkix/pkix.go
の各ファイルでは、主にコメントの修正や追加が行われています。これらは、コードの可読性を向上させたり、特定のアルゴリズムや構造に関する参照情報を提供したりするためのものです。例えば、cbc.go
では iv
の説明がより明確になり、rsa.go
では DecryptOAEP
の rand
パラメータ名が random
に修正され、コメントもそれに合わせて更新されています。pkix.go
では AttributeTypeAndValue
構造体に関するASN.1のRFCへの参照が追加されています。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下の通りです。
-
src/pkg/crypto/cipher/ocfb.go
およびsrc/pkg/crypto/cipher/ocfb_test.go
の削除: これらのファイルは完全に削除されており、OCFBモードの実装がGoの標準ライブラリから取り除かれました。 -
src/pkg/crypto/crypto.go
の変更:--- a/src/pkg/crypto/crypto.go +++ b/src/pkg/crypto/crypto.go @@ -14,15 +14,15 @@ import ( type Hash uint const ( - MD4 Hash = 1 + iota // in package crypto/md4 - MD5 // in package crypto/md5 - SHA1 // in package crypto/sha1 - SHA224 // in package crypto/sha256 - SHA256 // in package crypto/sha256 - SHA384 // in package crypto/sha512 - SHA512 // in package crypto/sha512 + MD4 Hash = 1 + iota // import code.google.com/p/go.crypto/md4 + MD5 // import crypto/md5 + SHA1 // import crypto/sha1 + SHA224 // import crypto/sha256 + SHA256 // in package crypto/sha256 + SHA384 // in package crypto/sha512 + SHA512 // in package crypto/sha512 MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA - RIPEMD160 // in package crypto/ripemd160 + RIPEMD160 // import code.google.com/p/go.crypto/ripemd160 maxHash ) @@ -50,8 +50,8 @@ func (h Hash) Size() int { var hashes = make([]func() hash.Hash, maxHash) -// New returns a new hash.Hash calculating the given hash function. If the -// hash function is not linked into the binary, New returns nil. +// New returns a new hash.Hash calculating the given hash function. New panics +// if the hash function is not linked into the binary. func (h Hash) New() hash.Hash { if h > 0 && h < maxHash { f := hashes[h] @@ -59,7 +59,12 @@ func (h Hash) New() hash.Hash { return f() } } - return nil + panic("crypto: requested hash function is unavailable") +} + +// Available reports whether the given hash function is linked into the binary. +func (h Hash) Available() bool { + return h < maxHash && hashes[h] != nil } // RegisterHash registers a function that returns a new instance of the given
-
src/pkg/crypto/tls/tls.go
の変更:--- a/src/pkg/crypto/tls/tls.go +++ b/src/pkg/crypto/tls/tls.go @@ -33,16 +33,16 @@ func Client(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config, isClient: true} } -// A Listener implements a network listener (net.Listener) for TLS connections. -type Listener struct { - listener net.Listener - config *Config +// A listener implements a network listener (net.Listener) for TLS connections. +type listener struct { + net.Listener + config *Config } // Accept waits for and returns the next incoming TLS connection. // The returned connection c is a *tls.Conn. -func (l *Listener) Accept() (c net.Conn, err error) { - c, err = l.listener.Accept() +func (l *listener) Accept() (c net.Conn, err error) { + c, err = l.Listener.Accept() if err != nil { return } @@ -50,28 +50,22 @@ func (l *Listener) Accept() (c net.Conn, err error) { return } -// Close closes the listener. -func (l *Listener) Close() error { return l.listener.Close() } - -// Addr returns the listener's network address. -func (l *Listener) Addr() net.Addr { return l.listener.Addr() } - // NewListener creates a Listener which accepts connections from an inner // Listener and wraps each connection with Server. // The configuration config must be non-nil and must have // at least one certificate. -func NewListener(listener net.Listener, config *Config) (l *Listener) { - l = new(Listener) - l.listener = listener +func NewListener(inner net.Listener, config *Config) net.Listener { + l := new(listener) + l.Listener = inner l.config = config - return + return l } // Listen creates a TLS listener accepting connections on the // given network address using net.Listen. // The configuration config must be non-nil and must have // at least one certificate. -func Listen(network, laddr string, config *Config) (*Listener, error) { +func Listen(network, laddr string, config *Config) (net.Listener, error) { if config == nil || len(config.Certificates) == 0 { return nil, errors.New("tls.Listen: no certificates in configuration") }
コアとなるコードの解説
src/pkg/crypto/crypto.go
の変更点
このファイルの変更は、Goの crypto
パッケージにおけるハッシュ関数の利用方法とエラーハンドリングのパラダイムシフトを示しています。
-
コメントの更新:
MD4
とRIPEMD160
のインポートパスに関するコメントが修正されました。これは、これらのハッシュ関数がGoの標準ライブラリのコア部分ではなく、golang.org/x/crypto
のような外部モジュールとして提供されていることを明確にするためです。これにより、ユーザーはこれらのハッシュ関数を使用するために、適切なモジュールをインポートする必要があることを認識できます。 -
Hash.New()
のパニックへの変更: 以前は、利用できないハッシュ関数がHash.New()
に渡された場合、関数はnil
を返していました。これは、呼び出し元がnil
チェックを怠ると、後続の操作でランタイムパニック(nil
ポインタ参照)を引き起こす可能性がありました。 変更後、Hash.New()
は、利用できないハッシュ関数が指定された場合にpanic("crypto: requested hash function is unavailable")
を発生させるようになりました。この変更は、Goの「失敗は早く」という哲学に沿ったものです。これにより、開発者はコンパイル時ではなく、プログラムの実行初期段階で問題を特定し、修正することができます。これは、セキュリティ関連のコードにおいては特に重要であり、予期せぬ動作を防ぐのに役立ちます。 -
Hash.Available()
の追加:Hash.New()
がパニックを発生させるようになったため、開発者がハッシュ関数が利用可能かどうかを事前に確認できるメカニズムが必要になりました。そこで、Hash.Available() bool
メソッドが追加されました。このメソッドは、特定のハッシュ関数が現在のバイナリにリンクされており、Hash.New()
を呼び出してもパニックが発生しないことを保証するために使用できます。これにより、開発者はより堅牢なコードを記述し、利用できないハッシュ関数に対するエラーを適切に処理できるようになります。
src/pkg/crypto/tls/tls.go
の変更点
このファイルの変更は、Goの crypto/tls
パッケージにおけるTLSリスナーの実装に関する内部的なリファクタリングです。
-
Listener
からlistener
への変更:Listener
構造体の名前がlistener
に変更され、小文字で始まることで、この型がパッケージの外部からは直接アクセスできない非公開(unexported)な型になりました。これは、Goの慣習に従い、内部実装の詳細を隠蔽し、公開APIをより安定させるためのものです。 -
net.Listener
の埋め込み: 以前はlistener net.Listener
というフィールドとしてnet.Listener
を保持していましたが、変更後はnet.Listener
を直接listener
構造体に埋め込む形になりました。Goの埋め込み(embedding)機能により、listener
型は自動的にnet.Listener
インターフェースのすべてのメソッド(Accept
,Close
,Addr
)を継承します。これにより、コードがより簡潔になり、l.listener.Accept()
のような冗長な記述がl.Accept()
のように直接呼び出せるようになります。また、Close()
とAddr()
メソッドは、埋め込みによって自動的に提供されるため、明示的な実装が不要になり、削除されました。 -
NewListener
およびListen
関数の戻り値の変更:NewListener
およびListen
関数の戻り値の型が、具体的な実装型である*Listener
からnet.Listener
インターフェースに変更されました。これは、Goのインターフェースの強力な利用例です。これにより、これらの関数は、net.Listener
インターフェースを満たす任意の型を返すことができ、将来的な実装の変更に対してより柔軟になります。呼び出し元は、具体的な実装の詳細に依存することなく、インターフェースを通じて操作を行うことができます。
これらの変更は、crypto/tls
パッケージの内部構造を改善し、Goの言語機能をより効果的に活用することで、コードの保守性と拡張性を高めることを目的としています。
関連リンク
- Go Issue 2841: https://github.com/golang/go/issues/2841 (このコミットが対処したバグの元の報告)
- Go CL 5629044: https://golang.org/cl/5629044 (このコミットに対応するGoのコードレビューシステム上のチェンジリスト)
- RFC 4880 - OpenPGP Message Format: https://tools.ietf.org/html/rfc4880 (OCFBモードが定義されているOpenPGPの仕様)
- Go言語の
crypto
パッケージドキュメント: https://pkg.go.dev/crypto - Go言語の
crypto/cipher
パッケージドキュメント: https://pkg.go.dev/crypto/cipher - Go言語の
crypto/tls
パッケージドキュメント: https://pkg.go.dev/crypto/tls
参考にした情報源リンク
- Go Issue 2841の議論内容
- Goの公式ドキュメントおよびソースコード
- RFC 4880 (OpenPGP Message Format)
- Go言語のインターフェースと埋め込みに関する一般的な情報
- Go言語のエラーハンドリングとパニックに関する一般的な情報
- 暗号モードに関する一般的な情報 (CBC, CFBなど)
- ハッシュ関数に関する一般的な情報 (MD4, RIPEMD160など)
- TLSプロトコルに関する一般的な情報
- Goの
golang.org/x/crypto
プロジェクトに関する情報