ssl证书-如何在ASN1中使用[0]和[3]wơrk



我正在解码ASN1(在X.509中用于HTTPS证书)。我做得很好,但有一件事我找不到,也找不到可以理解的文档。

在这个JS ASN1解析器中,您可以看到SEQUENCE元素下的[0][3],第一个在数据中是这样的:A0 03 02 01 02 ...。我想知道这意味着什么以及如何解码。

另一个例子是X.509 v3证书的剖析,在前两个SEQUENCE元素后面有一个[0]

我不明白的是,A0如何与标签字节的前2位是一个类,下一个是基元/构造位,其余5位应该是标签类型的方案相适应。A0是10100000,这意味着标签类型值将为零。

听起来您需要介绍ASN.1标记。有两个角度可以处理这个问题。X.690定义BER/CER/DER编码规则。因此,它回答了标签如何编码的问题。X.680定义了ASN.1本身。因此,它定义了标记的语法和规则。这两个规范都可以在ITU-T网站上找到。我会给你一个快速的概述。

标签在BER/DER/CER中用于识别类型。它们对于区分序列的组成部分和选择的备选方案特别有用。

标记将标记类和标记号组合在一起。标记类包括UNIVERSAL、APPLICATION、PRIVATE和CONTEXT-SPECIFIC。UNIVERSAL类基本上用于内置类型。APPLICATION通常用于用户定义的类型。CONTEXT-SPECIFIC通常用于构造类型(SEQUENCE、CHOICE、SEQUENCEOF)中的组件。从语法上讲,当在ASN.1模块中指定标签时,它们被写在括号内:[tag_class-tag_number];对于CONTEXT-SPECIFIC,省略了tag_class。因此,[应用程序10]或[0]。

虽然每个ASN.1类型都有一个相关的标签,但在语法上,还有一个"TaggedType",ASN.1作者使用它来指定用于编码类型的标签。基本上,TaggedType将标记前缀放在类型之前。例如:

MyType ::= SEQUENCE {
  field_with_tagged_type [0] UTF8String
}

TaggedType中的标记是显式的或隐式的。如果显式,这意味着我希望对原始标记进行显式编码。如果是隐式的,这意味着我很乐意只对我指定的标签进行编码。在显式情况下,BER编码产生嵌套的TLV(标签长度值):外部标签(在上面的示例中为[0])、长度,然后另一个TLV作为值。在本例中,此内部TLV将具有一个UTF8String的标记[UNIVERSAL 12]。

标记是显式还是隐式取决于如何编写标记和标记环境。例如:

MyType2 ::= SEQUENCE {
  field_with_explicit_tag [0] EXPLICIT UTF8String OPTIONAL,
  field_with_implicit_tag [1] IMPLICIT UTF8String OPTIONAL,
  field_with_tag [2] UTF8String OPTIONAL
}

如果既不指定IMPLICIT也不指定EXPLICIT,则有一些规则可以定义标记是显式还是隐式(请参见X.680 31)。这些规则考虑了为ASN.1模块定义的标记环境。ASN.1模块可以将标记环境指定为IMPLICIT TAGS、EXPLICIT TAGS或AUTOMATIC TAGS粗略地说,如果您没有为标记指定IMPLICIT或EXPLICIT,则如果标记环境为EXPLICIT则标记将是显式的,而如果标记环境是IMPLICIT和AUTOMATIC则标记是隐式的。自动标记环境与IMPLICIT标记环境基本相同,不同之处在于为SEQUENCE和CHOICE类型的成员自动分配唯一标记。

请注意,在上面的示例中,MyType2的三个组件都是可选的。在BER/CER/DER中,解码器将根据编码的标签(显然最好是唯一的)知道存在什么组件。

ASN.1 BER和DER使用ASN.1 TAGS来明确识别编码流中的某些组件。ASN.1标签有4类:UNIVERSAL、APPLICATION、PRIVATE和上下文特定。[0]是一个特定于上下文的标记,因为它前面没有标记类keword。UNIVERSAL是为ASN.1中的内置类型保留的。在包含OPTIONAL元素的SEQUENCE中,您通常会看到特定于上下文的标记来消除潜在的歧义。如果你知道你收到的是两个不可选的项目,一个接一个,你就知道哪一个是哪一个,即使它们的标签是相同的。但是,如果第一个标签是可选的,那么这两个标签必须有不同的标签,否则,如果编码中只有一个标签,则无法判断您收到了哪个标签。

如今,ASN.1规范通常使用";"自动标签";这样您就不必担心消息中的这种歧义消除,因为SEQUENCE、SET和CHOICE的组件将自动为每个组件获取以[0]、[1]、[2]等开头的上下文特定标签。

有关ASN.1标签的更多信息,请访问http://www.oss.com/asn1/resources/books-whitepapers-pubs/asn1-books.html那里有两本免费下载的书。

另一个优秀的资源是http://asn1-playground.oss.com在这里,您可以在在线编译器和编码器/解码器中尝试使用不同标签的ASN.1规范的变体。在那里,您可以看到标记更改对编码的影响。

我终于完成了这项工作,并认为我会为仍在努力理解这一点的人提供一些见解。在我的示例中,与上面的示例一样,我使用的是DER格式的X.509证书。我遇到了"A0 03 02 01 02"序列,不知道它是如何翻译成版本号2的。所以,如果你有同样的问题,下面是它的工作原理。

A0告诉它是一个"上下文特定"字段,一个"构造"标记,类型值为0x00。立即,特定于上下文的告诉不要使用DER/BER的正常类型字段。相反,如果这是一个X.509证书,则在RFC 5280,p 116中标记了类型值。在那里,您将看到四个带有标记的字段[0]、[1]、[2]和[3],分别代表"version"、"issuerUniqueID"、"subjectUniqueID"one_answers"extension"。因此,在这种情况下,A0值告诉您这是X.509上下文特定字段之一,特别是"版本"类型。这样可以处理"A0"值。

正如您所期望的,"03"值只是您的长度。

由于这被确定为"构造",数据应该表示一个正常的DER/BER对象。"02 01 02"是您要查找的实际版本号,用整数表示。"02"是Integer的标准BER编码,"01"是您的长度,而"02"则是您的值,或者在本例中是您的版本号。

因此,假设X.509定义了4个特定于上下文的类型,您应该期望在证书中的任何位置看到"A0"、"A1"、"A2"one_answers"A3"。希望上面提供的信息现在更有意义,并帮助您更好地理解这些标记所代表的内容。

[0]是一种特定于上下文的标记类型,这意味着为了弄清楚它赋予字段(如果设置了"构造"标志)或数据值(如果没有设置"构造"标记)什么意义,它会包装;你必须知道它出现在什么环境中。

此外,您还需要知道发送方和接收方在DER流中交换的是什么类型的对象,即";ASN.1模块";。

假设他们正在交换证书签名请求,[0]显示为根SEQUENCE:中SEQUENCE内的第4个字段

SEQUENCE
    SEQUENCE
        INTEGER 0
        SEQUENCE { ... }
        SEQUENCE { ... }
        [0] { ... }
    }
}

然后,根据定义证书签名请求的DER内容的RFC2968,定义ASN.1模块的附录A,该特定字段的含义被偷偷地定义为";属性";以及";应设置构造标志":

    attributes    [0] Attributes{{ CRIAttributes }}

你也可以走另一条路,看到";属性";必须是根序列内第一个序列内的第四个字段,并通过查看根序列定义(第4节:"顶级类型CertificateRequest"),找到其中的CertificateRequestInfo位置,并找到";属性";项目位于CertificateRequestInfo中,并最终查看它是如何标记的。

最新更新