From 825130b661fbd51902bb584160c9c6ddbd03b966 Mon Sep 17 00:00:00 2001 From: Chris Portman Date: Mon, 3 Dec 2018 15:35:46 +1100 Subject: [PATCH] Fixes #29069 --- src/encoding/asn1/asn1.go | 40 ++++++++---- src/encoding/asn1/asn1_test.go | 115 +++++++++++++++++---------------- src/encoding/asn1/common.go | 3 + 3 files changed, 89 insertions(+), 69 deletions(-) diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index 3cfd9d1276497f..d3140c7c09064b 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -329,17 +329,26 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) // UTCTime -func parseUTCTime(bytes []byte) (ret time.Time, err error) { +func parseUTCTime(bytes []byte, format string) (ret time.Time, err error) { s := string(bytes) + var formatStr string - formatStr := "0601021504Z0700" - ret, err = time.Parse(formatStr, s) - if err != nil { - formatStr = "060102150405Z0700" + if format != "" { + formatStr = format ret, err = time.Parse(formatStr, s) - } - if err != nil { - return + if err != nil { + return + } + } else { + formatStr = "0601021504Z0700" + ret, err = time.Parse(formatStr, s) + if err != nil { + formatStr = "060102150405Z0700" + ret, err = time.Parse(formatStr, s) + } + if err != nil { + return + } } if serialized := ret.Format(formatStr); serialized != s { @@ -357,8 +366,11 @@ func parseUTCTime(bytes []byte) (ret time.Time, err error) { // parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. -func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) { - const formatStr = "20060102150405Z0700" +func parseGeneralizedTime(bytes []byte, format string) (ret time.Time, err error) { + formatStr := "20060102150405Z0700" + if format != "" { + formatStr = format + } s := string(bytes) if ret, err = time.Parse(formatStr, s); err != nil { @@ -686,9 +698,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam case TagOID: result, err = parseObjectIdentifier(innerBytes) case TagUTCTime: - result, err = parseUTCTime(innerBytes) + result, err = parseUTCTime(innerBytes, params.timeFormat) case TagGeneralizedTime: - result, err = parseGeneralizedTime(innerBytes) + result, err = parseGeneralizedTime(innerBytes, params.timeFormat) case TagOctetString: result = innerBytes default: @@ -843,9 +855,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam var time time.Time var err1 error if universalTag == TagUTCTime { - time, err1 = parseUTCTime(innerBytes) + time, err1 = parseUTCTime(innerBytes, params.timeFormat) } else { - time, err1 = parseGeneralizedTime(innerBytes) + time, err1 = parseGeneralizedTime(innerBytes, params.timeFormat) } if err1 == nil { v.Set(reflect.ValueOf(time)) diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index f0a54e0cb2e699..33de1ed488ecad 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -258,51 +258,54 @@ func TestObjectIdentifier(t *testing.T) { } type timeTest struct { - in string - ok bool - out time.Time + in string + ok bool + out time.Time + format string } var utcTestData = []timeTest{ - {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60))}, - {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))}, - {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)}, - {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)}, - {"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC)}, - {"a10506234540Z", false, time.Time{}}, - {"91a506234540Z", false, time.Time{}}, - {"9105a6234540Z", false, time.Time{}}, - {"910506a34540Z", false, time.Time{}}, - {"910506334a40Z", false, time.Time{}}, - {"91050633444aZ", false, time.Time{}}, - {"910506334461Z", false, time.Time{}}, - {"910506334400Za", false, time.Time{}}, + {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60)), ""}, + {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60)), ""}, + {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC), ""}, + {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC), ""}, + {"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC), ""}, + // Test the use of specified custom formats that can be supplied using the timeFormat tag + {"19510506234500.123456Z", true, time.Date(1951, 05, 06, 23, 45, 0, 123456000, time.UTC), "20060102150405.999999Z0700"}, + {"a10506234540Z", false, time.Time{}, ""}, + {"91a506234540Z", false, time.Time{}, ""}, + {"9105a6234540Z", false, time.Time{}, ""}, + {"910506a34540Z", false, time.Time{}, ""}, + {"910506334a40Z", false, time.Time{}, ""}, + {"91050633444aZ", false, time.Time{}, ""}, + {"910506334461Z", false, time.Time{}, ""}, + {"910506334400Za", false, time.Time{}, ""}, /* These are invalid times. However, the time package normalises times * and they were accepted in some versions. See #11134. */ - {"000100000000Z", false, time.Time{}}, - {"101302030405Z", false, time.Time{}}, - {"100002030405Z", false, time.Time{}}, - {"100100030405Z", false, time.Time{}}, - {"100132030405Z", false, time.Time{}}, - {"100231030405Z", false, time.Time{}}, - {"100102240405Z", false, time.Time{}}, - {"100102036005Z", false, time.Time{}}, - {"100102030460Z", false, time.Time{}}, - {"-100102030410Z", false, time.Time{}}, - {"10-0102030410Z", false, time.Time{}}, - {"10-0002030410Z", false, time.Time{}}, - {"1001-02030410Z", false, time.Time{}}, - {"100102-030410Z", false, time.Time{}}, - {"10010203-0410Z", false, time.Time{}}, - {"1001020304-10Z", false, time.Time{}}, + {"000100000000Z", false, time.Time{}, ""}, + {"101302030405Z", false, time.Time{}, ""}, + {"100002030405Z", false, time.Time{}, ""}, + {"100100030405Z", false, time.Time{}, ""}, + {"100132030405Z", false, time.Time{}, ""}, + {"100231030405Z", false, time.Time{}, ""}, + {"100102240405Z", false, time.Time{}, ""}, + {"100102036005Z", false, time.Time{}, ""}, + {"100102030460Z", false, time.Time{}, ""}, + {"-100102030410Z", false, time.Time{}, ""}, + {"10-0102030410Z", false, time.Time{}, ""}, + {"10-0002030410Z", false, time.Time{}, ""}, + {"1001-02030410Z", false, time.Time{}, ""}, + {"100102-030410Z", false, time.Time{}, ""}, + {"10010203-0410Z", false, time.Time{}, ""}, + {"1001020304-10Z", false, time.Time{}, ""}, } func TestUTCTime(t *testing.T) { for i, test := range utcTestData { - ret, err := parseUTCTime([]byte(test.in)) + ret, err := parseUTCTime([]byte(test.in), test.format) if err != nil { if test.ok { - t.Errorf("#%d: parseUTCTime(%q) = error %v", i, test.in, err) + t.Errorf("#%d: parseUTCTime(%q, %q) = error %v", i, test.in, test.format, err) } continue } @@ -320,33 +323,35 @@ func TestUTCTime(t *testing.T) { } var generalizedTimeTestData = []timeTest{ - {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)}, - {"20100102030405", false, time.Time{}}, - {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}, - {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))}, + {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC), ""}, + {"20100102030405", false, time.Time{}, ""}, + {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60)), ""}, + {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60)), ""}, + // Test the use of specified custom formats that can be supplied using the timeFormat tag + {"19510506234500.123456Z", true, time.Date(1951, 05, 06, 23, 45, 0, 123456000, time.UTC), "20060102150405.999999Z0700"}, /* These are invalid times. However, the time package normalises times * and they were accepted in some versions. See #11134. */ - {"00000100000000Z", false, time.Time{}}, - {"20101302030405Z", false, time.Time{}}, - {"20100002030405Z", false, time.Time{}}, - {"20100100030405Z", false, time.Time{}}, - {"20100132030405Z", false, time.Time{}}, - {"20100231030405Z", false, time.Time{}}, - {"20100102240405Z", false, time.Time{}}, - {"20100102036005Z", false, time.Time{}}, - {"20100102030460Z", false, time.Time{}}, - {"-20100102030410Z", false, time.Time{}}, - {"2010-0102030410Z", false, time.Time{}}, - {"2010-0002030410Z", false, time.Time{}}, - {"201001-02030410Z", false, time.Time{}}, - {"20100102-030410Z", false, time.Time{}}, - {"2010010203-0410Z", false, time.Time{}}, - {"201001020304-10Z", false, time.Time{}}, + {"00000100000000Z", false, time.Time{}, ""}, + {"20101302030405Z", false, time.Time{}, ""}, + {"20100002030405Z", false, time.Time{}, ""}, + {"20100100030405Z", false, time.Time{}, ""}, + {"20100132030405Z", false, time.Time{}, ""}, + {"20100231030405Z", false, time.Time{}, ""}, + {"20100102240405Z", false, time.Time{}, ""}, + {"20100102036005Z", false, time.Time{}, ""}, + {"20100102030460Z", false, time.Time{}, ""}, + {"-20100102030410Z", false, time.Time{}, ""}, + {"2010-0102030410Z", false, time.Time{}, ""}, + {"2010-0002030410Z", false, time.Time{}, ""}, + {"201001-02030410Z", false, time.Time{}, ""}, + {"20100102-030410Z", false, time.Time{}, ""}, + {"2010010203-0410Z", false, time.Time{}, ""}, + {"201001020304-10Z", false, time.Time{}, ""}, } func TestGeneralizedTime(t *testing.T) { for i, test := range generalizedTimeTestData { - ret, err := parseGeneralizedTime([]byte(test.in)) + ret, err := parseGeneralizedTime([]byte(test.in), test.format) if (err == nil) != test.ok { t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok) } diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go index 255d1ebfa8990e..acc69cb3ecff52 100644 --- a/src/encoding/asn1/common.go +++ b/src/encoding/asn1/common.go @@ -80,6 +80,7 @@ type fieldParameters struct { tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). stringType int // the string tag to use when marshaling. timeType int // the time tag to use when marshaling. + timeFormat string // the time format to use when unmarshalling. Format appropriate for time.Parse() set bool // true iff this should be encoded as a SET omitEmpty bool // true iff this should be omitted if empty when marshaling. @@ -102,6 +103,8 @@ func parseFieldParameters(str string) (ret fieldParameters) { } case part == "generalized": ret.timeType = TagGeneralizedTime + case strings.HasPrefix(part, "timeFormat:"): + ret.timeFormat = part[11:] case part == "utc": ret.timeType = TagUTCTime case part == "ia5":