Skip to content

Commit 050b60a

Browse files
committed
encoding/asn1: use GeneralizedTime for times outside the range of UTCTime.
Fixes issue #6976. LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/72080044
1 parent 287967f commit 050b60a

File tree

4 files changed

+61
-11
lines changed

4 files changed

+61
-11
lines changed

src/pkg/crypto/tls/generate_cert.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ func main() {
5858

5959
notAfter := notBefore.Add(*validFor)
6060

61-
// end of ASN.1 time
62-
endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
63-
if notAfter.After(endOfTime) {
64-
notAfter = endOfTime
65-
}
66-
6761
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
6862
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
6963
if err != nil {

src/pkg/encoding/asn1/asn1.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,11 +465,15 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
465465
if err != nil {
466466
return
467467
}
468-
// We pretend that various other string types are PRINTABLE STRINGs
469-
// so that a sequence of them can be parsed into a []string.
470468
switch t.tag {
471469
case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
470+
// We pretend that various other string types are
471+
// PRINTABLE STRINGs so that a sequence of them can be
472+
// parsed into a []string.
472473
t.tag = tagPrintableString
474+
case tagGeneralizedTime, tagUTCTime:
475+
// Likewise, both time types are treated the same.
476+
t.tag = tagUTCTime
473477
}
474478

475479
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {

src/pkg/encoding/asn1/marshal.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
295295
return out.WriteByte(byte('0' + v%10))
296296
}
297297

298+
func marshalFourDigits(out *forkableWriter, v int) (err error) {
299+
var bytes [4]byte
300+
for i := range bytes {
301+
bytes[3-i] = '0' + byte(v%10)
302+
v /= 10
303+
}
304+
_, err = out.Write(bytes[:])
305+
return
306+
}
307+
308+
func outsideUTCRange(t time.Time) bool {
309+
year := t.Year()
310+
return year < 1950 || year >= 2050
311+
}
312+
298313
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
299-
year, month, day := t.Date()
314+
year := t.Year()
300315

301316
switch {
302317
case 1950 <= year && year < 2000:
@@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
310325
return
311326
}
312327

328+
return marshalTimeCommon(out, t)
329+
}
330+
331+
func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
332+
year := t.Year()
333+
if year < 0 || year > 9999 {
334+
return StructuralError{"cannot represent time as GeneralizedTime"}
335+
}
336+
if err = marshalFourDigits(out, year); err != nil {
337+
return
338+
}
339+
340+
return marshalTimeCommon(out, t)
341+
}
342+
343+
func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
344+
_, month, day := t.Date()
345+
313346
err = marshalTwoDigits(out, int(month))
314347
if err != nil {
315348
return
@@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte {
378411
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
379412
switch value.Type() {
380413
case timeType:
381-
return marshalUTCTime(out, value.Interface().(time.Time))
414+
t := value.Interface().(time.Time)
415+
if outsideUTCRange(t) {
416+
return marshalGeneralizedTime(out, t)
417+
} else {
418+
return marshalUTCTime(out, t)
419+
}
382420
case bitStringType:
383421
return marshalBitString(out, value.Interface().(BitString))
384422
case objectIdentifierType:
@@ -504,7 +542,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
504542
return StructuralError{"explicit string type given to non-string member"}
505543
}
506544

507-
if tag == tagPrintableString {
545+
switch tag {
546+
case tagPrintableString:
508547
if params.stringType == 0 {
509548
// This is a string without an explicit string type. We'll use
510549
// a PrintableString if the character set in the string is
@@ -521,6 +560,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
521560
} else {
522561
tag = params.stringType
523562
}
563+
case tagUTCTime:
564+
if outsideUTCRange(v.Interface().(time.Time)) {
565+
tag = tagGeneralizedTime
566+
}
524567
}
525568

526569
if params.set {

src/pkg/encoding/asn1/marshal_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ type marshalTest struct {
6767
out string // hex encoded
6868
}
6969

70+
func farFuture() time.Time {
71+
t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
72+
if err != nil {
73+
panic(err)
74+
}
75+
return t
76+
}
77+
7078
var marshalTests = []marshalTest{
7179
{10, "02010a"},
7280
{127, "02017f"},
@@ -83,6 +91,7 @@ var marshalTests = []marshalTest{
8391
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
8492
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
8593
{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
94+
{farFuture(), "180f32313030303430353132303130315a"},
8695
{BitString{[]byte{0x80}, 1}, "03020780"},
8796
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
8897
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},

0 commit comments

Comments
 (0)