【问题标题】:ASN.1 Unmarshalling using go structs gives tags don't match errorASN.1 使用 go 结构解组给出标签不匹配错误
【发布时间】:2018-04-05 06:26:42
【问题描述】:

我正在尝试为以下定义执行 ASN.1 编组/解组:

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
...
}

对应的go结构是:

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"`
}

我正在填写结构,编组它们,然后将它们转换为十六进制。 当我这样做时,获得的十六进制序列(seqA)是:

302e300f020101020204d2020215b302021a0a040430413042300b02019c020200be020200c80404304330440202309c

当我在 http://asn1-playground.oss.com/ 上执行相同操作时,我得到以下十六进制序列 (seqB):

302AA00F 80010181 0204D282 0215B383 021A0A81 020A0BA2 0B80019C 810200BE 820200C8 83020C0D 8402309C

我将这两个十六进制序列都输入了 unmarshal 函数;虽然 seqA 已正确解组,但解组 seqB 会出现以下错误:

解组时出错:asn1:结构错误:标签不匹配(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

这是编组/解组的代码:

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
}
  1. 为什么相同定义的十六进制序列不同?
  2. 如何纠正我在解组 seqB 期间遇到的错误?

编辑:相反,输入到http://asn1-playground.oss.com/ 的 go 代码序列 (seqA) 给了我这个错误:

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'.

编辑 2:根据@YaFred 的建议编辑结构后,我的结构现在看起来像这样:

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"`
}

使用这些结构编组给我的十六进制代码与从 asn 游乐场获得的相同。但是,解组失败并出现以下错误:

十六进制代码: 302aa00f800101810204d2820215b383021a0a81020a0ba20b80019c810200be820200c883020c0d8402309c

错误(我之前尝试使用 go 代码解组十六进制代码(来自 asn 操场)时遇到的相同错误):

解组时出错:asn1:结构错误:标签不匹配(0 vs {class:2 tag:0 length:15 isCompound:true}) {optional:false 显式:假应用程序:真默认值:标签:0xc042008348 stringType:0 timeType:0 set:false omitEmpty:false} MessageFields @2

编辑 3:从结构中删除“应用程序”标签有助于我按预期解组十六进制代码。

【问题讨论】:

  • 在我看来,asn1Marshal GO 函数由于某种原因没有正确计算结构中元素的标签。您应该确保您的模块声明具有自动标记,即它应该看起来像这样 ModuleName DEFINITIONS AUTOMATIC TAGS ::= BEGIN.
  • 谢谢!我应该在我的 go 结构中包含自动标签吗?如果是,怎么做?
  • 您还应该仔细检查参考资料,确保自动标记是您想要的。 asn1-playground 默认为它,但 IMPLICIT(或 EXPLICIT)在野外更常见。
  • 标签和第一条评论中提到的类似:“ModuleName DEFINITIONS AUTOMATIC TAGS...”我不明白这个标签应该如何包含在go代码中。
  • 不幸的是,我不熟悉 GO ASN.1 工具。从我在您的 ASN.1 模式和生成的编码中看到的内容,ASN.1 工具的 GO 实现似乎存在某种问题。考虑到您在类型定义中没有手动标记并且您具有相同类型的 OPTIONAL 字段,编译此模式的唯一方法是使用 AUTOMATIC TAGS(asn1 游乐场将在不使用 AUTOMATIC 时发出模式编译错误标签)。但是查看您的 seqA 编码,似乎出于某种未知原因,GO 工具使用了隐式标签。

标签: go asn.1


【解决方案1】:

在您输入类型的地方(使用您的工具以及使用http://asn1-playground.oss.com/),您必须使用模块。如果不是,它不是一个有效的 asn1 规范(你的工具和 oss.com 应该拒绝它)。

My-module DEFINITIONS ::= 
BEGIN 

ACEI    ::= SEQUENCE {
etc ...

END

工具接受在不知道模块标记上下文的情况下对类型进行编码这一事实是https://stackoverflow.com/questions/tagged/asn.1上许多问题的原因

要回答第二个问题(关于长度的差异),您应该显示您给 oss.com 的值是什么......很可能:

neRegNumber  '0A0B'H
siteInfo     '0C0D'H    

它们都是 2 个字节长

但是当你写 []byte("0A0B") 时,你肯定是在要求 Go 给你字符串“0A0B”的字节(实际上是 ASCII 中的 30 41 30 42)

我认为[]byte{10,11} 应该给你'0A0B'H 的字节

已编辑

如果您的工具不采用 asn.1 模块,您仍然可以自己进行自动标记

ACEI    ::= SEQUENCE {
message         [0] IMPLICIT MessageFields,
neRegNumber     [1] IMPLICIT OCTET STRING OPTIONAL,
gpsInfo         [2] IMPLICIT GpsInfo OPTIONAL,
siteInfo        [3] IMPLICIT OCTET STRING OPTIONAL,
nlementID       [4] IMPLICIT INTEGER(0..16777216) OPTIONAL,
...
}

GpsInfo         ::= SEQUENCE {
gpsLat      [0] IMPLICIT INTEGER(-900000000..900000000) OPTIONAL,
gpsLong     [1] IMPLICIT INTEGER(-1800000000..1800000000) OPTIONAL,
gpsAlt      [2] IMPLICIT INTEGER OPTIONAL,
...
}
MessageFields       ::= SEQUENCE {
messageSequence     [0] IMPLICIT INTEGER (1..65535),
bsId                [1] IMPLICIT INTEGER (1..65535) OPTIONAL,
neID                [2] IMPLICIT INTEGER(0..16777216) OPTIONAL, -- unsigned int
nelementID          [3] IMPLICIT INTEGER(0..16777216) OPTIONAL, -- unsigned int
...
}

已编辑 2(基于与 @Aarvi 的聊天)

我突然想到https://golang.org/pkg/encoding/asn1/ 不涉及 ASN.1 编译器。

取而代之的是手动编写和注释 Go 结构。

所以遵循 ASN.1 类型(在选择了 AUTOMATICS TAGS 的模块中)

GpsInfo         ::= SEQUENCE {
   gpsLat      INTEGER(-900000000..900000000) OPTIONAL,
   gpsLong     INTEGER(-1800000000..1800000000) OPTIONAL,
   gpsAlt      INTEGER OPTIONAL,
   ...
}

必须像这样手动编写

type GPSInfo struct {
    GpsLatitude  int `asn1:"tag:0,implicit,optional"`
    GpsLongitude int `asn1:"tag:1,implicit,optional"`
    GpsAltitude int `asn1:"tag:2,implicit,optional"`
}

【讨论】:

  • 知道如何在 Go 中进行模块标记吗?我的 ASN 定义文件有一个定义,如“模块名称定义自动标签 ::=”
  • 是的,我正在使用相同的。
  • 据我所知,实现非常有限。您可以在编辑后的答案中使用我的建议吗?
  • 我尝试了您的建议,并编辑了我的问题以包含相同的结果。 PS:SO 上似乎有一些错误,UI 对我来说看起来不同,我无法像我想要的那样编​​辑它。请多多包涵。
  • 我想你快到了。您再次混合文本和六边形。解组时必须提供字节。看看golang.org/pkg/encoding/hex/#DecodeString
猜你喜欢
  • 1970-01-01
  • 2015-07-10
  • 2014-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 2019-08-23
  • 2014-04-26
相关资源
最近更新 更多