Commit 0bb96bea authored by Richard Barnes's avatar Richard Barnes Committed by Adam Langley

encoding/asn1: Improved control of flags and times

This change corrects the serialization of asn1.Flag values, so that
when set, they serialize to an empty value, and when unset, they are
omitted. It also adds a format parameter that allows calling code
to control whether time.Time values are serialized as UTCTime or
GeneralizedTime.

Change-Id: I6d97abf009ea317338dab30c80f35a2de7e07104
Reviewed-on: https://go-review.googlesource.com/5970Reviewed-by: 's avatarAdam Langley <agl@golang.org>
Run-TryBot: Adam Langley <agl@golang.org>
parent d942737f
...@@ -579,6 +579,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -579,6 +579,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
result, err = parseObjectIdentifier(innerBytes) result, err = parseObjectIdentifier(innerBytes)
case tagUTCTime: case tagUTCTime:
result, err = parseUTCTime(innerBytes) result, err = parseUTCTime(innerBytes)
case tagGeneralizedTime:
result, err = parseGeneralizedTime(innerBytes)
case tagOctetString: case tagOctetString:
result = innerBytes result = innerBytes
default: default:
......
...@@ -358,6 +358,8 @@ func newBool(b bool) *bool { return &b } ...@@ -358,6 +358,8 @@ func newBool(b bool) *bool { return &b }
var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
{"", fieldParameters{}}, {"", fieldParameters{}},
{"ia5", fieldParameters{stringType: tagIA5String}}, {"ia5", fieldParameters{stringType: tagIA5String}},
{"generalized", fieldParameters{timeType: tagGeneralizedTime}},
{"utc", fieldParameters{timeType: tagUTCTime}},
{"printable", fieldParameters{stringType: tagPrintableString}}, {"printable", fieldParameters{stringType: tagPrintableString}},
{"optional", fieldParameters{optional: true}}, {"optional", fieldParameters{optional: true}},
{"explicit", fieldParameters{explicit: true, tag: new(int)}}, {"explicit", fieldParameters{explicit: true, tag: new(int)}},
...@@ -366,7 +368,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame ...@@ -366,7 +368,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame
{"default:42", fieldParameters{defaultValue: newInt64(42)}}, {"default:42", fieldParameters{defaultValue: newInt64(42)}},
{"tag:17", fieldParameters{tag: newInt(17)}}, {"tag:17", fieldParameters{tag: newInt(17)}},
{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}}, {"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false, false}}, {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, 0, false, false}},
{"set", fieldParameters{set: true}}, {"set", fieldParameters{set: true}},
} }
......
...@@ -74,6 +74,7 @@ type fieldParameters struct { ...@@ -74,6 +74,7 @@ type fieldParameters struct {
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil). defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
stringType int // the string tag to use when marshaling. stringType int // the string tag to use when marshaling.
timeType int // the time tag to use when marshaling.
set bool // true iff this should be encoded as a SET set bool // true iff this should be encoded as a SET
omitEmpty bool // true iff this should be omitted if empty when marshaling. omitEmpty bool // true iff this should be omitted if empty when marshaling.
...@@ -94,6 +95,10 @@ func parseFieldParameters(str string) (ret fieldParameters) { ...@@ -94,6 +95,10 @@ func parseFieldParameters(str string) (ret fieldParameters) {
if ret.tag == nil { if ret.tag == nil {
ret.tag = new(int) ret.tag = new(int)
} }
case part == "generalized":
ret.timeType = tagGeneralizedTime
case part == "utc":
ret.timeType = tagUTCTime
case part == "ia5": case part == "ia5":
ret.stringType = tagIA5String ret.stringType = tagIA5String
case part == "printable": case part == "printable":
......
...@@ -410,9 +410,11 @@ func stripTagAndLength(in []byte) []byte { ...@@ -410,9 +410,11 @@ func stripTagAndLength(in []byte) []byte {
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) { func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
switch value.Type() { switch value.Type() {
case flagType:
return nil
case timeType: case timeType:
t := value.Interface().(time.Time) t := value.Interface().(time.Time)
if outsideUTCRange(t) { if params.timeType == tagGeneralizedTime || outsideUTCRange(t) {
return marshalGeneralizedTime(out, t) return marshalGeneralizedTime(out, t)
} else { } else {
return marshalUTCTime(out, t) return marshalUTCTime(out, t)
...@@ -552,6 +554,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) ...@@ -552,6 +554,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
} }
class := classUniversal class := classUniversal
if params.timeType != 0 && tag != tagUTCTime {
return StructuralError{"explicit time type given to non-time member"}
}
if params.stringType != 0 && tag != tagPrintableString { if params.stringType != 0 && tag != tagPrintableString {
return StructuralError{"explicit string type given to non-string member"} return StructuralError{"explicit string type given to non-string member"}
} }
...@@ -575,7 +581,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) ...@@ -575,7 +581,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
tag = params.stringType tag = params.stringType
} }
case tagUTCTime: case tagUTCTime:
if outsideUTCRange(v.Interface().(time.Time)) { if params.timeType == tagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
tag = tagGeneralizedTime tag = tagGeneralizedTime
} }
} }
......
...@@ -42,6 +42,14 @@ type explicitTagTest struct { ...@@ -42,6 +42,14 @@ type explicitTagTest struct {
A int `asn1:"explicit,tag:5"` A int `asn1:"explicit,tag:5"`
} }
type flagTest struct {
A Flag `asn1:"tag:0,optional"`
}
type generalizedTimeTest struct {
A time.Time `asn1:"generalized"`
}
type ia5StringTest struct { type ia5StringTest struct {
A string `asn1:"ia5"` A string `asn1:"ia5"`
} }
...@@ -92,10 +100,13 @@ var marshalTests = []marshalTest{ ...@@ -92,10 +100,13 @@ var marshalTests = []marshalTest{
{[]byte{1, 2, 3}, "0403010203"}, {[]byte{1, 2, 3}, "0403010203"},
{implicitTagTest{64}, "3003850140"}, {implicitTagTest{64}, "3003850140"},
{explicitTagTest{64}, "3005a503020140"}, {explicitTagTest{64}, "3005a503020140"},
{flagTest{true}, "30028000"},
{flagTest{false}, "3000"},
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"}, {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"}, {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"}, {time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
{farFuture(), "180f32313030303430353132303130315a"}, {farFuture(), "180f32313030303430353132303130315a"},
{generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"},
{BitString{[]byte{0x80}, 1}, "03020780"}, {BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"}, {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"}, {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment