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

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

コミット

commit 184e7a2bf2d091a48029f9953693a2b9f3ba3cc1
Author: Adam Langley <agl@golang.org>
Date:   Mon Oct 29 11:16:58 2012 -0400

    crypto/x509: always write validity times in UTC.
    
    RFC 5280 section 4.1.2.5.1 says so.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/6775068

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

https://github.com/golang/go/commit/184e7a2bf2d091a48029f9953693a2b9f3ba3cc1

元コミット内容

このコミットは、Go言語の crypto/x509 パッケージにおいて、X.509証明書および証明書失効リスト (CRL) の有効期間(validity)および更新時刻(ThisUpdate, NextUpdate)を常にUTC(協定世界時)で書き出すように変更するものです。コミットメッセージには「RFC 5280 section 4.1.2.5.1 says so.」と明記されており、この変更が標準仕様への準拠を目的としていることが示されています。

変更の背景

X.509証明書は、公開鍵基盤(PKI)においてエンティティの公開鍵を識別し、その鍵が特定のエンティティに属することを証明するために広く使用されています。これらの証明書には、有効期間を示す NotBefore(有効開始日時)と NotAfter(有効終了日時)というフィールドが含まれています。また、CRL(Certificate Revocation List)にも ThisUpdate(このCRLが発行された日時)と NextUpdate(次のCRLが発行される予定日時)というフィールドがあります。

これらの時刻情報をどのように表現するかは、相互運用性において非常に重要です。異なるシステムや実装が異なるタイムゾーンや時刻表現を使用すると、証明書の有効性判断やCRLの処理において不整合が生じる可能性があります。

RFC 5280は、X.509 Public Key Infrastructure (PKIX) の証明書とCRLのプロファイルに関する標準仕様です。このRFCは、証明書およびCRL内の時刻表現について明確なガイドラインを提供しています。特に、セクション4.1.2.5.1は、validity フィールド内の notBefore および notAfter の時刻がUTCで表現されるべきであることを規定しています。同様の要件は、CRLの ThisUpdate および NextUpdate フィールドにも適用されます。

このコミットは、Go言語の crypto/x509 パッケージが、これらの標準仕様に厳密に準拠していなかった点を修正し、生成される証明書やCRLがより広範なシステムとの互換性を確保できるようにするために行われました。

前提知識の解説

X.509証明書

X.509は、公開鍵証明書の標準フォーマットを定義するITU-T(国際電気通信連合電気通信標準化部門)の勧告です。PKIにおいて、エンティティ(ユーザー、サーバーなど)の公開鍵と、その鍵が属するエンティティの識別情報を結びつける役割を果たします。証明書は、信頼された第三者である認証局(CA)によってデジタル署名され、その正当性が保証されます。

X.509証明書の主要なフィールドには以下のようなものがあります。

  • バージョン: 証明書のバージョン(例: v3)。
  • シリアル番号: CAによって割り当てられる一意の番号。
  • 署名アルゴリズム: 証明書に署名するために使用されたアルゴリズム。
  • 発行者: 証明書を発行したCAの識別名。
  • 有効期間 (Validity): 証明書が有効である期間を示す NotBeforeNotAfter の日時。
  • サブジェクト: 証明書が発行されたエンティティの識別名。
  • 公開鍵情報: サブジェクトの公開鍵と、その鍵のアルゴリズム。
  • 発行者の一意の識別子 (Issuer Unique ID): (v2/v3のみ)発行者の一意の識別子。
  • サブジェクトの一意の識別子 (Subject Unique ID): (v2/v3のみ)サブジェクトの一意の識別子。
  • 拡張領域 (Extensions): (v3のみ)追加情報(例: サブジェクト代替名、鍵用途、証明書ポリシーなど)を含む。

証明書失効リスト (CRL)

CRLは、認証局(CA)によって発行されるリストで、有効期限内であるにもかかわらず、何らかの理由で失効した証明書のシリアル番号が含まれています。これにより、証明書が盗まれたり、秘密鍵が漏洩したりした場合でも、その証明書が無効であることをシステムが認識できるようになります。

CRLの主要なフィールドには以下のようなものがあります。

  • バージョン: CRLのバージョン。
  • 署名アルゴリズム: CRLに署名するために使用されたアルゴリズム。
  • 発行者: CRLを発行したCAの識別名。
  • ThisUpdate: このCRLが発行された日時。
  • NextUpdate: 次のCRLが発行される予定日時。
  • 失効した証明書のエントリ: 失効した各証明書のシリアル番号と失効日時。
  • CRL拡張領域: 追加情報を含む。

RFC 5280

RFC 5280は、「Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile」というタイトルのIETF(Internet Engineering Task Force)標準です。これは、X.509証明書とCRLの具体的なプロファイル(実装上の詳細な要件)を定義しており、インターネット上でのPKIの相互運用性を確保するために非常に重要です。

特に、RFC 5280のセクション4.1.2.5.1「Validity」には、証明書の有効期間を示す notBefore および notAfter フィールドの時刻表現に関する規定があります。このセクションでは、これらの時刻がUTC(協定世界時)で表現されるべきであることが明確に述べられています。

The notBefore and notAfter fields each indicate a time. The notBefore field indicates the first time at which the certificate is valid. The notAfter field indicates the time at which the certificate ceases to be valid.

For certificates issued after 31 December 1999, the notBefore and notAfter times MUST be expressed as UTCTime or GeneralizedTime.

UTCTime values MUST be expressed as Greenwich Mean Time (GMT), which is equivalent to UTC.

この規定は、タイムゾーンの曖昧さを排除し、異なるシステム間での時刻解釈の一貫性を保証するために不可欠です。

UTC (Coordinated Universal Time)

UTCは、国際的な時刻標準であり、地球の自転に基づくUT1(世界時)と原子時計に基づくTAI(国際原子時)を組み合わせたものです。タイムゾーンや夏時間の影響を受けないため、コンピュータシステム間で時刻情報を交換する際の基準として広く採用されています。

技術的詳細

このコミットの技術的な核心は、Go言語の time.Time 型が持つタイムゾーン情報を無視し、明示的にUTCに変換してからX.509構造体(証明書やCRL)に設定することです。

Goの time.Time 型は、時刻値とそれに付随するロケーション(タイムゾーン情報)を保持できます。通常、time.Now() で取得される時刻はローカルタイムゾーンの情報を含んでいます。しかし、X.509証明書やCRLの仕様では、時刻はUTCで表現されることが求められています。

変更前は、template.NotBeforetemplate.NotAfternowexpiry といった time.Time 型の変数が、そのまま validity 構造体やCRLのフィールドに渡されていました。これらの変数にローカルタイムゾーンの情報が含まれていた場合、生成される証明書やCRLの時刻情報がRFC 5280の要件を満たさない可能性がありました。

このコミットでは、time.Time 型の UTC() メソッドが使用されています。UTC() メソッドは、time.Time オブジェクトの時刻値を変更せずに、そのロケーション情報をUTCに設定します。これにより、元の時刻がどのタイムゾーンで表現されていても、X.509構造体に書き込まれる際には常にUTCとして解釈されるようになります。

具体的には、以下の箇所が変更されています。

  1. 証明書の有効期間 (validity): template.NotBeforetemplate.NotAftertemplate.NotBefore.UTC()template.NotAfter.UTC() に変更されました。これにより、証明書の有効開始日時と終了日時がUTCで記録されることが保証されます。

  2. CRLの更新時刻 (ThisUpdate, NextUpdate): nowexpirynow.UTC()expiry.UTC() に変更されました。これにより、CRLの発行日時と次の更新予定日時がUTCで記録されることが保証されます。

この変更により、Goの crypto/x509 パッケージによって生成される証明書およびCRLは、RFC 5280の時刻表現に関する厳格な要件に準拠し、より高い相互運用性を実現します。これは、異なるシステムやアプリケーションがこれらの証明書やCRLを正しく解釈し、時刻関連の誤動作を防ぐ上で非常に重要です。

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

変更は src/pkg/crypto/x509/x509.go ファイル内で行われています。

--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -1224,7 +1224,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
  		SerialNumber:       template.SerialNumber,
  		SignatureAlgorithm: signatureAlgorithm,
  		Issuer:             asn1.RawValue{FullBytes: asn1Issuer},
-		Validity:           validity{template.NotBefore, template.NotAfter},
+		Validity:           validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
  		Subject:            asn1.RawValue{FullBytes: asn1Subject},
  		PublicKey:          publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
  		Extensions:         extensions,
@@ -1314,8 +1314,8 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [\
  			Algorithm: oidSignatureSHA1WithRSA,
  		},
  		Issuer:              c.Subject.ToRDNSequence(),
-		ThisUpdate:          now,
-		NextUpdate:          expiry,
+		ThisUpdate:          now.UTC(),
+		NextUpdate:          expiry.UTC(),
  		RevokedCertificates: revokedCerts,
  	}

コアとなるコードの解説

CreateCertificate 関数内の変更

CreateCertificate 関数は、新しいX.509証明書を作成する役割を担っています。この関数内で、証明書の Validity フィールドが設定される箇所が変更されました。

-		Validity:           validity{template.NotBefore, template.NotAfter},
+		Validity:           validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
  • template.NotBefore: 証明書の有効開始日時を表す time.Time 型の変数。
  • template.NotAfter: 証明書の有効終了日時を表す time.Time 型の変数。

変更前は、これらの time.Time オブジェクトがそのまま validity 構造体に渡されていました。もし template.NotBeforetemplate.NotAfter がローカルタイムゾーンの情報を持っていた場合、生成される証明書の時刻はUTCではない形式でエンコードされる可能性がありました。

変更後は、template.NotBefore.UTC()template.NotAfter.UTC() が使用されています。UTC() メソッドは、time.Time オブジェクトの時刻値をUTCに変換(実際には、時刻値はそのままにロケーション情報をUTCに設定)します。これにより、証明書に書き込まれる有効期間の時刻が常にUTCとして解釈されるようになります。

CreateCRL メソッド内の変更

CreateCRL メソッドは、証明書失効リスト(CRL)を作成する役割を担っています。このメソッド内で、CRLの ThisUpdate および NextUpdate フィールドが設定される箇所が変更されました。

-		ThisUpdate:          now,
-		NextUpdate:          expiry,
+		ThisUpdate:          now.UTC(),
+		NextUpdate:          expiry.UTC(),
  • now: CRLが発行される現在の時刻を表す time.Time 型の変数。
  • expiry: 次のCRLが発行される予定時刻を表す time.Time 型の変数。

CreateCertificate 関数と同様に、変更前はこれらの time.Time オブジェクトがそのままCRLのフィールドに渡されていました。これにより、CRLの更新時刻がUTCではない形式でエンコードされる可能性がありました。

変更後は、now.UTC()expiry.UTC() が使用されています。これにより、CRLに書き込まれる ThisUpdateNextUpdate の時刻が常にUTCとして解釈されることが保証されます。

これらの変更は、Go言語の crypto/x509 パッケージが生成するX.509証明書およびCRLが、RFC 5280の厳格な時刻表現要件に準拠することを確実にするためのものです。これにより、Goで生成された証明書やCRLが、他のPKIシステムとの間でより高い相互運用性を持つようになります。

関連リンク

参考にした情報源リンク