summaryrefslogtreecommitdiff
path: root/src/pkg/asn1/asn1.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/asn1/asn1.go')
-rw-r--r--src/pkg/asn1/asn1.go102
1 files changed, 62 insertions, 40 deletions
diff --git a/src/pkg/asn1/asn1.go b/src/pkg/asn1/asn1.go
index d06b1d4d7..8c99bd7a0 100644
--- a/src/pkg/asn1/asn1.go
+++ b/src/pkg/asn1/asn1.go
@@ -373,7 +373,7 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
// a number of ASN.1 values from the given byte array and returns them as a
// slice of Go values of the given type.
-func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflect.Type) (ret *reflect.SliceValue, err os.Error) {
+func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) {
expectedTag, compoundType, ok := getUniversalType(elemType)
if !ok {
err = StructuralError{"unknown Go type for slice"}
@@ -389,6 +389,11 @@ func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflec
if err != nil {
return
}
+ // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
+ // that a sequence of them can be parsed into a []string.
+ if t.tag == tagGeneralString {
+ t.tag = tagPrintableString
+ }
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
err = StructuralError{"sequence tag mismatch"}
return
@@ -404,7 +409,7 @@ func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflec
params := fieldParameters{}
offset := 0
for i := 0; i < numElements; i++ {
- offset, err = parseField(ret.Elem(i), bytes, offset, params)
+ offset, err = parseField(ret.Index(i), bytes, offset, params)
if err != nil {
return
}
@@ -456,13 +461,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
}
result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
offset += t.length
- v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
+ v.Set(reflect.NewValue(result))
return
}
// Deal with the ANY type.
- if ifaceType, ok := fieldType.(*reflect.InterfaceType); ok && ifaceType.NumMethod() == 0 {
- ifaceValue := v.(*reflect.InterfaceValue)
+ if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 {
var t tagAndLength
t, offset, err = parseTagAndLength(bytes, offset)
if err != nil {
@@ -501,7 +505,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return
}
if result != nil {
- ifaceValue.Set(reflect.NewValue(result))
+ v.Set(reflect.NewValue(result))
}
return
}
@@ -516,7 +520,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return
}
if params.explicit {
- if t.class == classContextSpecific && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
+ expectedClass := classContextSpecific
+ if params.application {
+ expectedClass = classApplication
+ }
+ if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
if t.length > 0 {
t, offset, err = parseTagAndLength(bytes, offset)
if err != nil {
@@ -527,9 +535,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
return
}
-
- flagValue := v.(*reflect.BoolValue)
- flagValue.Set(true)
+ v.SetBool(true)
return
}
} else {
@@ -551,6 +557,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
if universalTag == tagPrintableString && t.tag == tagIA5String {
universalTag = tagIA5String
}
+ // Likewise for GeneralString
+ if universalTag == tagPrintableString && t.tag == tagGeneralString {
+ universalTag = tagGeneralString
+ }
// Special case for time: UTCTime and GeneralizedTime both map to the
// Go type time.Time.
@@ -566,6 +576,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
expectedTag = *params.tag
}
+ if !params.explicit && params.application && params.tag != nil {
+ expectedClass = classApplication
+ expectedTag = *params.tag
+ }
+
// We have unwrapped any explicit tagging at this point.
if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
// Tags don't match. Again, it could be an optional element.
@@ -588,23 +603,20 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
switch fieldType {
case objectIdentifierType:
newSlice, err1 := parseObjectIdentifier(innerBytes)
- sliceValue := v.(*reflect.SliceValue)
- sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
+ v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice)))
if err1 == nil {
- reflect.Copy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
+ reflect.Copy(v, reflect.NewValue(newSlice))
}
err = err1
return
case bitStringType:
- structValue := v.(*reflect.StructValue)
bs, err1 := parseBitString(innerBytes)
if err1 == nil {
- structValue.Set(reflect.NewValue(bs).(*reflect.StructValue))
+ v.Set(reflect.NewValue(bs))
}
err = err1
return
case timeType:
- ptrValue := v.(*reflect.PtrValue)
var time *time.Time
var err1 os.Error
if universalTag == tagUTCTime {
@@ -613,55 +625,53 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
time, err1 = parseGeneralizedTime(innerBytes)
}
if err1 == nil {
- ptrValue.Set(reflect.NewValue(time).(*reflect.PtrValue))
+ v.Set(reflect.NewValue(time))
}
err = err1
return
case enumeratedType:
parsedInt, err1 := parseInt(innerBytes)
- enumValue := v.(*reflect.IntValue)
if err1 == nil {
- enumValue.Set(int64(parsedInt))
+ v.SetInt(int64(parsedInt))
}
err = err1
return
case flagType:
- flagValue := v.(*reflect.BoolValue)
- flagValue.Set(true)
+ v.SetBool(true)
return
}
- switch val := v.(type) {
- case *reflect.BoolValue:
+ switch val := v; val.Kind() {
+ case reflect.Bool:
parsedBool, err1 := parseBool(innerBytes)
if err1 == nil {
- val.Set(parsedBool)
+ val.SetBool(parsedBool)
}
err = err1
return
- case *reflect.IntValue:
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch val.Type().Kind() {
case reflect.Int:
parsedInt, err1 := parseInt(innerBytes)
if err1 == nil {
- val.Set(int64(parsedInt))
+ val.SetInt(int64(parsedInt))
}
err = err1
return
case reflect.Int64:
parsedInt, err1 := parseInt64(innerBytes)
if err1 == nil {
- val.Set(parsedInt)
+ val.SetInt(parsedInt)
}
err = err1
return
}
- case *reflect.StructValue:
- structType := fieldType.(*reflect.StructType)
+ case reflect.Struct:
+ structType := fieldType
if structType.NumField() > 0 &&
structType.Field(0).Type == rawContentsType {
bytes := bytes[initOffset:offset]
- val.Field(0).SetValue(reflect.NewValue(RawContent(bytes)))
+ val.Field(0).Set(reflect.NewValue(RawContent(bytes)))
}
innerOffset := 0
@@ -679,11 +689,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
// adding elements to the end has been used in X.509 as the
// version numbers have increased.
return
- case *reflect.SliceValue:
- sliceType := fieldType.(*reflect.SliceType)
+ case reflect.Slice:
+ sliceType := fieldType
if sliceType.Elem().Kind() == reflect.Uint8 {
val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
- reflect.Copy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
+ reflect.Copy(val, reflect.NewValue(innerBytes))
return
}
newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
@@ -692,7 +702,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
}
err = err1
return
- case *reflect.StringValue:
+ case reflect.String:
var v string
switch universalTag {
case tagPrintableString:
@@ -701,11 +711,17 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
v, err = parseIA5String(innerBytes)
case tagT61String:
v, err = parseT61String(innerBytes)
+ case tagGeneralString:
+ // GeneralString is specified in ISO-2022/ECMA-35,
+ // A brief review suggests that it includes structures
+ // that allow the encoding to change midstring and
+ // such. We give up and pass it as an 8-bit string.
+ v, err = parseT61String(innerBytes)
default:
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
}
if err == nil {
- val.Set(v)
+ val.SetString(v)
}
return
}
@@ -724,9 +740,9 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
if params.defaultValue == nil {
return
}
- switch val := v.(type) {
- case *reflect.IntValue:
- val.Set(*params.defaultValue)
+ switch val := v; val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val.SetInt(*params.defaultValue)
}
return
}
@@ -776,8 +792,14 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// Other ASN.1 types are not supported; if it encounters them,
// Unmarshal returns a parse error.
func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
- v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
- offset, err := parseField(v, b, 0, fieldParameters{})
+ return UnmarshalWithParams(b, val, "")
+}
+
+// UnmarshalWithParams allows field parameters to be specified for the
+// top-level element. The form of the params is the same as the field tags.
+func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
+ v := reflect.NewValue(val).Elem()
+ offset, err := parseField(v, b, 0, parseFieldParameters(params))
if err != nil {
return nil, err
}