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

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

このコミットは、Go言語の標準ライブラリであるcrypto/x509パッケージにおける、利用不可能なハッシュ関数を使用した場合のパニック(プログラムの異常終了)を修正するものです。具体的には、crypto.Hash.New()の挙動変更に対応し、ハッシュ関数が利用可能かどうかを事前にチェックすることで、安全性を向上させています。

コミット

c8e1946f33ee2cf482922ba2398086189faf53f6 Author: Adam Langley agl@golang.org Date: Thu May 3 16:39:57 2012 -0400

crypto/x509: fix panic when using unavailable hash function.

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

https://github.com/golang/go/commit/c8e1946f33ee2cf482922ba2398086189faf53f6

元コミット内容

crypto/x509: fix panic when using unavailable hash function.

crypto.Hash.New() changed to panicking when the hash function isn't
linked in, but crypto/x509 still expects it to return nil.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6175047

変更の背景

この変更の背景には、Go言語の暗号化ライブラリにおける内部的な挙動変更があります。以前のcrypto.Hash.New()関数は、指定されたハッシュ関数が利用できない(例えば、コンパイル時にリンクされていない)場合にnilを返していました。しかし、このコミットが行われる少し前に、crypto.Hash.New()の挙動が変更され、利用不可能なハッシュ関数が指定された場合にはnilを返す代わりにパニック(実行時エラーによるプログラムの強制終了)を引き起こすようになりました。

crypto/x509パッケージ内のコードは、このcrypto.Hash.New()の新しい挙動に対応しておらず、引き続きnilが返されることを期待していました。そのため、利用不可能なハッシュ関数がCertificate.CheckSignatureメソッドに渡された際に、crypto.Hash.New()がパニックを引き起こし、プログラムがクラッシュするという問題が発生していました。このコミットは、この互換性の問題を解決し、crypto/x509が新しいcrypto.Hash.New()の挙動に適切に対応できるようにするためのものです。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と暗号技術に関する基本的な知識が必要です。

  • Go言語のpanic: Go言語におけるpanicは、回復不可能なエラーが発生した際にプログラムの実行を停止させるメカニズムです。通常、プログラムの継続が不可能または意味をなさない場合に発生し、スタックトレースを出力してプログラムを終了させます。これは、他の言語における「例外」に似ていますが、Goではエラーハンドリングにerrorインターフェースを使用することが推奨されており、panicはより深刻な状況で用いられます。
  • cryptoパッケージ: Go言語の標準ライブラリには、暗号化機能を提供するcryptoパッケージ群があります。これには、ハッシュ関数(crypto/sha256, crypto/md5など)、暗号化アルゴリズム、デジタル署名などが含まれます。
  • crypto/x509パッケージ: crypto/x509パッケージは、X.509証明書とPKIX(Public Key Infrastructure X.509)標準を扱うための機能を提供します。X.509証明書は、公開鍵暗号システムにおいて、公開鍵の所有者を検証するために広く使用されています。ウェブサイトのHTTPS通信などで利用されるSSL/TLS証明書もX.509証明書の一種です。
  • ハッシュ関数 (Hash Function): ハッシュ関数は、任意の長さの入力データ(メッセージ)を受け取り、固定長の短いデータ(ハッシュ値、メッセージダイジェスト、フィンガープリントなどと呼ばれる)を出力する一方向性の関数です。暗号学的ハッシュ関数は、入力が少しでも変わると出力が大きく変わる(雪崩効果)、同じハッシュ値を持つ異なる入力を見つけることが困難である(衝突耐性)などの特性を持ち、データの完全性検証やデジタル署名に利用されます。
  • デジタル署名 (Digital Signature): デジタル署名は、電子文書の作成者の身元を証明し、文書が改ざんされていないことを保証する技術です。送信者は文書のハッシュ値を計算し、自身の秘密鍵で暗号化して署名を作成します。受信者は送信者の公開鍵で署名を復号し、文書のハッシュ値を再計算して比較することで、署名の正当性と文書の完全性を検証します。
  • crypto.Hash: crypto.Hash型は、Go言語のcryptoパッケージで定義されている列挙型(uint8のエイリアス)で、特定のハッシュアルゴリズム(例: crypto.SHA256, crypto.MD5)を表します。この型には、そのハッシュアルゴリズムが利用可能かどうかをチェックするAvailable()メソッドや、新しいハッシュ関数インスタンスを生成するNew()メソッドなどが定義されています。
  • SignatureAlgorithm: crypto/x509パッケージで定義されている列挙型で、デジタル署名に使用されるアルゴリズム(例: SHA256WithRSA, ECDSAWithSHA384など)を表します。

技術的詳細

このコミットが修正している問題は、crypto.Hash.New()関数のセマンティクス(挙動)の変更と、それに対応していなかったcrypto/x509パッケージのコードとの間の不整合に起因します。

  1. 旧来のcrypto.Hash.New()の挙動: 以前は、crypto.Hash型のNew()メソッドは、対応するハッシュアルゴリズムがシステムにリンクされていない(利用できない)場合、エラーを示すためにnilを返していました。crypto/x509パッケージのCertificate.CheckSignatureメソッドは、このnil戻り値をチェックし、ErrUnsupportedAlgorithmを返すことで、サポートされていないアルゴリズムが使用されたことを適切に処理していました。

    // 変更前 (概念的なコード)
    h := hashType.New() // hashTypeが利用不可の場合、hはnilになる
    if h == nil {
        return ErrUnsupportedAlgorithm
    }
    
  2. crypto.Hash.New()の新しい挙動: このコミットの少し前に、crypto.Hash.New()の内部実装が変更され、利用不可能なハッシュアルゴリズムに対してはnilを返す代わりにpanicを引き起こすようになりました。これは、通常、利用可能なハッシュ関数のみがNew()に渡されるべきであり、利用不可能なハッシュ関数が渡されることはプログラミングエラーであるという設計思想に基づいている可能性があります。

  3. crypto/x509の不整合: crypto/x509パッケージのCertificate.CheckSignatureメソッドは、このcrypto.Hash.New()の挙動変更を認識していませんでした。そのため、hashType.New()を呼び出した後、以前のようにnilチェックを行っていましたが、実際にはpanicが発生するため、このチェックに到達する前にプログラムがクラッシュしていました。

  4. 修正内容: このコミットでは、crypto.Hash.New()を呼び出す前に、hashType.Available()メソッドを使ってハッシュアルゴリズムが利用可能かどうかを明示的にチェックするようになりました。

    // 変更後
    if !hashType.Available() { // ハッシュ関数が利用可能か事前にチェック
        return ErrUnsupportedAlgorithm
    }
    h := hashType.New() // 利用可能であることが保証された上でNew()を呼び出す
    

    hashType.Available()は、そのハッシュアルゴリズムがGoのランタイムに登録され、利用可能である場合にtrueを返します。このチェックを先に行うことで、利用不可能なハッシュ関数が渡された場合でもpanicを回避し、代わりにErrUnsupportedAlgorithmを返すという、以前の期待されたエラーハンドリングの挙動を維持できるようになりました。これにより、crypto/x509パッケージの堅牢性が向上し、予期せぬクラッシュを防ぐことができます。

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

変更はsrc/pkg/crypto/x509/x509.goファイル内のCertificate構造体のCheckSignatureメソッドにあります。

--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -388,10 +388,10 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
 		return ErrUnsupportedAlgorithm
 	}
 
-\th := hashType.New()\n-\tif h == nil {\n+\tif !hashType.Available() {\n 		return ErrUnsupportedAlgorithm
 	}\n+\th := hashType.New()\n 
 	h.Write(signed)
 	digest := h.Sum(nil)

コアとなるコードの解説

変更されたCheckSignatureメソッドは、X.509証明書のデジタル署名を検証する役割を担っています。このメソッドは、署名アルゴリズム(algo)、署名対象のデータ(signed)、および実際の署名データ(signature)を受け取ります。

変更前のコードでは、以下のようになっていました。

h := hashType.New()
if h == nil {
    return ErrUnsupportedAlgorithm
}

ここで、hashTypeSignatureAlgorithmから導出されたcrypto.Hash型の値です。以前は、hashType.New()nilを返すことで、そのハッシュアルゴリズムが利用できないことを示していました。

変更後のコードは以下のようになっています。

if !hashType.Available() {
    return ErrUnsupportedAlgorithm
}
h := hashType.New()

この変更により、hashType.New()を呼び出す前に、hashType.Available()という新しいチェックが追加されました。

  • hashType.Available(): このメソッドは、対応するハッシュアルゴリズムがGoのランタイムで利用可能である場合にtrueを返します。利用できない場合はfalseを返します。
  • if !hashType.Available(): この条件文は、「もしハッシュアルゴリズムが利用可能でなければ」という意味になります。
  • return ErrUnsupportedAlgorithm: ハッシュアルゴリズムが利用可能でない場合、ErrUnsupportedAlgorithmエラーを返して処理を終了します。これにより、panicを回避し、呼び出し元に適切なエラーを通知できます。
  • h := hashType.New(): この行は、hashType.Available()trueを返した場合にのみ実行されます。つまり、ここでNew()が呼び出される際には、ハッシュアルゴリズムが確実に利用可能であることが保証されているため、panicが発生する可能性がなくなります。

この修正は、crypto.Hash.New()の挙動変更にcrypto/x509パッケージが適応するための重要な変更であり、Go言語の標準ライブラリの堅牢性と互換性を維持するために行われました。

関連リンク

参考にした情報源リンク