[インデックス 13966] ファイルの概要
コミット
commit cca48f1a577bc5eb8363ef4ce63af6a9b30a164a
Author: David du Colombier <0intro@gmail.com>
Date: Wed Sep 26 14:47:47 2012 -0400
crypto/x509: add Plan 9 root certificate location
R=golang-dev
CC=golang-dev, rsc
https://golang.org/cl/6571056
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cca48f1a577bc5eb8363ef4ce63af6a9b30a164a
元コミット内容
crypto/x509: add Plan 9 root certificate location
R=golang-dev
CC=golang-dev, rsc
https://golang.org/cl/6571056
変更の背景
このコミットは、Go言語のcrypto/x509
パッケージにPlan 9オペレーティングシステム用のルート証明書(CA証明書)の探索パスを追加するものです。GoのプログラムがTLS/SSL通信を行う際、通信相手の証明書が信頼できるものであるかを確認するために、システムにインストールされている信頼されたルート証明書を利用します。
従来のGoのcrypto/x509
パッケージは、Linux、macOS (Darwin)、Windowsなどの主要なOS環境におけるルート証明書の探索パスをサポートしていましたが、Plan 9オペレーティングシステムには対応していませんでした。この不足により、Plan 9上で動作するGoアプリケーションがTLS/SSL通信を行う際に、システムが提供する信頼されたルート証明書を自動的に利用できず、証明書の検証に失敗する可能性がありました。
このコミットの目的は、Plan 9環境においてもGoアプリケーションがセキュアな通信を円滑に行えるよう、Plan 9の標準的なルート証明書パスである/sys/lib/tls/ca.pem
を認識させ、自動的にロードする機能を追加することにあります。これにより、Goのクロスプラットフォーム対応がさらに強化され、Plan 9ユーザーもGoのネットワーク機能をより安全に利用できるようになります。
前提知識の解説
1. X.509証明書とルート証明書
X.509は、公開鍵証明書の標準フォーマットです。インターネット上の通信において、サーバーやクライアントの身元を確認し、通信の暗号化を確立するために広く利用されています。X.509証明書は、公開鍵、所有者の情報、発行者の情報、有効期間、デジタル署名などを含みます。
ルート証明書(Root Certificate)は、認証局(CA: Certificate Authority)によって自己署名された証明書であり、信頼の鎖(Chain of Trust)の最上位に位置します。Webブラウザやオペレーティングシステムには、信頼できる主要な認証局のルート証明書があらかじめインストールされており、これらが通信相手の証明書を検証する際の信頼の起点となります。
2. TLS/SSL通信と証明書検証
TLS (Transport Layer Security) およびその前身であるSSL (Secure Sockets Layer) は、インターネット上での安全なデータ通信を可能にする暗号化プロトコルです。TLS通信では、サーバーがクライアントに自身のX.509証明書を提示し、クライアントはその証明書が信頼できる認証局によって発行されたものであるか、また改ざんされていないかなどを検証します。この検証プロセスにおいて、クライアントは自身のシステムに保存されているルート証明書を利用して、提示された証明書の信頼性を確認します。
3. Go言語のcrypto/x509
パッケージ
Go言語の標準ライブラリに含まれるcrypto/x509
パッケージは、X.509証明書の解析、生成、検証などの機能を提供します。特に、x509.SystemCertPool()
関数は、オペレーティングシステムが提供する信頼されたルート証明書のプールをロードする役割を担っています。このプールは、TLSクライアントがサーバー証明書を検証する際に使用されます。
4. ビルドタグ(Build Tags)
Go言語には「ビルドタグ」という機能があります。これは、ソースコードファイルの先頭に// +build tagname
のようなコメントを記述することで、特定の環境や条件でのみそのファイルをコンパイル対象とする仕組みです。例えば、// +build linux
と書かれたファイルはLinux環境でのみコンパイルされ、他のOSでは無視されます。これにより、OS固有のコードや機能を持つファイルを、単一のコードベース内で管理することが可能になります。
5. Plan 9オペレーティングシステム
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの概念をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現し、それらをネットワーク越しに透過的にアクセスできるという特徴を持ちます。Go言語の開発者の一部はPlan 9の開発にも携わっており、Go言語自体もPlan 9の設計思想から影響を受けている部分があります。Plan 9におけるTLS/SSL関連のファイルは、通常/sys/lib/tls/
ディレクトリに配置されます。
技術的詳細
このコミットは、Go言語のcrypto/x509
パッケージにおけるシステムルート証明書のロードロジックに、Plan 9オペレーティングシステム固有のパスを追加するものです。
具体的には、以下の2つのファイルが変更されています。
-
src/pkg/crypto/x509/root_plan9.go
(新規作成):- このファイルは、
// +build plan9
というビルドタグを持っています。これは、このファイルがPlan 9環境でのみコンパイルされることを意味します。 certFiles
という文字列スライスが定義されており、Plan 9におけるルート証明書の標準的なパスである"/sys/lib/tls/ca.pem"
が格納されています。initSystemRoots()
関数が実装されています。この関数は、certFiles
に定義されたパスを順に試行し、最初に読み込みに成功した証明書ファイルをPEM形式で読み込み、x509.CertPool
に追加します。これにより、Plan 9システムが提供する信頼されたルート証明書がGoの証明書プールにロードされます。systemVerify()
関数は、Plan 9環境では証明書のシステム検証をサポートしないため、nil, nil
を返します。これは、Goのcrypto/x509
パッケージが提供する一般的な証明書検証ロジックを使用することを意味し、OS固有の検証メカニズムには依存しないことを示唆しています。
- このファイルは、
-
src/pkg/crypto/x509/root_stub.go
(変更):- このファイルは、元々
// +build plan9 darwin,!cgo
というビルドタグを持っていました。これは、Plan 9環境、またはCgoを使用しないDarwin(macOS)環境でコンパイルされることを意味していました。 - 今回の変更で、ビルドタグから
plan9
が削除され、// +build darwin,!cgo
となりました。 - これにより、
root_stub.go
はPlan 9環境ではコンパイルされなくなり、代わりに新しく追加されたroot_plan9.go
がPlan 9固有のルート証明書ロードロジックを提供することになります。root_stub.go
は、システムルート証明書をロードできない環境(例えば、CgoなしのmacOSなど)のためのスタブ実装として機能し続けます。
- このファイルは、元々
この変更により、Goのビルドシステムは、Plan 9環境でコンパイルする際にroot_plan9.go
を選択し、他の環境では既存のOS固有のファイル(例: Linuxの場合はroot_unix.go
、Windowsの場合はroot_windows.go
など)またはroot_stub.go
を選択するようになります。
コアとなるコードの変更箇所
src/pkg/crypto/x509/root_plan9.go
(新規追加)
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build plan9
package x509
import "io/ioutil"
// Possible certificate files; stop after finding one.
var certFiles = []string{
"/sys/lib/tls/ca.pem",
}
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
func initSystemRoots() {
roots := NewCertPool()
for _, file := range certFiles {
data, err := ioutil.ReadFile(file)
if err == nil {
roots.AppendCertsFromPEM(data)
break
}
}
systemRoots = roots
}
src/pkg/crypto/x509/root_stub.go
(変更)
--- a/src/pkg/crypto/x509/root_stub.go
+++ b/src/pkg/crypto/x509/root_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build plan9 darwin,!cgo
+// +build darwin,!cgo
package x509
コアとなるコードの解説
root_plan9.go
// +build plan9
: この行はGoのビルドタグです。Goコンパイラは、このタグが存在する場合にのみ、このファイルをPlan 9オペレーティングシステム向けにビルドする際に含めます。これにより、Plan 9固有のコードが他のOSのビルドに混入するのを防ぎます。package x509
: このファイルがcrypto/x509
パッケージの一部であることを示します。import "io/ioutil"
: ファイルの読み込みに必要なioutil
パッケージをインポートしています。var certFiles = []string{"/sys/lib/tls/ca.pem"}
: Plan 9システムにおける信頼されたルート証明書ファイルが配置される可能性のあるパスを定義しています。Plan 9では、通常/sys/lib/tls/ca.pem
にCA証明書が格納されます。func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error)
: この関数は、Goのcrypto/x509
パッケージが提供する証明書検証のインターフェースの一部です。Plan 9ではOSレベルでの証明書検証メカニズムに直接フックしないため、ここでは単にnil, nil
を返しています。これは、Goの標準的な検証ロジックが適用されることを意味します。func initSystemRoots()
: この関数は、Goプログラムの起動時に一度だけ実行され、システムが提供するルート証明書をロードする役割を担います。roots := NewCertPool()
: 新しい証明書プールを作成します。このプールに信頼されたルート証明書が追加されます。for _, file := range certFiles
:certFiles
に定義された各パスをループで処理します。data, err := ioutil.ReadFile(file)
: 指定されたパスからファイルを読み込もうとします。if err == nil
: ファイルの読み込みが成功した場合、つまりそのパスに証明書ファイルが存在した場合。roots.AppendCertsFromPEM(data)
: 読み込んだファイルの内容(PEM形式の証明書データ)を証明書プールに追加します。break
: 最初の有効な証明書ファイルが見つかり、ロードされた時点でループを終了します。これは、複数のパスが定義されている場合に、最初に見つかったものだけを使用するという戦略を示しています。systemRoots = roots
: グローバル変数systemRoots
に、ロードされたルート証明書プールを設定します。このsystemRoots
が、GoのTLSクライアントが証明書検証を行う際に参照する信頼された証明書の集合となります。
root_stub.go
// +build darwin,!cgo
: 変更後のビルドタグです。元々含まれていたplan9
が削除されています。これにより、このファイルはPlan 9環境ではコンパイルされなくなり、Cgoを使用しないmacOS環境でのみコンパイルされるようになります。root_stub.go
は、システムルート証明書をロードできない環境のためのフォールバック(スタブ)実装として機能します。
この変更により、Goのビルドシステムは、Plan 9環境ではroot_plan9.go
を、Cgoを使用しないmacOS環境ではroot_stub.go
を、その他の主要なOS(Linux, Windowsなど)ではそれぞれのOS固有のルート証明書ロードロジックを持つファイルを適切に選択してコンパイルするようになります。
関連リンク
- Go言語の
crypto/x509
パッケージのドキュメント: https://pkg.go.dev/crypto/x509 - Go言語のビルドタグに関するドキュメント: https://go.dev/cmd/go/#hdr-Build_constraints
- Plan 9 from Bell Labs 公式サイト: https://9p.io/plan9/
参考にした情報源リンク
- Go言語のソースコード(特に
src/crypto/x509
ディレクトリ内のファイル) - Plan 9オペレーティングシステムのファイルシステム構造に関する一般的な知識
- X.509証明書とTLS/SSLプロトコルに関する一般的な知識
- Go言語のビルドシステムに関するドキュメント
- GitHubのコミット履歴と関連するコードレビューコメント
- Go言語のIssueトラッカーやメーリングリストでの議論(該当する場合)
ioutil.ReadFile
のGoドキュメント: https://pkg.go.dev/io/ioutil#ReadFile (Go 1.16以降はos.ReadFile
が推奨)x509.CertPool
のGoドキュメント: https://pkg.go.dev/crypto/x509#CertPoolx509.Certificate.Verify
のGoドキュメント: https://pkg.go.dev/crypto/x509#Certificate.Verifyx509.SystemCertPool
のGoドキュメント: https://pkg.go.dev/crypto/x509#SystemCertPool