JR精品文章 - ASN.1/BER/DER编码子集入门指南
ASN.1/BER/DER编码子集入门指南(一)
RSA实验室技术笔记
作者:Burton S.Kaliski Jr.
最终修订日期:Nov 1,1993
翻译:David(David@javaresearch.org),2002年6月ASN.1/BER/DER编码子集入门指南
摘要:本 笔记提供了关于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的高级特点(例如宏),因为ASN.1/BER/DER编码子集入门指南ASN.1/BER/DER编码子集入门指南它们在实现PKCS时并不必要。关于其它特征和更多细节,请读者参考CCITT的建议文档:X.208、X.209,这两份文档中定义了ASN.1和BER。
术语和表示法 本笔记中,字节指8位无符号整数,第8位最重要,而第1位最不重要。以下表示法将用来表示ASN.1标记:
BIT 用等宽在类型和值标记中表示文本字符;例如,它表示十六进制中的一个字节值。
[i]n1[/i] 宽体斜体表示一个变量
[ ] 方括号表示一个条款是可选的
{ } 大括号表示相关条款
| 竖条表示可以在一组值中任选
... 省略号表示多次重复
= 等号表示条目由一些子条目来表达。
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值表示成octet string的方法,缩写为BER。(当然还有其它的方法,但是BER是OSI中转换这些值的标准)
使用BER,一个ASN.1的值有三种编码方法,选择哪种取决于值的类型和值的长度是否已知。这三种方法是:基本的,定长编码;结构化的,定长编码;及, 结构化的,不定长编码。简单的non-string类型使用第一种(简单、定长编码);结构类型可使用任一种结构化的编码方法;简单的string类型根 据值的长度是否已知可使用任一种方法。隐式标签定义的类型可使用下层类型的方法,显式标签定义的类型使用结构化的编码方法。
每种BER编码方法都有三或四部分:
- ●Identifier octets:定义了ASN.1值的类和标签值,指明编码方法是简单化的还是结构化的。
●Length octets:对于定长编码方法,它指出了内容octet的个数;对于结构化、非定长编码方法,它指名长度是不确定的。
●Contents octets:对于简单的、定长编码方法,它给出了值的具体表示;对于结构化的方法,它给出了值的内容的BER编码的串联。
●End-of-contents octets:对于结构化、非定长的编码方法,它表示内容结束;对于其它方法,没有该部分。
在下面的章节中介绍了这三种编码方法。
3.1、简单定长方法(Primitive, definite-length method)
这种方法用于简单类型及通过对简单类型使用隐式标签生成的类型。它要求值的长度是事先预知的。BER编码的部分定义如下:
1.Identifier octets,有两种形式:较小的标签值(标签值在0和30之间)和较大的标签值(标签值大于等于31)
- ●Low-tag-number form:一个octet。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。第 二个和以后的octet给出标签值,基于128,最高位在先,以便使用尽可能少的数字,每个octet的bit8都置为1,最后一个为0。
2.Length octets:有两种格式:短型(长度在0至127之间)和长型(长度在0至21008-1之间)
- ●Short form: 一个octet,bit8为0,bit7-1表示长度。
●Long form: 2-127个octet。第一个octet的Bit8为1,bit7-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.一个octet,值为80
●Contents octets.见第3.2节。
●End-of-contents octets两个octet,为00 00。
由于end-of-contents octet出现在通常普通BER编码出现的位置(例如,在一个sequence值的内容octet出现的位置),可 把00和00分别视为identifier和length octet。因此end-of-contents octet实际上是一个具有 universal class,标签值为0,长度为0的值的简单定长编码。
关于更多,请参见:
ASN.1/BER/DER编码子集入门指南