aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoding')
-rw-r--r--src/encoding/asn1/asn1.go22
-rw-r--r--src/encoding/asn1/asn1_test.go31
-rw-r--r--src/encoding/asn1/marshal.go1
3 files changed, 51 insertions, 3 deletions
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 4e3f85de13..0b64f06d36 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -828,9 +828,18 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
}
// Special case for time: UTCTime and GeneralizedTime both map to the
- // Go type time.Time.
- if universalTag == TagUTCTime && t.tag == TagGeneralizedTime && t.class == ClassUniversal {
- universalTag = TagGeneralizedTime
+ // Go type time.Time. getUniversalType returns the tag for UTCTime when
+ // it sees a time.Time, so if we see a different time type on the wire,
+ // or the field is tagged with a different type, we change the universal
+ // type to match.
+ if universalTag == TagUTCTime {
+ if t.class == ClassUniversal {
+ if t.tag == TagGeneralizedTime {
+ universalTag = t.tag
+ }
+ } else if params.timeType != 0 {
+ universalTag = params.timeType
+ }
}
if params.set {
@@ -1103,6 +1112,13 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// numeric causes strings to be unmarshaled as ASN.1 NumericString values
// utf8 causes strings to be unmarshaled as ASN.1 UTF8String values
//
+// When decoding an ASN.1 value with an IMPLICIT tag into a time.Time field,
+// Unmarshal will default to a UTCTime, which doesn't support time zones or
+// fractional seconds. To force usage of GeneralizedTime, use the following
+// tag:
+//
+// generalized causes time.Times to be unmarshaled as ASN.1 GeneralizedTime values
+//
// If the type of the first field of a structure is RawContent then the raw
// ASN1 contents of the struct will be stored in it.
//
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index 60dae71df4..0597740bd5 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -1185,3 +1185,34 @@ func BenchmarkObjectIdentifierString(b *testing.B) {
_ = oidPublicKeyRSA.String()
}
}
+
+func TestImplicitTypeRoundtrip(t *testing.T) {
+ type tagged struct {
+ IA5 string `asn1:"tag:1,ia5"`
+ Printable string `asn1:"tag:2,printable"`
+ UTF8 string `asn1:"tag:3,utf8"`
+ Numeric string `asn1:"tag:4,numeric"`
+ UTC time.Time `asn1:"tag:5,utc"`
+ Generalized time.Time `asn1:"tag:6,generalized"`
+ }
+ a := tagged{
+ IA5: "ia5",
+ Printable: "printable",
+ UTF8: "utf8",
+ Numeric: "123 456",
+ UTC: time.Now().UTC().Truncate(time.Second),
+ Generalized: time.Now().UTC().Truncate(time.Second),
+ }
+ enc, err := Marshal(a)
+ if err != nil {
+ t.Fatalf("Marshal failed: %s", err)
+ }
+ var b tagged
+ if _, err := Unmarshal(enc, &b); err != nil {
+ t.Fatalf("Unmarshal failed: %s", err)
+ }
+
+ if !reflect.DeepEqual(a, b) {
+ t.Fatalf("Unexpected diff after roundtripping struct\na: %#v\nb: %#v", a, b)
+ }
+}
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index b9c0b8bce0..70e4fafc12 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -725,6 +725,7 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
// omitempty: causes empty slices to be skipped
// printable: causes strings to be marshaled as ASN.1, PrintableString values
// utf8: causes strings to be marshaled as ASN.1, UTF8String values
+// numeric: causes strings to be marshaled as ASN.1, NumericString values
// utc: causes time.Time to be marshaled as ASN.1, UTCTime values
// generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values
func Marshal(val any) ([]byte, error) {