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

[インデックス 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.gosrc/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 では、ハッシュ関数の取り扱いに関する重要な変更が行われました。

  1. インポートパスのコメント変更: MD4RIPEMD160 のハッシュ関数に関するコメントが、// in package crypto/md4 から // import code.google.com/p/go.crypto/md4 のように変更されました。これは、これらのハッシュ関数がGoのメインリポジトリではなく、go.crypto サブプロジェクト(現在は golang.org/x/crypto に移行)で提供されていることを明示するためのものです。これにより、ユーザーはこれらのハッシュ関数を利用するために、追加のインポートが必要であることを理解しやすくなります。

  2. Hash.New() メソッドの振る舞い変更: 以前の Hash.New() メソッドは、要求されたハッシュ関数がバイナリにリンクされていない場合(つまり、RegisterHash で登録されていない場合)に nil を返していました。このコミットでは、この振る舞いが変更され、nil を返す代わりに panic("crypto: requested hash function is unavailable") を発生させるようになりました。 この変更の意図は、利用できないハッシュ関数が要求された場合に、プログラムが予期せぬ nil ポインタ参照エラーでクラッシュするのではなく、より明確なエラーメッセージとともに早期に失敗するようにすることです。これにより、開発者は問題をデバッグしやすくなります。

  3. 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 structtype 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 では DecryptOAEPrand パラメータ名が random に修正され、コメントもそれに合わせて更新されています。pkix.go では AttributeTypeAndValue 構造体に関するASN.1のRFCへの参照が追加されています。

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

このコミットにおけるコアとなるコードの変更箇所は以下の通りです。

  1. src/pkg/crypto/cipher/ocfb.go および src/pkg/crypto/cipher/ocfb_test.go の削除: これらのファイルは完全に削除されており、OCFBモードの実装がGoの標準ライブラリから取り除かれました。

  2. 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
    
  3. 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 パッケージにおけるハッシュ関数の利用方法とエラーハンドリングのパラダイムシフトを示しています。

  • コメントの更新: MD4RIPEMD160 のインポートパスに関するコメントが修正されました。これは、これらのハッシュ関数が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の議論内容
  • 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.gosrc/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 では、ハッシュ関数の取り扱いに関する重要な変更が行われました。

  1. インポートパスのコメント変更: MD4RIPEMD160 のハッシュ関数に関するコメントが、// in package crypto/md4 から // import code.google.com/p/go.crypto/md4 のように変更されました。これは、これらのハッシュ関数がGoのメインリポジトリではなく、go.crypto サブプロジェクト(現在は golang.org/x/crypto に移行)で提供されていることを明示するためのものです。これにより、ユーザーはこれらのハッシュ関数を利用するために、追加のインポートが必要であることを理解しやすくなります。

  2. Hash.New() メソッドの振る舞い変更: 以前の Hash.New() メソッドは、要求されたハッシュ関数がバイナリにリンクされていない場合(つまり、RegisterHash で登録されていない場合)に nil を返していました。このコミットでは、この振る舞いが変更され、nil を返す代わりに panic("crypto: requested hash function is unavailable") を発生させるようになりました。 この変更の意図は、利用できないハッシュ関数が要求された場合に、プログラムが予期せぬ nil ポインタ参照エラーでクラッシュするのではなく、より明確なエラーメッセージとともに早期に失敗するようにすることです。これにより、開発者は問題をデバッグしやすくなります。

  3. 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 structtype 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 では DecryptOAEPrand パラメータ名が random に修正され、コメントもそれに合わせて更新されています。pkix.go では AttributeTypeAndValue 構造体に関するASN.1のRFCへの参照が追加されています。

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

このコミットにおけるコアとなるコードの変更箇所は以下の通りです。

  1. src/pkg/crypto/cipher/ocfb.go および src/pkg/crypto/cipher/ocfb_test.go の削除: これらのファイルは完全に削除されており、OCFBモードの実装がGoの標準ライブラリから取り除かれました。

  2. 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
    
  3. 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 パッケージにおけるハッシュ関数の利用方法とエラーハンドリングのパラダイムシフトを示しています。

  • コメントの更新: MD4RIPEMD160 のインポートパスに関するコメントが修正されました。これは、これらのハッシュ関数が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の議論内容
  • Goの公式ドキュメントおよびソースコード
  • RFC 4880 (OpenPGP Message Format)
  • Go言語のインターフェースと埋め込みに関する一般的な情報
  • Go言語のエラーハンドリングとパニックに関する一般的な情報
  • 暗号モードに関する一般的な情報 (CBC, CFBなど)
  • ハッシュ関数に関する一般的な情報 (MD4, RIPEMD160など)
  • TLSプロトコルに関する一般的な情報
  • Goの golang.org/x/crypto プロジェクトに関する情報