I am trying to do ASN.1 marshal/unmarshal for the following definition:
ACEI ::= SEQUENCE {
message MessageFields,
neRegNumber OCTET STRING OPTIONAL,
gpsInfo GpsInfo OPTIONAL,
siteInfo OCTET STRING OPTIONAL,
nlementID INTEGER(0..16777216) OPTIONAL,
...
}
GpsInfo ::= SEQUENCE {
gpsLat INTEGER(-900000000..900000000) OPTIONAL,
gpsLong INTEGER(-1800000000..1800000000) OPTIONAL,
gpsAlt INTEGER OPTIONAL,
...
}
MessageFields ::= SEQUENCE {
messageSequence INTEGER (1..65535),
bsId INTEGER (1..65535) OPTIONAL,
neID INTEGER(0..16777216) OPTIONAL, -- unsigned int
nelementID INTEGER(0..16777216) OPTIONAL, -- unsigned int
...
}
The corresponding go structs are:
type ACEI struct {
Message MessageFields
NeRegNumber []byte `asn1:"optional"`
GPSInfo GPSInfo `asn1:"optional"`
SiteInfo []byte `asn1:"optional"`
NElementID int `asn1:"optional"`
}
type GPSInfo struct {
GpsLatitude int `asn1:"optional"`
GpsLongitude int `asn1:"optional"`
GpsAltitude int `asn1:"optional"`
}
type MessageFields struct {
MessageSequence int
BsId int `asn1:"optional"`
NeID int `asn1:"optional"`
NElementID int `asn1:"optional"`
}
I am filling in the structs, marshalling them and then converting them to hex. When I do that, the hex sequence (seqA) obtained is:
302e300f020101020204d2020215b302021a0a040430413042300b02019c020200be020200c80404304330440202309c
When I do the same on http://asn1-playground.oss.com/, I get the following hex sequence (seqB):
302AA00F 80010181 0204D282 0215B383 021A0A81 020A0BA2 0B80019C 810200BE 820200C8 83020C0D 8402309C
I fed in both these hex sequences to the unmarshal function; while the seqA is correctly unmarshalled, unmarshalling seqB gives me the following error:
Error while unmarshalling: asn1: structure error: tags don't match (16 vs {class:2 tag:0 length:15 isCompound:true}) {optional:false explicit:false application:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} MessageFields @2
This is the code that marshals/unmarshals:
func main() {
//Marshalling
messageSequence := structs.MessageFields{1, 1234, 5555, 6666}
gpsInfo := structs.GPSInfo{-100, 190, 200}
val := structs.ACEI{messageSequence, []byte("0A0B"), gpsInfo, []byte("0C0D"), 12444}
hexmdata := asn1Marshal(val)
//Unmarshalling hex sequence (seqA) generated by go code
res1, _ := asn1Unmarshal(hexmdata)
fmt.Println(res1)
//Unmarshalling hex sequence (seqB) generated by http://asn1-playground.oss.com/
res2, _ := asn1Unmarshal(strings.ToLower("302AA00F800101810204D2820215B383021A0A81020A0BA20B80019C810200BE820200C883020C0D8402309C"))
fmt.Println(res2)
}
func asn1Unmarshal(hexmdata string) (structs.ACEI, error){
fmt.Println(hexmdata)
s, _ := hex.DecodeString(hexmdata)
res := structs.ACEI{}
_, err := asn1.Unmarshal(s, &res)
if err != nil {
fmt.Println("Error while unmarshalling: ", err)
}
return res, err
}
func asn1Marshal(data structs.ACEI) string {
mdata, _ := asn1.Marshal(data)
hexmdata := hex.EncodeToString(mdata)
return hexmdata
}
- Why are the hex sequences different for the same definition?
- How can I correct the error that I get during unmarshalling of seqB?
EDIT: Conversely, the go code sequence (seqA) when fed to http://asn1-playground.oss.com/ gives me this error:
ACEI SEQUENCE: tag = [UNIVERSAL 16] constructed; length = 46
D0033E: Tag mismatch or tag not expected: [UNIVERSAL 16] (expected tag [0]); check field 'message' (type: MessageFields) of PDU #1 'ACEI'.
*SKIPPED*: tag = [UNIVERSAL 16] constructed; length = 15
<skipped>
D0033E: Tag mismatch or tag not expected: [UNIVERSAL 4] (expected tag [0]); check field 'message' (type: MessageFields) of PDU #1 'ACEI'.
*SKIPPED*: tag = [UNIVERSAL 4] primitive; length = 4
<skipped>
D0033E: Tag mismatch or tag not expected: [UNIVERSAL 16] (expected tag [0]); check field 'message' (type: MessageFields) of PDU #1 'ACEI'.
*SKIPPED*: tag = [UNIVERSAL 16] constructed; length = 11
<skipped>
D0033E: Tag mismatch or tag not expected: [UNIVERSAL 4] (expected tag [0]); check field 'message' (type: MessageFields) of PDU #1 'ACEI'.
*SKIPPED*: tag = [UNIVERSAL 4] primitive; length = 4
<skipped>
D0033E: Tag mismatch or tag not expected: [UNIVERSAL 2] (expected tag [0]); check field 'message' (type: MessageFields) of PDU #1 'ACEI'.
*SKIPPED*: tag = [UNIVERSAL 2] primitive; length = 2
<skipped>
D0049E: Field omitted: "message"; check PDU #1 'ACEI'.
S0012E: Decoding of PDU #1 failed with the return code '5'.
EDIT 2: After editing the structs according to @YaFred's suggestion, my structs look like this now:
type ACEI struct {
Message MessageFields `asn1:"application,tag:0,implicit"`
NeRegNumber []byte `asn1:"application,tag:1,implicit,optional"`
GPSInfo GPSInfo `asn1:"application,tag:2,implicit,optional"`
SiteInfo []byte `asn1:"application,tag:3,implicit,optional"`
NElementID int `asn1:"application,tag:4,implicit,optional"`
}
type GPSInfo struct {
GpsLatitude int `asn1:"application,tag:0,implicit,optional"`
GpsLongitude int `asn1:"application,tag:1,implicit,optional"`
GpsAltitude int `asn1:"application,tag:2,implicit,optional"`
}
type MessageFields struct {
MessageSequence int `asn1:"application,tag:0,implicit"`
BsId int `asn1:"application,tag:1,implicit,optional"`
NeID int `asn1:"application,tag:2,implicit,optional"`
NElementID int `asn1:"application,tag:3,implicit,optional"`
}
Marshalling using these structs gives me the same hex code as that obtained from asn playground. But, the unmarshalling fails with the following error:
Hex code: 302aa00f800101810204d2820215b383021a0a81020a0ba20b80019c810200be820200c883020c0d8402309c
Error (the same error I was getting before when I tried to unmarshall hex code (from asn playground) using go code):
Error while unmarshalling: asn1: structure error: tags don't match (0 vs {class:2 tag:0 length:15 isCompound:true}) {optional:false explicit:false application:true defaultValue: tag:0xc042008348 stringType:0 timeType:0 set:false omitEmpty:false} MessageFields @2
EDIT 3: Removing the "application" tag from the structs helps me unmarshal the hex code as expected.
Where you input your types (with your tool as well as with http://asn1-playground.oss.com/), you must use a module. If not, it is not a valid asn1 specification (and your tool as well as oss.com should reject it).
The fact that tools accept to encode types without knowing the module tagging context is the reason for many questions on https://stackoverflow.com/questions/tagged/asn.1
To answer the second question (about the difference of length), you should show what values you gave to oss.com .. it's likely:
They are both 2 bytes long
But when you write
[]byte("0A0B")
you are certainly asking Go to give you the bytes of the string "0A0B" (indeed 30 41 30 42 in ASCII)I think
[]byte{10,11}
should give you the bytes for'0A0B'H
EDITED
If your tool does not take an asn.1 module, you can still do the automatic tagging yourself
EDITED 2 (based on chat with @Aarvi)
It just occurred to me that https://golang.org/pkg/encoding/asn1/ does not involve an ASN.1 compiler.
Instead a Go struct is manually written and annotated.
So following ASN.1 type (in a module with AUTOMATICS TAGS selected)
has to be written manually like this