我们在(遗留)项目中使用JAC ASN.1 Compiler,并遇到了我们收到无法解析的ASN.1消息的情况。
我看了一下解析器代码,发现这是库中的一个错误。由于切换到商业解决方案并非如此简单,我们不得不分叉并修复它。
ASN.1解码期间是否有任何情况,您在其中读取标签号,而不是查看您的架构是否在您所在的结构级别上具有此标签号,您看看是否有任何嵌套元素具有此标记? / p>
这是一个复制图书馆中的错误的小例子。您可以使用this online playground来编译架构等,并查看正常运行的解析器没有问题。
基本上,它是一个包含两个元素的结构:一个选项和一个字符串,两者都是可选的。该示例的关键是choice元素包含一个标签号等于可选字符串标签号的元素。
Example DEFINITIONS ::= BEGIN
Message ::= SEQUENCE {
params [1] EXPLICIT Params OPTIONAL,
confuser [2] IMPLICIT PrintableString OPTIONAL
}
Params ::= CHOICE {
unimportant [1] IMPLICIT PrintableString,
accident [2] IMPLICIT Accident
}
Accident ::= SEQUENCE {
irrelevant [1] IMPLICIT PrintableString OPTIONAL
}
END
message Message ::= {
confuser "Foo"
}
30058203 466F6F
使用JAC解析器时,它将正确读取消息中的标记号2
,然后遍历模式中的元素以找到要与其关联的元素。但是,对于选择元素,它有一些额外的逻辑:
而不是说" params有标签1,它不是2,所以这个值与它不对应",它是" params有标签1,它不是2,但它是一个选择元素,它包含一个带有标记2的元素,所以这必须是我正在寻找的元素"。
然后它接受Accident
类,继续解析并最终失败,因为它现在无法在此类中找到标记2
。
解析器逻辑中的注释表明这是针对未标记的选择元素的情况。但这让我感到困惑:根据我读到的所有内容,未标记的选择元素不具有默认标记,而是明确标记;此外,选项可以从不隐式标记。
但是有了这些信息,我无法想象任何情况下解析器中的这个逻辑是有用的,我倾向于简单地删除它。但是,我刚刚熟悉ASN.1,因为这个bug可能会忽略一些东西 - 是吗?
答案 0 :(得分:2)
有一种可能需要查看选择成员的标签,并且选择是在没有标签的情况下添加的:
例如,如果您的定义是:
Message ::= SEQUENCE {
params Params OPTIONAL,
confuser [2] IMPLICIT PrintableString OPTIONAL
}
回答你的问题。
解析器逻辑中的注释表明这是针对未标记的选择元素的情况。但这让我感到困惑:根据我读到的所有内容,未标记的选择元素不具有默认标记,而是明确标记;而且,永远不能隐式标记选择。
不,未标记的选择元素采用选择的标记。标记的选择元素必须明确标记,并且永远不能隐式标记。
回到你的定义
Message ::= SEQUENCE {
params [1] EXPLICIT Params OPTIONAL,
confuser [2] IMPLICIT PrintableString OPTIONAL
}
params组件必须有一个显式标记(因为你将它标记为EXPLICIT ...而且还因为X.680的第30.7.c节:
30.6如果满足以下任何条件,则标记结构指定显式标记:
...
℃。 "标签类型"使用替代品和" TagDefault"该模块是IMPLICIT TAGS或AUTOMATIC TAGS,但是由" Type"定义的类型。是一种无标记的选择类型,无标记的开放类型,或无标记的“DummyReference" (见ITU-T X.683建议书| ISO / IEC 8824-4,8.3)。
在这种情况下编码:
x.690:第8.9.2条& 8.9.3
8.9.2内容八位字节应包括对来自中列出的每种类型的一个数据值的完整编码 ASN.1序列类型的定义,按照它们在定义中的出现顺序,除非引用了类型 使用关键字OPTIONAL或关键字DEFAULT。
8.9.3对于用关键字引用的类型,数据值的编码可以但不必存在 可选或关键字DEFAULT。如果存在,它将出现在对应于该点的编码中 ASN.1定义中类型的外观。
但对于params组件,适用的规则首先是8.14.2
8.14.2如果在类型的定义中没有使用隐式标记(参见ITU-T X.680建议书| ISO / IEC 8824-1,30.6), 应构造编码,内容八位字节应为完整的基本编码。
...只有在显式标记类型中我们才能考虑选择8.13的编码
8.13选择值的编码 选择值的编码应与所选类型的值的编码相同。
答案 1 :(得分:1)
这里的真正问题是,尽管指定了标记,解析器仍会查看嵌套元素。 params
字段(如果存在)将始终在编码中使用[1]标记。
对于未标记的字段,查看标记的嵌套类型是有意义的。