[インデックス 15063] ファイルの概要
このコミットは、Go言語の crypto/x509
パッケージにおけるRSA公開鍵のパース処理において、不正な(負またはゼロの)RSAパラメータが検出された場合に、より分かりやすいエラーメッセージを返すように改善するものです。具体的には、RSAモジュラス(N)や公開指数(E)が正の数でない場合に、明確なエラーを返すようになります。
コミット
commit 5c659d736241f4904eb3d513f9f585397a3ed8af
Author: Adam Langley <agl@golang.org>
Date: Thu Jan 31 12:54:37 2013 -0500
crypto/x509: test for negative RSA parameters.
Someone found software that generates negative numbers for the RSA
modulus in an X.509 certificate. Our error messages were very poor in
this case so this change improves that.
Update #4728
Return more helpful errors when RSA parameters are negative or zero.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7228072
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5c659d736241f4904eb3d513f9f585397a3ed8af
元コミット内容
crypto/x509: test for negative RSA parameters.
X.509証明書内のRSAモジュラスに負の数を生成するソフトウェアが発見されました。このケースにおけるGoの既存のエラーメッセージは非常に分かりにくかったため、この変更によって改善されます。
Issue #4728 を更新し、RSAパラメータが負またはゼロの場合に、より分かりやすいエラーを返します。
変更の背景
この変更の背景には、実際の運用環境で不正なX.509証明書が生成されるケースが発見されたことがあります。具体的には、一部のソフトウェアがRSA公開鍵のパラメータであるモジュラス(N)に負の値を設定してしまうという問題がありました。
X.509証明書は公開鍵暗号の公開鍵を配布するための標準的なフォーマットであり、その中に含まれるRSA公開鍵は、モジュラス N
と公開指数 E
の2つのパラメータで構成されます。これらのパラメータは数学的に正の整数である必要があります。しかし、特定のソフトウェアの実装ミスやバグにより、これらのパラメータが負の値やゼロとしてエンコードされてしまうことがありました。
Go言語の crypto/x509
パッケージは、X.509証明書をパースし、その中の公開鍵を検証する役割を担っています。このような不正な証明書が入力された際、Goの既存の実装では、エラーメッセージが抽象的で、何が問題なのかを特定しにくいものでした。例えば、単に「パースエラー」のような一般的なメッセージが返されるだけで、開発者が問題の原因をデバッグするのに苦労する可能性がありました。
このコミットは、このような現実世界で発生する可能性のある不正な入力に対して、Goのライブラリがより堅牢に対応し、開発者に対して具体的なエラー情報を提供することで、デバッグや問題解決を容易にすることを目的としています。これにより、Goアプリケーションが不正な証明書を処理する際のユーザーエクスペリエンスが向上します。
前提知識の解説
X.509証明書
X.509は、公開鍵証明書のフォーマットを定義するITU-Tの標準規格です。主にTLS/SSL通信において、サーバーやクライアントの身元を証明するために使用されます。X.509証明書には、公開鍵、所有者の情報、発行者の情報、有効期間、デジタル署名などが含まれます。
RSA公開鍵暗号
RSAは、最も広く使用されている公開鍵暗号アルゴリズムの一つです。RSA公開鍵は、以下の2つの主要なパラメータで構成されます。
- モジュラス (N): 2つの大きな素数
p
とq
の積N = p * q
です。RSAのセキュリティは、このN
を素因数分解することの困難性に基づいています。数学的にN
は常に正の整数でなければなりません。 - 公開指数 (E): 通常は小さな正の整数で、最も一般的な値は
65537
(0x10001) です。これもまた、数学的に正の整数でなければなりません。
RSA公開鍵は、ASN.1 (Abstract Syntax Notation One) というデータ記述言語とDER (Distinguished Encoding Rules) というエンコーディングルールを用いて、X.509証明書内にエンコードされます。ASN.1では、整数型は符号付きで表現されるため、理論的には負の値をエンコードすることも可能です。しかし、RSAの数学的定義上、モジュラスと公開指数は正の数である必要があります。
Go言語の crypto/x509
パッケージ
Go言語の標準ライブラリには、暗号化とセキュリティに関連する豊富なパッケージが含まれています。crypto/x509
パッケージは、X.509証明書のパース、検証、生成などの機能を提供します。このパッケージは、TLS/SSL通信やPKI (Public Key Infrastructure) を利用するGoアプリケーションの基盤となります。
エラーハンドリングの重要性
ソフトウェア開発において、エラーハンドリングは非常に重要です。特にセキュリティ関連のライブラリでは、不正な入力や予期せぬ状況に対して堅牢である必要があります。曖昧なエラーメッセージは、開発者が問題を特定し、修正するのを困難にし、結果としてアプリケーションの脆弱性につながる可能性もあります。このコミットのように、具体的なエラーメッセージを提供することは、ライブラリの使いやすさと信頼性を向上させる上で不可欠です。
技術的詳細
このコミットは、src/pkg/crypto/x509/x509.go
ファイル内の parsePublicKey
関数に修正を加えるものです。この関数は、X.509証明書から公開鍵情報をパースする際に呼び出されます。
RSA公開鍵のパース処理において、ASN.1でエンコードされたモジュラス N
と公開指数 E
が big.Int
型として読み込まれた後、それらの値が正の数であるかどうかが検証されます。
具体的には、以下のチェックが追加されました。
-
RSAモジュラス (N) のチェック:
if p.N.Sign() <= 0 { ... }
p.N
は*big.Int
型のRSAモジュラスを表します。Sign()
メソッドは、big.Int
の符号を返します。> 0
の場合: 正の数= 0
の場合: ゼロ< 0
の場合: 負の数 この条件p.N.Sign() <= 0
は、モジュラスがゼロまたは負の数である場合に真となります。この場合、"x509: RSA modulus is not a positive number"
というエラーメッセージを含む新しいエラーが返されます。
-
RSA公開指数 (E) のチェック:
if p.E <= 0 { ... }
p.E
はint
型のRSA公開指数を表します。この条件p.E <= 0
は、公開指数がゼロまたは負の数である場合に真となります。この場合、"x509: RSA public exponent is not a positive number"
というエラーメッセージを含む新しいエラーが返されます。
これらのチェックは、rsa.PublicKey
構造体が構築される前に実行されます。これにより、不正なパラメータを持つ公開鍵がシステム内で使用されることを防ぎ、より早期に、より具体的なエラーを報告することが可能になります。
この変更は、Goの errors
パッケージを使用して新しいエラーを作成し、それを返すというGoのエラーハンドリングの慣習に従っています。これにより、呼び出し元のコードは、返されたエラーをチェックし、適切な処理を行うことができます。
コアとなるコードの変更箇所
src/pkg/crypto/x509/x509.go
ファイルの parsePublicKey
関数内。
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -660,6 +660,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{\n return nil, err
}\n
+\t\tif p.N.Sign() <= 0 {\n+\t\t\treturn nil, errors.New("x509: RSA modulus is not a positive number")\n+\t\t}\n+\t\tif p.E <= 0 {\n+\t\t\treturn nil, errors.New("x509: RSA public exponent is not a positive number")\n+\t\t}\n+\n \t\tpub := &rsa.PublicKey{\n \t\t\tE: p.E,\n \t\t\tN: p.N,\n```
## コアとなるコードの解説
変更は `src/pkg/crypto/x509/x509.go` ファイルの `parsePublicKey` 関数内、特にRSA公開鍵のパースロジックに集中しています。
1. **`if p.N.Sign() <= 0 { ... }`**:
* `p.N` は、パースされたRSAモジュラスを表す `*big.Int` 型の変数です。
* `p.N.Sign()` は `big.Int` のメソッドで、その値の符号を返します。
* `1` は正の数
* `0` はゼロ
* `-1` は負の数
* この条件は、モジュラス `N` がゼロまたは負の値である場合に真となります。
* もし条件が真であれば、`errors.New("x509: RSA modulus is not a positive number")` を用いて新しいエラーオブジェクトが作成され、関数は `nil` (公開鍵) とこのエラーを返して終了します。これにより、不正なモジュラスを持つ公開鍵がこれ以上処理されるのを防ぎます。
2. **`if p.E <= 0 { ... }`**:
* `p.E` は、パースされたRSA公開指数を表す `int` 型の変数です。
* この条件は、公開指数 `E` がゼロまたは負の値である場合に真となります。
* もし条件が真であれば、`errors.New("x509: RSA public exponent is not a positive number")` を用いて新しいエラーオブジェクトが作成され、関数は `nil` (公開鍵) とこのエラーを返して終了します。これにより、不正な公開指数を持つ公開鍵がこれ以上処理されるのを防ぎます。
これらのチェックは、`rsa.PublicKey` 構造体のインスタンスが実際に作成される直前に追加されています。これにより、Goの `crypto/x509` パッケージは、X.509証明書内のRSA公開鍵パラメータの妥当性をより厳密に検証し、不正なデータに対してより具体的で役立つエラーメッセージを提供するようになります。これは、ライブラリの堅牢性とデバッグのしやすさを向上させる重要な改善です。
## 関連リンク
* **GitHubコミットページ**: [https://github.com/golang/go/commit/5c659d736241f4904eb3d513f9f585397a3ed8af](https://github.com/golang/go/commit/5c659d736241f4904eb3d513f9f585397a3ed8af)
* **Go Code Review (CL)**: [https://golang.org/cl/7228072](https://golang.org/cl/7228072)
* **Go Issue 4728**: [https://go.dev/issue/4728](https://go.dev/issue/4728) (このコミットで更新されたIssue)
## 参考にした情報源リンク
* **X.509**: [https://en.wikipedia.org/wiki/X.509](https://en.wikipedia.org/wiki/X.509)
* **RSA (cryptosystem)**: [https://en.wikipedia.org/wiki/RSA_(cryptosystem)](https://en.wikipedia.org/wiki/RSA_(cryptosystem))
* **Go言語 `crypto/x509` パッケージドキュメント**: [https://pkg.go.dev/crypto/x509](https://pkg.go.dev/crypto/x509)
* **Go言語 `math/big` パッケージドキュメント (big.Int.Sign())**: [https://pkg.go.dev/math/big#Int.Sign](https://pkg.go.dev/math/big#Int.Sign)
* **Go言語 `errors` パッケージドキュメント**: [https://pkg.go.dev/errors](https://pkg.go.dev/errors)
* **ASN.1**: [https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One)
* **DER**: [https://en.wikipedia.org/wiki/X.690#DER_encoding](https://en.wikipedia.org/wiki/X.690#DER_encoding)