Add support for ASN.1 "choice"
This commit is contained in:
parent
5ca2e7da6f
commit
a52e547fc7
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.DS_Store
|
25
asn1/asn1.go
25
asn1/asn1.go
@ -572,7 +572,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
|
// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
|
||||||
// a number of ASN.1 values from the given byte slice and returns them as a
|
// a number of ASN.1 values from the given byte slice and returns them as a
|
||||||
// slice of Go values of the given type.
|
// slice of Go values of the given type.
|
||||||
func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err error) {
|
func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type, params fieldParameters) (ret reflect.Value, err error) {
|
||||||
matchAny, expectedTag, compoundType, ok := getUniversalType(elemType)
|
matchAny, expectedTag, compoundType, ok := getUniversalType(elemType)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = StructuralError{"unknown Go type for slice"}
|
err = StructuralError{"unknown Go type for slice"}
|
||||||
@ -599,7 +599,7 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
|
|||||||
t.tag = TagUTCTime
|
t.tag = TagUTCTime
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matchAny && (t.class != ClassUniversal || t.isCompound != compoundType || t.tag != expectedTag) {
|
if !matchAny && (t.class != ClassUniversal || t.isCompound != compoundType || t.tag != expectedTag) && !params.choice {
|
||||||
err = StructuralError{"sequence tag mismatch"}
|
err = StructuralError{"sequence tag mismatch"}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -611,10 +611,10 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
|
|||||||
numElements++
|
numElements++
|
||||||
}
|
}
|
||||||
ret = reflect.MakeSlice(sliceType, numElements, numElements)
|
ret = reflect.MakeSlice(sliceType, numElements, numElements)
|
||||||
params := fieldParameters{}
|
fp := fieldParameters{choice: params.choice}
|
||||||
offset := 0
|
offset := 0
|
||||||
for i := 0; i < numElements; i++ {
|
for i := 0; i < numElements; i++ {
|
||||||
offset, err = parseField(ret.Index(i), bytes, offset, params)
|
offset, err = parseField(ret.Index(i), bytes, offset, fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -800,8 +800,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We have unwrapped any explicit tagging at this point.
|
// We have unwrapped any explicit tagging at this point.
|
||||||
if !matchAnyClassAndTag && (t.class != expectedClass || t.tag != expectedTag) ||
|
if (!matchAnyClassAndTag && (t.class != expectedClass || t.tag != expectedTag) ||
|
||||||
(!matchAny && t.isCompound != compoundType) {
|
(!matchAny && t.isCompound != compoundType)) && !params.choice {
|
||||||
// Tags don't match. Again, it could be an optional element.
|
// Tags don't match. Again, it could be an optional element.
|
||||||
ok := setDefaultValue(v, params)
|
ok := setDefaultValue(v, params)
|
||||||
if ok {
|
if ok {
|
||||||
@ -913,6 +913,17 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
innerOffset := 0
|
innerOffset := 0
|
||||||
for i := 0; i < structType.NumField(); i++ {
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
field := structType.Field(i)
|
field := structType.Field(i)
|
||||||
|
if params.choice {
|
||||||
|
tag := parseFieldParameters(field.Tag.Get("asn1")).tag
|
||||||
|
if tag != nil && t.tag == *tag || t.class != ClassContextSpecific && tag == nil {
|
||||||
|
if tag == nil || params.set {
|
||||||
|
innerBytes = bytes[initOffset:offset]
|
||||||
|
}
|
||||||
|
innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, fieldParameters{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
if i == 0 && field.Type == rawContentsType {
|
if i == 0 && field.Type == rawContentsType {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -932,7 +943,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
reflect.Copy(val, reflect.ValueOf(innerBytes))
|
reflect.Copy(val, reflect.ValueOf(innerBytes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
|
newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem(), params)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
val.Set(newSlice)
|
val.Set(newSlice)
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ type tagAndLength struct {
|
|||||||
type fieldParameters struct {
|
type fieldParameters struct {
|
||||||
optional bool // true iff the field is OPTIONAL
|
optional bool // true iff the field is OPTIONAL
|
||||||
explicit bool // true iff an EXPLICIT tag is in use.
|
explicit bool // true iff an EXPLICIT tag is in use.
|
||||||
|
choice bool // true iff CHOICE tag is in use.
|
||||||
application bool // true iff an APPLICATION tag is in use.
|
application bool // true iff an APPLICATION tag is in use.
|
||||||
private bool // true iff a PRIVATE tag is in use.
|
private bool // true iff a PRIVATE tag is in use.
|
||||||
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
|
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
|
||||||
@ -100,6 +101,8 @@ func parseFieldParameters(str string) (ret fieldParameters) {
|
|||||||
if ret.tag == nil {
|
if ret.tag == nil {
|
||||||
ret.tag = new(int)
|
ret.tag = new(int)
|
||||||
}
|
}
|
||||||
|
case part == "choice":
|
||||||
|
ret.choice = true
|
||||||
case part == "generalized":
|
case part == "generalized":
|
||||||
ret.timeType = TagGeneralizedTime
|
ret.timeType = TagGeneralizedTime
|
||||||
case part == "utc":
|
case part == "utc":
|
||||||
|
@ -480,7 +480,11 @@ func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error
|
|||||||
default:
|
default:
|
||||||
m := make([]encoder, n1)
|
m := make([]encoder, n1)
|
||||||
for i := 0; i < n1; i++ {
|
for i := 0; i < n1; i++ {
|
||||||
m[i], err = makeField(v.Field(i+startingField), parseFieldParameters(t.Field(i+startingField).Tag.Get("asn1")))
|
fp := parseFieldParameters(t.Field(i + startingField).Tag.Get("asn1"))
|
||||||
|
if params.explicit && params.choice {
|
||||||
|
fp.explicit = true
|
||||||
|
}
|
||||||
|
m[i], err = makeField(v.Field(i+startingField), fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -495,6 +499,10 @@ func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fp fieldParameters
|
var fp fieldParameters
|
||||||
|
fp.choice = params.choice
|
||||||
|
if params.choice && params.set {
|
||||||
|
fp.explicit = true
|
||||||
|
}
|
||||||
|
|
||||||
switch l := v.Len(); l {
|
switch l := v.Len(); l {
|
||||||
case 0:
|
case 0:
|
||||||
@ -640,6 +648,10 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
|
|||||||
if params.explicit {
|
if params.explicit {
|
||||||
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{ClassUniversal, tag, bodyLen, isCompound}))
|
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{ClassUniversal, tag, bodyLen, isCompound}))
|
||||||
|
|
||||||
|
if params.choice {
|
||||||
|
t.tag = bytesEncoder(nil)
|
||||||
|
}
|
||||||
|
|
||||||
tt := new(taggedEncoder)
|
tt := new(taggedEncoder)
|
||||||
|
|
||||||
tt.body = t
|
tt.body = t
|
||||||
@ -660,6 +672,10 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
|
|||||||
|
|
||||||
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
|
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
|
||||||
|
|
||||||
|
if tag == TagSequence && params.choice {
|
||||||
|
t.tag = bytesEncoder(nil)
|
||||||
|
}
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user