阿里巴巴的笔记 https://bbs.21ic.com/?531844 [收藏] [复制] [RSS]

日志

【转】ASN.1/BER/DER编码子集入门指南

已有 1569 次阅读2010-3-3 04:47 |系统分类:通信网络| ASN.1, BER, DER


原文地址:http://www.javaresearch.org/article/647.htm
RSA实验室技术笔记
作者:Burton S.Kaliski Jr.
最终修订日期:Nov 1,1993
翻译:David(David@javaresearch.org),2002年6月

摘要:本 笔记提供了关于OSI提出的 ASN.1(Abstract Syntax Notation One)/BER(Basic Encoding Rules) /DER(Distinguished Encoding Rules)的入门指南。本文的主要目的是提供充分的背景细节资料,以便于让读者更好地理解和 实现PKCS系列标准。

译者注:关于安全或者通信,编码是件很基本的事情,无论对于设计人员还是编码人员来说,都是必不可少的。本人希望 通过翻译本文,为那些面对ASN.1编码一筹莫展的人或者因为对ASN.1编码一知半解而常常苦恼的人――提供帮助。在翻译本文之后,本人将利用JCE或 某些Java厂商的java包来演示如何解析和构建ASN.1编码的对象。



1、介绍


     总 所周知,抽象是解决软件开发问题的有效手段。利用抽象,设计人员可以定义系统的一个部分而不用关注这个部门实际上是如何实现或者表达的。这一方法使得实现 很open,它简化了定义过程,使得在实现部件之前可以声明某些“公理”、并且在设计高层部件时假定下层部件是可以实现的。抽象是现代多数软件规范的特 点。

     作为当今最复杂的系统之一,开放系统互联(OSI)是一个包含了大量抽象的例子。OSI是一个国际通用的标准体系,从物理层 一直到用户层,规划了计算机之间的互联。高层次的对象被抽象定义,并将由底层的对象来实现。比如,某层的一个服务可能需要在计算机之间传递某个抽象对象; 某一底层则可能提供关于0、1字符串的实现,利用一些编码规则把高层的抽象对象转换成这些字符串。OSI之所以被称为开放系统是因为它在每一层上支持不同 的服务实现。

     OSI的说明抽象对象的方法叫做抽象语法标记(ASN.1,在X.208中定义),而用0、1字符来表示这样的对象 的规则集合叫做基本编码规则(BER)。ASN.1是一个很灵活的标记法,它允许定义众多的数据类型――从整数和位串等简单类型到如集合、序列等的结构, 还可以是其它复杂定义的类型。BER描述了如何将ASN.1类型表示和编码成八位字节串。通常不止一种编码给定数据的方法,另一种叫做 DER(Distinguished Encoding Rules)的编码集合,它是BER的子集,其特点是给每一个ASN.1值一个唯一的编码。

     本 笔记的目的是充分地描述ASN.1/BER/DER编码子集,以便于理解和实现基于OSI的应用和RSA数据公司的PKCS标准。本笔记包括关于 ASN.1/BER/DER的概述、经过删节的ASN.1类型列表和它们的BER/DER编码。2-4节给出了一个ASN.1/BER/DER的概述,第 5节列出了一些ASN.1类型,给出了他们的表示法、特定的编码规则、例子和它们对于PKCS的应用情况。第6节以X.500区别名称为例做了一个总结。

     本笔记没有谈到ASN.1的高级特点(例如宏),因为它们在实现PKCS时并不必要。关于其它特征和更多细节,请读者参考CCITT的建议文档:X.208、X.209,这两份文档中定义了ASN.1和BER。

术语和表示法 本笔记中,字节指8位无符号整数,第8位最重要,而第1位最不重要。以下表示法将用来表示ASN.1标记:

     BIT   用等宽在类型和值标记中表示文本字符;例如,它表示十六进制中的一个字节值。
    n1    宽体斜体表示一个变量
    [ ]       方括号表示一个条款是可选的
    { }      大括号表示相关条款
     |      竖条表示可以在一组值中任选
    ...     省略号表示多次重复
     =       等号表示条目由一些子条目来表达。


2. 抽象语法标记(Abstract Syntax Notation One)


     抽象语法标记(Abstract Syntax Notation One)是描述抽象类型和值的标记,缩写为ASN.1。

     在 ASN.1中,一个类型就是值的一个集合。有些类型有有限个值,有些则有无限多个。一个给定的ASN.1类型的值是该类型集合里的一个元素。ASN.1有 四种类型:简单类型,它相当于原子,没有下层组件;结构类型,有组成部分;标签类型,由其它类型生成;其它类型,包括CHOICE和ANY类型。可以使用 ASN.1的分配符(::=)给类型和值指定名字,这些名字可以用于定义其它类型或值。

     除了CHOICE和ANY类型以外,每种ASN.1类型都有一个标签,由一个类和一个非负的标签数组成。标签值可以唯一区分ASN.1类型。也就是说,ASN.1类型的名字并不影响它的抽象含义,只有标签值才有这个作用。有四类标签:
    
    ●Universal:该类型的含义在所有的application中都相同。这种类型只在X.208中定义。
         ●Application:该类型的含义由application决定,如X.500目录服务。两个不同的application中的类型可以具有相同的application-specific标签但是可以具有不同的含义。
         ●Private:,该类型的含义根据给定的企业而不同。
         ●Context-specific:该类型的含义根据给定的结构类型而不同。Context-specific标签用于在一个给定的结构类型上下文中区分使用相同的下层标签的组件类型。在两个不同的结构类型中组件类型可以具有相同的标签但是含义不同。

     具 有universal标签的类型在X.208中定义,X.208也给出了类型的universal标签值。使用其他标签的类型在很多地方都有定义,通常是 通过implicit或explicit标签获得。表一列出了部分ASN.1类型及其universal-class标签。

(译者注:为了表示清晰,表格中的字段用下划线分隔开来)

====Type Tag================number_(decimal)========Tag_number_(hexadecimal)
________INTEGER____________________2_________________________02________________
________BIT_STRING_________________3_________________________03________________
________OCTET_STRING_______________4_________________________04________________
________NULL_______________________5_________________________05________________
________OBJECT IDENTIFIER__________6_________________________06________________
________SEQUENCE and SEQUENCE OF___16________________________10________________
________SET and SET OF____________17________________________11_________________
________PrintableString____________19________________________13________________
________T61String__________________20________________________14________________
________IA5String__________________22________________________16________________
________UTCTime____________________23________________________17________________

     ASN.1类型和值使用一种灵活的、类似编程语言的符号表示,规则如下:
    
    分层(换行)无特殊意义;多个空格和多个空行相当于一个空格。
         注释由一对连字符(--)开头,或者一对连字符和一个空行
         识别符(值或字段的名字)和类型索引(类型的名字)由大小写字母、数字、连字符和空格组成;识别符由小写字母开头,类型索引由大写字母开头。

     下面的四个子节概括介绍了简单类型、结构类型、隐式和显式标签类型,及其他类型。第5节定义了类型的更多细节。

2.1 简单类型(Simple types)


     简单类型没有组件,是“原子级”的类型。ASN.1定义了几个简单类型,其中与PKCS标准有关类型如下:
    
    ●BIT STRING:由0和1任意组成的比特流
         ●IA5String:由IA5(ASCII)字符任意组成的字符流
         ●INTEGER:一个任意的整数
         ●NULL:null值
         ●OBJECT IDENTIFIER:对象识别符,有一列整数构成,用于确定对象,如算法或属性类型
         ●OCTET STRING:任意的octet(8bit值)流
         ●PrintableString:任意可打印字符流
         ●T61String:T.61(8bit)字符的任意流
         ●UTCTime:"coordinated universal time"或者格林威治平均时(GMT)值。

     简单类型分为两类:string类型和non-string类型。BIT STRING, IA5String, OCTET STRING, PrintableString, T61String, 和UTCTime是string类型。

     考虑到编码,String类型可以视为由组件组成,组件是substring。这样即使事先不知道值的长度也可以使用结构化的、不定长的编码方式进行编码(例如,从一个file stream中输入的octet string值)。

     String类型可以指定大小限制,以限制值的长度。
    

2.2 结构化类型(Structured types)


     结构类型由组件组成。ASN.1定义了四种,都与PKCS标准有关:
    
    ●SEQUENCE:一个或多个类型的有序集合
         ●SEQUENCE OF:0个或某个给定类型多次出现的有序集合
         ●SET:一个或多个类型的无序集合
         ●SET OF:0个或某给定类型多次出现的无序集合

     结构类型允许有可选组件。可选组件可能有默认值。
    

2.3 隐式和显式标签类型(Implicitly and explicitly tagged types)


     在一个application中tagging对于区分类型十分有用,tagging通常也用于在一个结构类型中区分组件类型。例如,SET或SEQUENCE类型的可选组件一般都给予不同的context-specific标签以避免混淆。

     有两种方法可以标记一个类型:隐式(implicitly)和显式(explicitly)。
隐式标签类型是在其它类型基础上通过改变其下层类型的标签生成的。隐式标签使用ASN.1关键词[class number] IMPLICIT(见第5.1节)表示。

     显式标签是在其它类型基础上通过在其下层类型的标签之外添加一个外层标签生成的。从效果上看,显式标签类型是包含一个组件的结构类型,该组件即下层类型。显式标签由ASN.1关键词[class number] EXPLICIT(见第5.2节)表示。

     只有关键词[class number]与使用显式标签相同,除非该“模块”的ASN.1类型默认定义为隐式标签。(“模块”属于高级特性,不在本文档描述范围内)

     从编码的角度看,隐式标签类型可视为与下层类型相同,除非标签不同。显式标签类型可视为有一个组件的结构类型,该组件即为下层类型。隐式标签可以使编码较短,但是如果下层类型是不确定的,显式标签必须避免含糊不清(例如下层类型是CHOICE或ANY)。

     ASN.1中的其他类型包括CHOICE和ANY类型。CHOICE类型表示一个联合体,它具有一个或多个备选项(alternative);ANY类型表示任意类型的任意值,其中任意类型可能在使用对象识别符或整数值注册中定义。

3. 基本编码规则(Basic Encoding Rules)
   ASN.1 的基本编码规则定义了一种或多种把任意 ASN.1 值表示成字节字符串的方法,
缩写为BER。 (当然还有其它的方法,但是BER是 OSI中转换这些值的标准)
使用 BER,一个 ASN.1 的值有三种编码方法,选择哪种取决于值的类型和值的长度是
否已知。这三种方法是:简单定长编码,结构化定长编码,及结构化不定长编码。简单的
non-string类型使用第一种(简单定长编码) ;结构化类型可使用任一种结构化的编码方法;
简单的string类型根据值的长度是否已知可使用任一种方法。隐式标签定义的类型可使用下
层类型的方法,显式标签定义的类型使用结构化的编码方法。
每种BER编码方法都有三或四部分:
Identifier octets:定义了ASN.1 值的类和标签值, 指明编码方法是简单的还是结构化
的。
Length octets:对于定长编码方法,它指出了内容字节个数;对于结构化非定长编
码方法,它指明长度是不确定的。
Contents octets:对于简单定长编码方法,它给出了值的具体表示;对于结构化的
方法,它给出了值内容的BER编码的串联。
End-of-contents octets:对于结构化非定长的编码方法,它表示内容结束;对于其
它方法,没有该部分。
在下面的章节中介绍了这三种编码方法。

3.1 简单定长方法(Primitive, definite-length method

这种方法用于简单类型及通过对简单类型使用隐式标签生成的类型。 它要求值的长度是
事先预知的。BER编码的部分定义如下:
1. Identifier octets,有两种形式:较小的标签值(标签值在0 和30之间)和较大的标
签值(标签值大于等于31)
Low-tag-number form:一个字节。Bit8和bit7表示类(如表2),bit6值为0,表示
编码方法为简单化的。Bit5-1给出了标签值。


Class Bit 8 Bit 7
universal 0 0  
application 0 1
context-specific 1 0
private 1 1
High-tag-number form:两个或多个octet。第一个octet形式如low-tag-number
form,但是bit5-1均为1。第二个和以后的字节给出标签值,基于128,最高位在
先,以便使用尽可能少的数字,除了最后一个字节以外,每个字节的bit 8都置为1。
最后一个字节的为0。

2. Length octets: 有两种格式: 短型 (长度在0至127之间) 和长型 (长度在0至21008−1
之间)
Short form: 一个字节,bit8为0,bit 7-1表示长度。
Long form: 2-127个字节。第一个字节的Bit 8为1,bit 7-1表示后面有多少个用于
表示实际长度的octet。第二个和随后的octet给出实际长度,基于256,高位数字在
先。

3. Contents octets:给出了值的具体表示(如果类型是由隐式标签定义的,则给出了
下层类型的值) ,特定类型的细节详见第5节。

3.2 结构化定长方法(Constructed, definite-length method)

结构化定长方法适用于简单的string类型、结构类型、在二者基础上通过隐式标签生成
的类型和在任何类型基础上由显式标签生成的类型。要求值的长度事先已知。BER 编码方
法各部分如下:
1. Identifier octets:与第 3.1 节介绍的一样,但bit6的值为 1,表示编码方法是结构化
的。
2. Length octets:见第3.1节。
3. Contents octets,值的组件的BER编码的串联
对于简单string类型和在其基础上由隐式标签生成的类型,是值的连续子串的
BER编码的串联(隐式标签的下层值)
对于结构类型和在其基础上由隐式标签生成的类型,是值的组件的BER编码的
串联(隐式标签的下层值)
对于在任何类型基础上使用显式标签生成的类型,是下层值的BER编码
特定类型的细节见第5节。

3.3 结构化非定长方法(Constructed, indefinite-length method)

结构化的、非定长编码用于简单string类型、结构类型、在二者基础上使用隐式标签生
成的类型和在任何类型基础上使用显式标签生成的类型。不要求事先知道值的长度。BER
编码各部分如下:
Identifier octets,见第3.2节
Length octets.一个字节,值为80
Contents octets.见第 3.2节。
End-of-contents octets两个字节,为00   00。

由于end-of-contents octet通常出现在普通BER编码出现的位置 (例如, 在一个 sequence
值的内容 octet 出现的位置) ,可把 00 和 00 分别视为 identifier 和 length octet。因此
end-of-contents octet实际上是一个具有universal class,标签值为0,长度为0 的值的简单定
长编码。

4. Distinguished Encoding Rules(DER,可辨别编码规则)

DER是BER的子集,它定义了使用一个octet string来表示任何ASN.1 值的编码方法。
DER用于需要使用唯一的octet string编码的应用程序,例如根据一个 ASN.1 编码来计算数
字签名。DER在X.509 的第8.7 节定义。

DER在第 3节给出的规则基础上增加了如下限制:

1. 如果长度在0-127之间,必须使用短型长度表示法。
2. 如果长度大于等于 128,必须使用长型长度表示法。并且长度必须使用尽可能少的
字节表示。
3. 对于简单 string类型和在其基础上使用隐式标签生成的类型,必须使用简单定长编
码方法。
4. 对于结构化类型和在其基础上使用隐式标签生成的类型、及在任何类型基础上使用
显式标签生成的类型,必须使用结构化定长编码方法。
对于特殊类型(如BIT STRING、SEQUENCE、SET 和 SET OF)的其他限制见第5 节。

5. 某些类型的符号和编码

本节给出了部分 ASN.1 类型的符号,并介绍了如何使用 BER 和 DER 对这些类型进行
编码。
这里介绍的类型是第2 节提到的,按字母顺序列在下面。
每个介绍包括ASN.1 符号、BER编码和DER编码。编码的重点主要在内容字节上,标
签和长度字节遵循第3、4节的介绍。介绍还解释了每种类型用在PKCS中何处及相关的标
准。ASN.1 符号主要是针对类型的,但还是针对OBJECT IDENTIFIER给出了类型符号和值
符号。

5.1 隐式标签类型

隐式标签类型是在其他类型基础上通过改变下层类型的标签生成的类型。
隐式标签在整个 PKCS 中用于可选的 SEQUENCE 组件,其下层类型是除 ANY 以外的
任何类型。也用于PKCS #7的ExtendedCertificateOrCertificate类型的 extendedCertificate备
选项。
ASN.1 表示法:
[[class] number] IMPLICIT Type
class = UNIVERSAL | APPLICATION | PRIVATE
其中,Type 是类型,class 是可选的 class 名,number 是类内的标签值,是一个非负整
数。
在默认标签方法为隐式标签的ASN.1 模块中,也可以使用[[class] number] Type 符号,
关键词 IMPLICIT 是隐含的(见第 2.3 节) 。在模块以外的地方进行定义声明,最好使用关键词IMPLICIT以避免语义含混。
如果没有 class 名称,则标签为 context-specific 类。context-specific 类
型的标签只能出现在结构类型或CHOICE类型的组件中。
例:PKCS #8的 PrivateKeyInfo类型有一个可选的attributes组件,具有一个
隐式的、context-specific标签:
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
privateKey PrivateKey,
attributes [0] IMPLICIT Attributes OPTIONAL }
这里,下层类型为Attributes,class是缺省的(即context-specific类),在
这个类内的标签值为0。
BER encoding:根据下层类型可以采用简单化的或结构化的编码。内容字节与下层值
的BER编码有关。

例:一个PrivateKeyInfo值的attributes组件的BER编码如下:

如果下层的Attributes值采用简单化的BER编码(bit 6为0),则identifier
octet为80;如果采用结构化的编码(bit 6为1),则identifier octet为
a0。
z length和content octet分别与下层Attributes值的BER编码的相同。
DER encoding: 根据下层类型选择简单或结构化编码方法。Content octet与下层值的
DER编码有关。

5.2 显式标签类型


显示标签通过在一个类型的外层增加一个标签可以生成一个新的类型。
在整个 PKCS 中,显式标签用于下层类型为 ANY 的、可选的 SEQUENCE 类型组件,
及 X.509的Certificate类型的version组件。

ASN.1 表示法:
[[class] number] EXPLICIT Type
class = UNIVERSAL | APPLICATION | PRIVATE

Type 表示类型,class 是一个可选的类名,number 是一个非负整数,表示在类内的标
签值。
如果没有类名,则标签为 context-specific 类。Context-specific 类标签只能出现在
SEQUENCE、SET或CHOICE 类型的组件中。
在默认标签方法为显式标签的ASN.1 模块中,也可以使用 [[class] number] Type 符号,
关键词EXPLICIT是隐含的(见第2.3节) 。在模块以外的地方进行定义声明,最好显式写
明关键词EXPLICIT 以避免语义不清。
例: PKCS #7 中的 ContentInfo类型有一个可选的content组件, 具有一个显式的、
context-specific类的标签:
ContentInfo ::= SEQUENCE {
contentType ContentType,
content
    [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
这里下层的类型为 ANY DEFINED BY contentType,类名省略了(即为
context-specific类) ,类内的标签值为0。

例 2: X.509 的 Certificate类型有一个 version 组件, 具有显式的context-specific
类标签,其EXPLICIT 关键词省略了:
Certificate ::= ...
version [0] Version DEFAULT v1988,
...
这个标签是显式的,因为在X.509 中, ASN.1 模块的默认标签方法定义Certificate
类型为显式标签。

BER encoding. 结构化编码。Contents octets与下层值的BER编码有关。

例:ContentInfo 值的content 组件的BER 编码如下:
identifier octets为a0
length octets为下层ANY DEFINED BY contentType值的BER编码长

contents octets为下层ANY DEFINED BY contentType值的BER编码
DER encoding. 结构化编码。Contents octets与下层值的BER编码有关。

5.3 ANY

ANY类型用于表示任意类型的一个任意值, 其中任意类型可能在对象描述符的注册中定
义,或与一个整数值相关。
ANY 类型用于 PKCS #7 中的 ContentInfo 类型中特定的 content 值,或 X.509's
AlgorithmIdentifier 类型中特定算法的参数,或 X.501 中 Attribute 类型和
AttributeValueAssertion类型的属性值。Attribute类型广泛应用在PKCS #6, #7,
#8, #9 and #10中,AttributeValueAssertion类型用于 X.501 DN 中。

ASN.1 表示法:

ANY [DEFINED BY identifier]

这里identifier 是可选的识别符。

在ANY形式下,实际的类型是不确定的。
ANY DEFINED BY identifier 形式只能出现在SEQUENCE或 SET类型的组件中,对于
这些组件identifier 定义了一些其他的组件,其类型为INTEGER或 OBJECT IDENTIFIER
(或者是在这两者基础上添加标签生成的类型) 。这种形式下,实际的类型由其他组件的值
决定,其他组件的值可能由对象描述符注册也可能在一个整数表里。

例:X.509的AlgorithmIdentifier类型有一个 ANY类型的组件:
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
这里parameter组件的实际类型由algorithm组件的值决定。 实际类型在组件的对
象描述符的注册中定义。

BER encoding. 与实际值的BER编码相同。
例: parameter 组件的 BER 编码值是实际类型值的 BER 编码。实际类型在
algorithm组件的对象描述符值的注册中定义。
DER encoding. 与实际值的DER编码相同。

5.4 BIT STRING

BIT STRING类型表示任意的0和 1的比特流。一个BIT STRING值的长度可以是任
意值,包括0。该类型为string类型。
BIT STRING 类型用于 PKCS #6 ExtendedCertificate 类型中的 extended
certificates 的 digital signatures,或 X.509 Certificate 类型的 certificates 的 digital
signatures,或X.509 SubjectPublicKeyInfo类型的 certificates的public keys。

ASN.1 表示法:

BIT STRING

例:X.509的SubjectPublicKeyInfo 类型有一个BIT STRING类型的组件:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
publicKey BIT STRING }

BER encoding. 简单或结构化的编码。在简单编码中,第一个内容字节指出了该 bit
string 凑成 8 的倍数所缺少的 bit 数(这些 bit 称为无用的比特) 。第二个和随后的内容字节
指出了转换成字节字符串的bit string的值。转换过程如下:

1. 在 bit string的结尾填充0 至7个任意值的比特,使整个bit string的长度是8的倍
数。如果比特流的长度已经是8 的倍数,则不需要填充
2. 填充后的比特流被分成octet。前八个 bit作为第一个octet,分别为 bit8至 bit1;这
样一直分割下去,直到最后8个bit组成 octet。

在结构化编码中,contents octets是bit string连续子串的BER编码的串联。除了最后一
个子串,每个子串都是8bit的整数倍。
例: BIT STRING "011011100101110111"的BER编码可以是下列任意一种,区别在于
填充比特的选择、长度字节的格式、及编码是简单还是结构化的。
03 04 06 6e 5d c0
DER encoding
03 04 06 6e 5d e0 padded with "100000"
03 81 04 06 6e 5d c0 long form of length octets
23 09 constructed encoding: "0110111001011101" + "11"
   03 03 00 6e 5d
   03 02 06 c0
DER encoding. 简单编码。内容字节与BER简单编码类似,只是填充比特全部为0 bit。
例: BIT STRING 的"011011100101110111" DER编码为:
03 04 06 6e 5d c0

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)