]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/asn1: use GeneralizedTime for times outside the range of UTCTime.
authorAdam Langley <agl@golang.org>
Fri, 21 Mar 2014 15:14:38 +0000 (11:14 -0400)
committerAdam Langley <agl@golang.org>
Fri, 21 Mar 2014 15:14:38 +0000 (11:14 -0400)
Fixes issue #6976.

LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://golang.org/cl/72080044

src/pkg/crypto/tls/generate_cert.go
src/pkg/encoding/asn1/asn1.go
src/pkg/encoding/asn1/marshal.go
src/pkg/encoding/asn1/marshal_test.go

index 1b4830c725cb40f0766f354442ed74e4ffbd9807..5c6d8396d5208ea7a998718b2f154d3e688291b0 100644 (file)
@@ -58,12 +58,6 @@ func main() {
 
        notAfter := notBefore.Add(*validFor)
 
-       // end of ASN.1 time
-       endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
-       if notAfter.After(endOfTime) {
-               notAfter = endOfTime
-       }
-
        serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
        serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
        if err != nil {
index 7a3c3797c8bb8240455c133c208f912073315dc5..ec7f91c1bba5ebd8909aecabd24e7e6078b977a2 100644 (file)
@@ -465,11 +465,15 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
                if err != nil {
                        return
                }
-               // We pretend that various other string types are PRINTABLE STRINGs
-               // so that a sequence of them can be parsed into a []string.
                switch t.tag {
                case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+                       // We pretend that various other string types are
+                       // PRINTABLE STRINGs so that a sequence of them can be
+                       // parsed into a []string.
                        t.tag = tagPrintableString
+               case tagGeneralizedTime, tagUTCTime:
+                       // Likewise, both time types are treated the same.
+                       t.tag = tagUTCTime
                }
 
                if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
index da50cf25e83a7ab5c38a3ed2d3dc6005bf9d780c..e26fe59b305b29e1c8f81a06a61b150e3adb7ddb 100644 (file)
@@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
        return out.WriteByte(byte('0' + v%10))
 }
 
+func marshalFourDigits(out *forkableWriter, v int) (err error) {
+       var bytes [4]byte
+       for i := range bytes {
+               bytes[3-i] = '0' + byte(v%10)
+               v /= 10
+       }
+       _, err = out.Write(bytes[:])
+       return
+}
+
+func outsideUTCRange(t time.Time) bool {
+       year := t.Year()
+       return year < 1950 || year >= 2050
+}
+
 func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
-       year, month, day := t.Date()
+       year := t.Year()
 
        switch {
        case 1950 <= year && year < 2000:
@@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
                return
        }
 
+       return marshalTimeCommon(out, t)
+}
+
+func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+       year := t.Year()
+       if year < 0 || year > 9999 {
+               return StructuralError{"cannot represent time as GeneralizedTime"}
+       }
+       if err = marshalFourDigits(out, year); err != nil {
+               return
+       }
+
+       return marshalTimeCommon(out, t)
+}
+
+func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+       _, month, day := t.Date()
+
        err = marshalTwoDigits(out, int(month))
        if err != nil {
                return
@@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte {
 func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
        switch value.Type() {
        case timeType:
-               return marshalUTCTime(out, value.Interface().(time.Time))
+               t := value.Interface().(time.Time)
+               if outsideUTCRange(t) {
+                       return marshalGeneralizedTime(out, t)
+               } else {
+                       return marshalUTCTime(out, t)
+               }
        case bitStringType:
                return marshalBitString(out, value.Interface().(BitString))
        case objectIdentifierType:
@@ -504,7 +542,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
                return StructuralError{"explicit string type given to non-string member"}
        }
 
-       if tag == tagPrintableString {
+       switch tag {
+       case tagPrintableString:
                if params.stringType == 0 {
                        // This is a string without an explicit string type. We'll use
                        // a PrintableString if the character set in the string is
@@ -521,6 +560,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
                } else {
                        tag = params.stringType
                }
+       case tagUTCTime:
+               if outsideUTCRange(v.Interface().(time.Time)) {
+                       tag = tagGeneralizedTime
+               }
        }
 
        if params.set {
index 763c86da23f5b0b5b2ea7e2cb361fd8e8f6375e0..a15acbed012d15e4b74d47a261ffa289b22635d9 100644 (file)
@@ -67,6 +67,14 @@ type marshalTest struct {
        out string // hex encoded
 }
 
+func farFuture() time.Time {
+       t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
+       if err != nil {
+               panic(err)
+       }
+       return t
+}
+
 var marshalTests = []marshalTest{
        {10, "02010a"},
        {127, "02017f"},
@@ -83,6 +91,7 @@ var marshalTests = []marshalTest{
        {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
        {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
        {time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
+       {farFuture(), "180f32313030303430353132303130315a"},
        {BitString{[]byte{0x80}, 1}, "03020780"},
        {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
        {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},