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

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

このコミットは、Go言語の encoding/asn1 パッケージにおける UTCTime の解析ロジックを修正するものです。特に、2桁の年表記を持つ UTCTime が2000年以前の日付(例: 1950年代)を正しく解釈できるように、曖昧性解消のルールを適用しています。

コミット

commit 6aed6130309c5567015069599712671a99444fd1
Author: Adam Langley <agl@golang.org>
Date:   Mon Mar 5 11:31:24 2012 -0500

    encoding/asn1: handle UTCTime before the year 2000
    
    UTCTime only has a two digit date field and year values from 50 should
    be 1950, not 2050.
    
    R=golang-dev, r, rsc
    CC=golang-dev
    https://golang.org/cl/5729063

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

https://github.com/golang/go/commit/6aed6130309c5567015069599712671a99444fd1

元コミット内容

encoding/asn1: handle UTCTime before the year 2000

UTCTime は2桁の年フィールドしか持たないため、年が 50 から始まる値は 2050 ではなく 1950 と解釈されるべきである。

変更の背景

ASN.1 (Abstract Syntax Notation One) で定義される UTCTime 型は、年を2桁で表現します。例えば、YYMMDDhhmmssZ の形式です。この2桁の年表記は、特に2000年問題(Y2K問題)に関連して、年が19xx年代なのか20xx年代なのかを判断する際に曖昧さを生じさせます。

RFC 5280 (Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile) のセクション 4.1.2.5.1 では、UTCTime の年解釈について明確なルールが定められています。具体的には、2桁の年が 50 から 99 の範囲であれば 19YY と解釈し、00 から 49 の範囲であれば 20YY と解釈するというものです。

このコミット以前のGoの encoding/asn1 パッケージでは、このルールが正しく適用されておらず、例えば 50 という年が 2050 と誤って解釈される可能性がありました。これにより、特に古いX.509証明書など、UTCTime を使用しているシステムとの相互運用性に問題が生じる可能性がありました。このコミットは、この曖昧さを解消し、RFC 5280の規定に準拠することで、UTCTime の正しい解析を保証することを目的としています。

前提知識の解説

ASN.1 (Abstract Syntax Notation One)

ASN.1は、データ構造を記述するための標準的な記法であり、通信プロトコルやデータストレージにおいて、異なるシステム間でデータを交換する際に使用されます。ASN.1は、データの型(整数、文字列、日付など)や構造(シーケンス、セットなど)をプラットフォーム非依存な形で定義することを可能にします。

UTCTime

UTCTime は、ASN.1で定義される日付と時刻のデータ型の一つです。その特徴は、年が2桁で表現される点にあります。一般的な形式は YYMMDDhhmmssZ または YYMMDDhhmmss+hhmm のようになります。

  • YY: 年の下2桁
  • MM: 月
  • DD: 日
  • hh: 時
  • mm: 分
  • ss: 秒 (オプション)
  • Z: UTC (Zulu time) を示す。または +hhmm / -hhmm でタイムゾーンオフセットを示す。

RFC 5280

RFC 5280は、X.509公開鍵証明書と証明書失効リスト (CRL) のプロファイルを定義するIETF標準です。公開鍵基盤 (PKI) における証明書の構造、フィールド、およびそれらの解釈方法について詳細に規定しています。このRFCは、UTCTime の年解釈に関する曖昧さを解消するための重要なルールを含んでいます。

2桁の年問題 (Y2K+50問題)

2桁の年表記は、特に2000年を境に問題を引き起こしました。99 の次は 00 となるため、00 が1900年なのか2000年なのか、あるいはそれ以降の年なのかを判断する必要がありました。UTCTime の文脈では、RFC 5280によって、50 から 9919YY00 から 4920YY と解釈するというルールが確立されました。これは、UTCTime が2049年までの日付を表現するために設計されたためです。このルールは、しばしば「Y2K+50問題」または「スライディングウィンドウ」アプローチとして知られています。

技術的詳細

Go言語の time パッケージの time.Parse 関数は、指定されたレイアウト文字列に基づいて日付/時刻文字列を解析します。UTCTime の解析においては、"0601021504Z0700" (秒なし) と "060102150405Z0700" (秒あり) の2つのレイアウトが使用されます。ここで 06 は2桁の年を表します。

このコミットの核心は、time.Parse が2桁の年を解析した結果、得られた time.Time オブジェクトの年が 2050 以上である場合に、その年から100年を減算するというロジックを追加することです。これにより、例えば 502050 と解析された場合、1950 に修正されます。これは、RFC 5280の UTCTime の年解釈ルール(2桁の年が 50 から 99 の範囲であれば 19YY と解釈する)を実装したものです。

UTCTime は、RFC 5280の規定により、2050年より前の時刻のみをエンコードするように設計されています。したがって、解析された年が2050年以降である場合、それは2桁の年が 00 から 49 の範囲で 20YY と解釈された結果ではなく、50 から 99 の範囲で 19YY と解釈されるべきであったものが誤って 20YY と解釈されたケースであると判断できます。この修正により、UTCTime の解析がRFC 5280に完全に準拠するようになります。

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

src/pkg/encoding/asn1/asn1.go ファイルの parseUTCTime 関数が変更されています。

--- a/src/pkg/encoding/asn1/asn1.go
+++ b/src/pkg/encoding/asn1/asn1.go
@@ -250,10 +250,14 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)\n func parseUTCTime(bytes []byte) (ret time.Time, err error) {\n  	s := string(bytes)\n  	ret, err = time.Parse("0601021504Z0700", s)\n- 	if err == nil {\n- 		return\n+ 	if err != nil {\n+ 		ret, err = time.Parse("060102150405Z0700", s)\n  	}\n- 	ret, err = time.Parse("060102150405Z0700", s)\n+ 	if err == nil && ret.Year() >= 2050 {\n+ 		// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1\n+ 		ret = ret.AddDate(-100, 0, 0)\n+ 	}\n+\n  	return\n  }

コアとなるコードの解説

変更された parseUTCTime 関数は以下のロジックで動作します。

  1. 入力バイトスライス bytes を文字列 s に変換します。
  2. まず、秒を含まない形式 "0601021504Z0700"s を解析しようと試みます。
  3. もし最初の解析でエラーが発生した場合(つまり、秒なし形式では解析できなかった場合)、次に秒を含む形式 "060102150405Z0700" で再度解析を試みます。
  4. 追加されたロジック:
    • もし解析が成功し (err == nil)、かつ解析された time.Time オブジェクトの年 (ret.Year()) が 2050 以上である場合、以下の処理を行います。
    • ret.AddDate(-100, 0, 0) を呼び出して、年を100年減算します。これは、2桁の年が 50 から 99 の範囲であったにもかかわらず、time.Parse がデフォルトで 20YY と解釈してしまったケースを修正するためのものです。
    • コメント // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 が追加され、このロジックの根拠がRFC 5280にあることが明示されています。
  5. 最終的に、解析された time.Time オブジェクトとエラーを返します。

この修正により、UTCTime の2桁の年が 50 から 99 の範囲である場合、正しく 19YY と解釈されるようになり、RFC 5280に準拠した正確な日付解析が可能になります。

関連リンク

参考にした情報源リンク

  • RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile: https://tools.ietf.org/html/rfc5280 (特にセクション 4.1.2.5.1 UTCTime)
  • Go言語の公式ドキュメントおよびソースコード
  • ASN.1に関する一般的な情報源 (例: Wikipedia, ITU-T勧告)
  • Y2K問題および2桁の年解釈に関する技術記事# [インデックス 12372] ファイルの概要

このコミットは、Go言語の encoding/asn1 パッケージにおける UTCTime の解析ロジックを修正するものです。特に、2桁の年表記を持つ UTCTime が2000年以前の日付(例: 1950年代)を正しく解釈できるように、曖昧性解消のルールを適用しています。

コミット

commit 6aed6130309c5567015069599712671a99444fd1
Author: Adam Langley <agl@golang.org>
Date:   Mon Mar 5 11:31:24 2012 -0500

    encoding/asn1: handle UTCTime before the year 2000
    
    UTCTime only has a two digit date field and year values from 50 should
    be 1950, not 2050.
    
    R=golang-dev, r, rsc
    CC=golang-dev
    https://golang.org/cl/5729063

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

https://github.com/golang/go/commit/6aed6130309c5567015069599712671a99444fd1

元コミット内容

encoding/asn1: handle UTCTime before the year 2000

UTCTime は2桁の年フィールドしか持たないため、年が 50 から始まる値は 2050 ではなく 1950 と解釈されるべきである。

変更の背景

ASN.1 (Abstract Syntax Notation One) で定義される UTCTime 型は、年を2桁で表現します。例えば、YYMMDDhhmmssZ の形式です。この2桁の年表記は、特に2000年問題(Y2K問題)に関連して、年が19xx年代なのか20xx年代なのかを判断する際に曖昧さを生じさせます。

RFC 5280 (Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile) のセクション 4.1.2.5.1 では、UTCTime の年解釈について明確なルールが定められています。具体的には、2桁の年が 50 から 99 の範囲であれば 19YY と解釈し、00 から 49 の範囲であれば 20YY と解釈するというものです。

このコミット以前のGoの encoding/asn1 パッケージでは、このルールが正しく適用されておらず、例えば 50 という年が 2050 と誤って解釈される可能性がありました。これにより、特に古いX.509証明書など、UTCTime を使用しているシステムとの相互運用性に問題が生じる可能性がありました。このコミットは、この曖昧さを解消し、RFC 5280の規定に準拠することで、UTCTime の正しい解析を保証することを目的としています。

前提知識の解説

ASN.1 (Abstract Syntax Notation One)

ASN.1は、データ構造を記述するための標準的な記法であり、通信プロトコルやデータストレージにおいて、異なるシステム間でデータを交換する際に使用されます。ASN.1は、データの型(整数、文字列、日付など)や構造(シーケンス、セットなど)をプラットフォーム非依存な形で定義することを可能にします。

UTCTime

UTCTime は、ASN.1で定義される日付と時刻のデータ型の一つです。その特徴は、年が2桁で表現される点にあります。一般的な形式は YYMMDDhhmmssZ または YYMMDDhhmmss+hhmm のようになります。

  • YY: 年の下2桁
  • MM: 月
  • DD: 日
  • hh: 時
  • mm: 分
  • ss: 秒 (オプション)
  • Z: UTC (Zulu time) を示す。または +hhmm / -hhmm でタイムゾーンオフセットを示す。

RFC 5280

RFC 5280は、X.509公開鍵証明書と証明書失効リスト (CRL) のプロファイルを定義するIETF標準です。公開鍵基盤 (PKI) における証明書の構造、フィールド、およびそれらの解釈方法について詳細に規定しています。このRFCは、UTCTime の年解釈に関する曖昧さを解消するための重要なルールを含んでいます。

2桁の年問題 (Y2K+50問題)

2桁の年表記は、特に2000年を境に問題を引き起こしました。99 の次は 00 となるため、00 が1900年なのか2000年なのか、あるいはそれ以降の年なのかを判断する必要がありました。UTCTime の文脈では、RFC 5280によって、50 から 9919YY00 から 4920YY と解釈するというルールが確立されました。これは、UTCTime が2049年までの日付を表現するために設計されたためです。このルールは、しばしば「Y2K+50問題」または「スライディングウィンドウ」アプローチとして知られています。

技術的詳細

Go言語の time パッケージの time.Parse 関数は、指定されたレイアウト文字列に基づいて日付/時刻文字列を解析します。UTCTime の解析においては、"0601021504Z0700" (秒なし) と "060102150405Z0700" (秒あり) の2つのレイアウトが使用されます。ここで 06 は2桁の年を表します。

このコミットの核心は、time.Parse が2桁の年を解析した結果、得られた time.Time オブジェクトの年が 2050 以上である場合に、その年から100年を減算するというロジックを追加することです。これにより、例えば 502050 と解析された場合、1950 に修正されます。これは、RFC 5280の UTCTime の年解釈ルール(2桁の年が 50 から 99 の範囲であれば 19YY と解釈する)を実装したものです。

UTCTime は、RFC 5280の規定により、2050年より前の時刻のみをエンコードするように設計されています。したがって、解析された年が2050年以降である場合、それは2桁の年が 00 から 49 の範囲で 20YY と解釈された結果ではなく、50 から 99 の範囲で 19YY と解釈されるべきであったものが誤って 20YY と解釈されたケースであると判断できます。この修正により、UTCTime の解析がRFC 5280に完全に準拠するようになります。

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

src/pkg/encoding/asn1/asn1.go ファイルの parseUTCTime 関数が変更されています。

--- a/src/pkg/encoding/asn1/asn1.go
+++ b/src/pkg/encoding/asn1/asn1.go
@@ -250,10 +250,14 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)\n func parseUTCTime(bytes []byte) (ret time.Time, err error) {\n  	s := string(bytes)\n  	ret, err = time.Parse("0601021504Z0700", s)\n- 	if err == nil {\n- 		return\n+ 	if err != nil {\n+ 		ret, err = time.Parse("060102150405Z0700", s)\n  	}\n- 	ret, err = time.Parse("060102150405Z0700", s)\n+ 	if err == nil && ret.Year() >= 2050 {\n+ 		// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1\n+ 		ret = ret.AddDate(-100, 0, 0)\n+ 	}\n+\n  	return\n  }

コアとなるコードの解説

変更された parseUTCTime 関数は以下のロジックで動作します。

  1. 入力バイトスライス bytes を文字列 s に変換します。
  2. まず、秒を含まない形式 "0601021504Z0700"s を解析しようと試みます。
  3. もし最初の解析でエラーが発生した場合(つまり、秒なし形式では解析できなかった場合)、次に秒を含む形式 "060102150405Z0700" で再度解析を試みます。
  4. 追加されたロジック:
    • もし解析が成功し (err == nil)、かつ解析された time.Time オブジェクトの年 (ret.Year()) が 2050 以上である場合、以下の処理を行います。
    • ret.AddDate(-100, 0, 0) を呼び出して、年を100年減算します。これは、2桁の年が 50 から 99 の範囲であったにもかかわらず、time.Parse がデフォルトで 20YY と解釈してしまったケースを修正するためのものです。
    • コメント // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 が追加され、このロジックの根拠がRFC 5280にあることが明示されています。
  5. 最終的に、解析された time.Time オブジェクトとエラーを返します。

この修正により、UTCTime の2桁の年が 50 から 99 の範囲である場合、正しく 19YY と解釈されるようになり、RFC 5280に準拠した正確な日付解析が可能になります。

関連リンク

参考にした情報源リンク

  • RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile: https://tools.ietf.org/html/rfc5280 (特にセクション 4.1.2.5.1 UTCTime)
  • Go言語の公式ドキュメントおよびソースコード
  • ASN.1に関する一般的な情報源 (例: Wikipedia, ITU-T勧告)
  • Y2K問題および2桁の年解釈に関する技術記事