ASN.1 中隐式和显式标签的编码

Encoding of implicit and explicit tags in ASN.1

我想了解 IMPLICIT 和 EXPLICIT 标签实际上是如何以 DER 二进制形式编码的。

基本的例子很清楚。普通整数,

x INTEGER ::= 5

被编码为 TLV 三元组 02 01 05。在

x [2] IMPLICIT INTEGER ::= 5

隐式标签82替换现有标签02并形成另一个TLV:82 01 05,并在

x [3] EXPLICIT INTEGER ::= 5

在原始 TLV 周围添加了包装器:A3 03 02 01 05

现在我正在看一个更复杂的案例

30 42 A1 40 30 0D 82 0B  77 77 77 2E 62 61 64 2E
6F 72 67 30 09 82 07 62  61 64 2E 63 6F 6D 30 0D
81 0B 62 61 64 40 62 61  64 2E 6F 72 67 30 09 81
07 62 61 64 2E 63 6F 6D  30 0A 87 08 0A 00 00 00
FF 00 00 00

被解码为

SEQUENCE {
  [1] {
    SEQUENCE {
      [2] www.bad.org
    }
    SEQUENCE {
      [2] bad.com
    }
    SEQUENCE {
      [1] bad@bad.org
    }
    SEQUENCE {
      [1] bad.com
    }
    SEQUENCE {
      [7] 0A000000FF000000
    }
  }
}

我的问题是,我怎么知道A1是否是一个隐式标签[1] IMPLICIT SEQUENCE,它取代了原来的标签10,并且包含五个TLV元素(序列),还是环绕这五个元素的显式标签?什么是 A1

显式标签可以包裹多个 TLV 元素吗?

“构造”标志(第 6 位)指示标签是显式还是隐式,这是否正确?或者我需要查看包装纸和被包装物的长度吗?

我不是假设二进制数据是正确的,所以另一种可能是A1 40环绕了下面的序列30 0D ...,长度不匹配,数据必须被拒绝。

您问了几个问题,但每个问题都应该单独回答。

标签本身既不是隐式的也不是显式的。 “标记”(将标记添加到类型的操作)是隐式的或显式的。

考虑以下事实:在 ASN.1 中,每个基本类型(例如 INTEGER、BOOLEAN)或类型构造函数(CHOICE 除外)(例如 SEQUENCE)都有一个 built-in“通用”标签。例如,类型 INTEGER 具有 built-in 标签 UNIVERSAL 2,类型 OBJECT IDENTIFIER 具有 built-in 标签 UNIVERSAL 6,每个 SEQUENCE 类型具有 built-in 标签 UNIVERSAL 16,等等。这不是 BER/DER 特有的。这是类型本身的 属性。

当一种类型作为另一种类型(例如,SEQUENCE 或 CHOICE)的组件出现时,它通常(但不总是)被分配另一个标签。新标签可以替换现有标签或插入现有标签之前。这就是隐式标记和显式标记。在隐式标记中,新标记会替换它所应用的类型的现有标记。在显式标记中,新标记位于现有标记的前面。这也不是 BER/DER 特有的,它是 ASN.1 的一个特性。一些编码规则(BER、DER、OER在一定程度上)在编码中使用标签,而其他编码规则(PER、JER)在编码中不包含标签。不过,标签的存在独立于所使用的编码规则。

对给定类型使用隐式标记还是显式标记取决于几件事。首先,模块中指定了默认标记 header(EXPLICIT TAGS、IMPLICIT TAGS、AUTOMATIC TAGS),它为模块中存在的类型建立了默认标记模式。 (“默认默认”是显式标记。)其次,可以通过在“]”之后使用关键字 IMPLICIT 或 EXPLICIT 来覆盖特定类型模块的默认标记。第三,在某些情况下,标记必须是明确的。

如果在模块 header 中指定 AUTOMATIC TAGS,进程将生成并应用连续的标签,从“context-specific”0 开始,到每个序列类型、集合类型的每个组件,和选择类型,在其任何组件中都不包含文字标记。自动标记过程应用隐式标记,这意味着每个生成的标记将替换现有标记。

有一些限制和一些特殊情况。一是 CHOICE 类型没有自己的通用标记,因此不可能将隐式标记应用于前面没有文字标记(没有要替换的标记)的 CHOICE 类型。如果您不使用 AUTOMATIC TAGS 并且不向选择类型添加新标签,则选择类型将保持没有自己的标签。在 BER/DER 中,解码器仍然可以通过查看即将到来的标签来检测未标记的选择类型的存在,该标签属于存在的选择选项。

以上表明 BER/DER 解码器将如何解释编码中的下一个标签,这可能没有歧义。标记过程将明确定义的标签(通常是一个或两个标签,或者在未标记选择类型的情况下可能 none)分配给模块中的每个类型,包括复杂类型的组件类型。如上所述,这些标签是 ASN.1 模式中存在的每种类型的 属性。在 BER 和 DER 中,编码器将只插入它正在编码的每个值的类型的所有标签。如果值的类型有一个标签,编码器将产生一个 TLV。如果值的类型有两个标签,编码器将产生两个嵌套的 TLV。其实很简单。解码器会知道会发生什么。

Alessandro 为您提供了有关标记的精彩教程。一些快速补充要点:

通用 BER 解码器可以将 BER 数据解码为 TLV 层次结构,但您通常需要具有架构才能知道如何将其与 ASN.1 类型相关联。

标签应用于类型,因此,不,您不能添加显式标签来包装多个 TLV 元素。它将包装单个 TLV。

构造标志告诉你TLV中的V(值)本身是否是TLV。某些类型(例如 BIT STRING)可以以构造形式或原始形式进行编码。当一个类型被显式标记时,它总是会产生一个带有构造标志集的 TLV,但这不是唯一一次使用构造标志。