[インデックス 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
から 99
は 19YY
、00
から 49
は 20YY
と解釈するというルールが確立されました。これは、UTCTime
が2049年までの日付を表現するために設計されたためです。このルールは、しばしば「Y2K+50問題」または「スライディングウィンドウ」アプローチとして知られています。
技術的詳細
Go言語の time
パッケージの time.Parse
関数は、指定されたレイアウト文字列に基づいて日付/時刻文字列を解析します。UTCTime
の解析においては、"0601021504Z0700"
(秒なし) と "060102150405Z0700"
(秒あり) の2つのレイアウトが使用されます。ここで 06
は2桁の年を表します。
このコミットの核心は、time.Parse
が2桁の年を解析した結果、得られた time.Time
オブジェクトの年が 2050
以上である場合に、その年から100年を減算するというロジックを追加することです。これにより、例えば 50
が 2050
と解析された場合、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
関数は以下のロジックで動作します。
- 入力バイトスライス
bytes
を文字列s
に変換します。 - まず、秒を含まない形式
"0601021504Z0700"
でs
を解析しようと試みます。 - もし最初の解析でエラーが発生した場合(つまり、秒なし形式では解析できなかった場合)、次に秒を含む形式
"060102150405Z0700"
で再度解析を試みます。 - 追加されたロジック:
- もし解析が成功し (
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にあることが明示されています。
- もし解析が成功し (
- 最終的に、解析された
time.Time
オブジェクトとエラーを返します。
この修正により、UTCTime
の2桁の年が 50
から 99
の範囲である場合、正しく 19YY
と解釈されるようになり、RFC 5280に準拠した正確な日付解析が可能になります。
関連リンク
- Go言語の
encoding/asn1
パッケージ: https://pkg.go.dev/encoding/asn1 - Go言語の
time
パッケージ: https://pkg.go.dev/time - RFC 5280: https://tools.ietf.org/html/rfc5280
参考にした情報源リンク
- 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
から 99
は 19YY
、00
から 49
は 20YY
と解釈するというルールが確立されました。これは、UTCTime
が2049年までの日付を表現するために設計されたためです。このルールは、しばしば「Y2K+50問題」または「スライディングウィンドウ」アプローチとして知られています。
技術的詳細
Go言語の time
パッケージの time.Parse
関数は、指定されたレイアウト文字列に基づいて日付/時刻文字列を解析します。UTCTime
の解析においては、"0601021504Z0700"
(秒なし) と "060102150405Z0700"
(秒あり) の2つのレイアウトが使用されます。ここで 06
は2桁の年を表します。
このコミットの核心は、time.Parse
が2桁の年を解析した結果、得られた time.Time
オブジェクトの年が 2050
以上である場合に、その年から100年を減算するというロジックを追加することです。これにより、例えば 50
が 2050
と解析された場合、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
関数は以下のロジックで動作します。
- 入力バイトスライス
bytes
を文字列s
に変換します。 - まず、秒を含まない形式
"0601021504Z0700"
でs
を解析しようと試みます。 - もし最初の解析でエラーが発生した場合(つまり、秒なし形式では解析できなかった場合)、次に秒を含む形式
"060102150405Z0700"
で再度解析を試みます。 - 追加されたロジック:
- もし解析が成功し (
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にあることが明示されています。
- もし解析が成功し (
- 最終的に、解析された
time.Time
オブジェクトとエラーを返します。
この修正により、UTCTime
の2桁の年が 50
から 99
の範囲である場合、正しく 19YY
と解釈されるようになり、RFC 5280に準拠した正確な日付解析が可能になります。
関連リンク
- Go言語の
encoding/asn1
パッケージ: https://pkg.go.dev/encoding/asn1 - Go言語の
time
パッケージ: https://pkg.go.dev/time - RFC 5280: https://tools.ietf.org/html/rfc5280
参考にした情報源リンク
- 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桁の年解釈に関する技術記事