[インデックス 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桁の年解釈に関する技術記事