译者对自认为翻译可能不够准确的地方附上了原文,如有错误,请读者不吝评论斧正。
本笔记对 OSI 的抽象语法标记1 (Abstract Syntax Notation One,ASN.1)、基本编码规则 (Basic Encoding Rules,BER) 和可分辨编码规则 (Distinguished Encoding Rules,DER) 的子集进行入门介绍,目的是提供足够的背景知识以便让外行人都能够理解和实施 PKCS 系列标准。
“软件开发管理的关键是抽象”是一个广为大众所接受的设计原则。通过抽象,设计者可以描述/定义系统的某个部分,而无需关注该部分实际是如何实现和表示的。 这种做法的优势如下:
因此,抽象是大多数现代软件标准规范的特点之一。
现今最复杂的系统之一,开放系统互联(Open System Interconnection,OSI,在X.200标准规范中描述),就涉及了大量的抽象。OSI 是一种国际标准化体系架构,用于管理计算机从物理层到应用层的互联。在OSI中,较高层抽象定义的对象旨在通过较低层的对象来实现。例如,某层的服务可能需要在计算机之间传输某些抽象对象;此时较低层可能是通过编码将抽象对象转换成01串,并为01串提供传输服务,进而实现对上层抽象对象的传输。OSI 之所以被称为开放系统是因为对各层的服务它支持多种不同的实现方式。
OSI 中用于描述/定义抽象对象的方法称为 ASN.1(Abstract Syntax Notation One,在 X.208标准规范中定义),用于将这些对象表示为 01串的一组规则称为 BER(Basic Encoding Rules,在 X.209 中定义)。 ASN.1 是一种灵活的表示法,它允许定义各种数据类型,从简单类型(如整数和位串)到结构化类型(如集合和序列)以及根据其他类型定义的复杂类型。 BER描述了如何将每个ASN.1类型的值表示或编码为一串八位组。 对于相同的ASN.1值,通常有不止一种方法可以对其进行 BER 编码。 另一组规则称为可分辨编码规则 (DER),它是 BER 的子集,能够为每个 ASN.1值提供唯一编码。
这份笔记的目的是描述ASN.1、BER和DER的一个子集,该子集涉及的内容足以让人能够理解和实现RSA Data Security公司的公钥加密标准(这是一个基于OSI的应用)。本文的内容包括 对ASN.1、BER、DER的一个概述 和 经删减的ASN.1类型及对应的BER、DER编码。本文2~4节依序给出ASN.1、BER和DER的概述,第5节罗列了一些ASN.1类型,并给出它们的符号表示、特定的编码规则、示例和本文对它们在PKCS中的应用的点评。第6节使用一个X.500可分辨名称(X.500 distinguished names)示例作为总结。
ASN.1 的高级特征(例如宏)未在本笔记中描述,因为它们不是实现 PKCS 所必需的。 有关ASN.1的其他功能的信息以及更详细的一般信息,请参阅定义 ASN.1 和 BER 的 CCITT 建议 X.208 和 X.209(译者注:截至译者翻译本文时,ASN.1的最新标准规范是X.680,BER、而DER的最新标准规范是X.690)。
在这份笔记中,八位组是指一个8位的无符号整数,其中的位8权重最高,位1权重最低。此外,ASN.1符号将使用到如下的记号说明:
符号 | 含义 |
---|---|
BIT |
等宽字体表示类型和值的字面意义上的字符表示; 在示例中,它通常表示十六进制的八位组值 |
n1 | 粗斜体表示一个变量 |
[] | 粗方括号指示该项是可选的 |
{} | 粗花括号聚合相关项 |
| | 粗竖线分隔某个组内的备选项 |
… | 粗省略号表示重复出现 |
= | 粗等号将术语用子术语表示 |
ASN.1是用于描述抽象类型和值的一种符号表示法。
在ASN.1中,类型表示一组值的集合。某些类型具有有限数量的值,而某些其他类型具有无限多的值。给定ASN.1类型的某个值是该类型中的一个元素。ASN.1有四种类型:
类型和值可以使用ASN.1的分配操作符(::=)赋予名字,这些名字进而可以用于定义其他类型和值。
除了CHOICE和ANY之外的每个类型都具有一个标签(tag),这个标签由一个类别(class)和一个非负的标签号码(a nonnegative tag number)组成。当且仅当标签号码相同的情况下,ASN.1类型在抽象意义上是相同的。换句话说,ASN.1类型的名字并不能影响其抽象含义,只有标签可以。标签有如下四个类别:
X.208定义了带通用标签的类型,并给出了这些类型的通用标签号码(universal tag number)。带其他标签的类型在很多地方定义,并且通常通过隐式或者显式的标签获得(参见2.3节)。表1列出了一些ASN.1类型以及它们的通用类标签。
Type(类型) | Tag number (十进制表示的标签号码) | Tag number (十六进制表示的标签号码) |
---|---|---|
INTEGER |
2 | 02 |
BIT STRING |
3 | 03 |
OCTET STRING |
4 | 04 |
NULL |
5 | 05 |
OBJECT IDENTIFIER |
6 | 06 |
SEQUENCE 与 SEQUENCE OF |
16 | 10 |
SET 与 SET OF |
17 | 11 |
PrintableString |
19 | 13 |
T61String |
20 | 14 |
IA5String |
22 | 16 |
UTCTime |
23 | 17 |
Table 1. 一些类型以及它们的通用类标签号码
ASN.1 类型和值用一种灵活的、类似于编程语言的符号来表示,其具有如下的特殊规则:
下文分四个小节分别概述简单类型、结构类型、隐式及显式标记类型和其他类型,第5节将更具体地描述具体的类型。
简单类型是那些不包含组件的类型; 它们是“原子”类型。 ASN.1 所定义的类型中与 PKCS 标准相关的如下:
BIT STRING
:一个任意的由0和1构成的位串IA5String
:一个任意的IA5(ASCII)字符串Integer
:一个任意的整数NULL
:一个空值OBJECT IDENTIFIER
:一个对象标志符,它是一个整数序列,用于识别一个对象,如某个算法或者某个属性类型。OCTET STRING
:一个任意的八位组(八位的值)串PrintableString
:一个任意的可打印字符串T61String
:一个任意的T.61(八位)字符串UTCTime
:一个协调世界时间或者格林威治标准时间(GMT)值简单类型整体上可划分为两个大类:string类型和非String类型。BIT STRING
、IA5String
、OCTET STRING
、PrintableString
、T61String
和UTCTime
均是string类型。
出于编码目的,string类型是可视为由组件构成的,其组件为字串。因此,这使得人们可以对长度无法预知的值(如从文件流中输入的八位组串)使用结构化的、不定长的编码方式。
对于string类型,可以给出大小限制,以限制值的长度。
结构类型是由组件构成的类型。ASN.1定义了4种结构类型(都与PKCS标准相关):
SEQUENCE
:由一种或者多种类型组成的有序集合;SEQUENCE OF
:由给定类型的一次或者多次出现构成的有序集合;SET
:一个一种或者多种类型构成的无序集合;SET OF
:由给定类型的一次或者多次出现构成的无序集合。结构类型可以包含可选组件,这些可选组件可能具有默认值。
标记有利于在某个应用内进行类型区分;它也常用在某个结构类型中,用以区分组件类型。例如SET
或者SEQUENCE
类型中的可选组件通常会被赋予不同的上下文标签(context-specific tag)来避免混淆。
有两种标记一个类型的方式:隐式或者显式。
隐式标记类型是通过改变其基础类型标签来从其他类型中导出的类型(原文:Implicitly tagged types are derived from other types by changing the tag of the underlying type.)。隐式标记用ASN.1关键词[class number] IMPLICIT
指示(见5.1节)。
显式标记类型是通过给其基础类型标签添加一个外层标签来从其他类型中导出的类型(原文:Explicitly tagged types are derived from other types by adding an outer tag to the underlying type.)。在最终效果上,直接标记类型是由一个组件,即基础类型,构成的结构类型。直接标记用ASN.1关键词[class number] EXPLICIT
指示(见5.2节) 。
关键词[class number]本身与显式标记一样,除了当ASN.1类型定义所在的模块(module,“模块”)默认使用隐式标记的情况之外。(模块是本笔记所未涉及的高级特征。)
出于编码目的,隐式标记的类型除了标签不一样之外,被认为与其基础类型相同;显式标记类型被认为是只含一个组件(即其基础类型)的结构类型。隐式标签可以使得编码长度更短,但是在其基础类型不确定(如,基础类型是CHOICE
或ANY
)这种需要避免混淆的场景下显式标签是必需的。
ASN.1中其他类型包括CHOICE
和ANY
两种类型。CHOICE
类型表示具有一个或者多个备选项的一个联合体(union);ANY
类型表示一个任意的值或者任意类型,这里所说的任意类型可能在一个对象标识符或者整型值的注册阶段被定义。
ASN.1的BER给出一种或者多种方法将ASN.1值表示为一个八位组串。(当然,也有其他的方式来表示ASN.1 值,但BER是OSI中用于交换这些ASN.1值的标准。)
在BER下,有三种方法可以用于编码ASN.1值,对方法的选择取决于值的类型以及值的长度是否可以预知。这三种方法分别是:
简单的非string类型使用原始的定长编码方法;结构类型使用任一种结构化的编码方法;简单的string类型可以根据值长度是否已知使用上述任一种编码方法。
由隐式标记导出的类型使用其基础类型的编码方法;由显式标记导出的类型使用结构化的编码方法。
在每种方法中,BER编码三个或者四个部分:
上述的三种编码方式将在以下的章节中描述。
这种方法应用于简单类型以及由隐式标记从简单类型导出的类型。这种编码方法要求值的长度是可以预先得知的。这部分的BER编码如下:
标志符八位组(Identifier octets):分两种情况:低标签号码(对于从0~30的号码值)和高标签号码值(对于31或者更大的标签号码值)。
低标签号码编码:占一个八位组。位8 和 位7 指定标签类别,位6的值为“0”,指示使用的是原始编码方法,位5-1给出标签号码。
Class | Bit 8 | Bit 7 |
---|---|---|
通用标签(universal) | 0 | 0 |
应用标签(application) | 0 | 1 |
上下文标签(context-specific) | 1 | 0 |
私有标签(private) | 1 | 1 |
Table 2. 标志符八位组中的标签类别编码
高标签号码编码:占两个或者更多八位组。第一个八位组除了位5-1全取值为“1”之外,使用低标签号码编码形式。第二个以及随后的八位组给出以128为基的标签号码,首先是权重最高的数字,接着是尽可能少的数字,这些八位组除了最后一个之外其他的八位组的位8均取值为“1”。
长度八位组(Length octets):分两种情况:短长度(对于从0~127的长度)以及长长度(对于0~2^1008-1之间的长度)。
内容八位组(content octets):这部分给出值(或者基础类型的值,如果该类型是由隐式标记推导出来的的话)的具体表示。特定类型的细节将在后面的第5节给出。
这种方法应用于简单的string类型、结构类型、由隐式标记从简单string类型及结构类型导出的类型、由显式标记从任意类型导出的类型。这种编码方法要求值长度是可以预先得知的。这部分的BER编码如下:
标志符八位组:同3.1节,除位6取值为“1”用以指示使用的是结构化的编码;
长度八位组:同3.1节;
内容八位组:组件值的BER编码的级联:
特定类型的细节将在第5节给出。
这种方法用于简单的string类型、结构类型、由隐式标记从简单string类型和结构类型导出的类型、由显式标记从任何类型导出的类型。这种方法不需要预先知道值的长度。这部分的编码如下:
标志符八位组:同3.2节;
长度八位组:占一个八位组,取值为80
;
内容八位组:同3.2节;
结束标志八位组(End-of-content octets):占两个字节00 00
;
鉴于内容结束标志八位组可能出现在一个预期是正常BER编码的地方(如sequence value的内容八位组中),即00
和00
分别是标识符和长度八位组,因而内容结束标志八位组实际上是一个带通用类别、标签号码为0、长度为0的值的原始定长编码。
ASN.1 的可分辨编码规则(Distinguished Encoding Rules,DER)是 BER 的一个子集,它只提供了一种将ASN.1 值表示为八位组串的方法,适用于要求唯一编码的应用场景,如需要在 ASN.1 值上计算数字签名的情况。 DER 在 X.509 的第 8.7 节中定义。
DER在第3节的基础上添加了如下约束:
其他对特定类型(例如BIT STRING
、SEQUENCE
、SET
和SET OF
)的约束将在第五节被定义。
本节给出了一些 ASN.1 类型的表示法,并描述了如何使用 BER 和 DER 对这些类型的值进行编码。
本节所述的类型即在第2节所展示的类型,本节将按字母序依次对它们进行介绍。
每部分的描述覆盖所述类型的ASN.1表示法、BER编码和DER编码。编码描述的重点将放在内容八位组的编码上,标签(tag)和长度八位组的编码遵循第3和第4节所述的规则。下文也解释了每种类型在 PKCS 和相关标准中的使用位置。 ASN.1 表示法通常仅用于类型,但对于 OBJECT IDENTIFIER
类型,也给出了值表示法。
隐式标记类型 是 通过改变基础类型标签 从其他类型导出的类型。
隐式标记被用在PCKS全文里SEQUENCE
中的基础类型是非ANY
类型的可选组件上,以及在PKCS #7中ExtendedCertificateOrCertificate类型的extendedCertificate备选项上。
[[class]number] IMPLICIT
Type
class=UNIVERSAL
|APPLICATION
|PRIVATE
这里的Type表示类型,class是一个可选的标签类别,number是在该类别内的标签号码,是一个非负的整数。
在默认标记方法为隐式标记的ASN.1“模块”中,表示法[[class]number] Type也是可接受的,这里隐含了IMPLICIT
关键词。(见2.3节)对于在模块外部声明的定义,推荐明确包含关键字 IMPLICIT
以防造成歧义。
如果类别名称缺失,则该标签是上下文类标签。上下文标签仅允许出现在结构类型或者SET
类型的组件上。
例如:PKCS #8的PrivateKeyInfo
类型包含一个可选的attribute
组件,该组件的标签是隐式上下文类的。
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
privateKey PrivateKey,
attributes [0] IMPLICIT Attributes OPTIONAL }
这里attributes
基础类型是Attributes
,class缺失(也就是说,它的标签是上下文类的),在该标签类别中,其标签号码为0。
根据基础类型的不同使用原始的或结构化的编码,内容八位组与其底层值经BER编码后的结果相同。
例如:某个PrivateKeyInfo
值中的attribute
组件的BER编码如下:
Attributes
值使用的是原始的BER编码,则标识符八位组取值为80
;如果底层Attributes
值使用的是结构化的BER编码,则取值为A0
;Attributes
值的长度和内容值经BER编码后的八位组。根据基础类型的不同使用原始的或结构化的编码。内容八位组与其底层值经DER编码后的结果一致。
显式标记类型 是指 通过给基础类型添加一个外层的标签 来从其他类型导出的类型。
显式标记被用在PKCS全文里SEQUENCE
中除ANY
之外的类型的可选组件上,以及在X.509的Certificate
类型中的version
组件上。
[[class]number] EXPLICIT
Type
class=UNIVERSAL
|APPLICATION
|PRIVATE
这里的Type表示类型,class是一个可选的标签类别,number是在该类别内的标签号码,是一个非负的整数。
如果类别名称缺失,则该标签是上下文类标签。上下文标签仅允许出现在SEQUENCE
、SET
或者CHOICE
类型的组件上。
在默认标记方法是显式标记的ASN.1“模块”中,表示法[[class]number] Type也是可接受的,这里隐含了EXPLICIT
关键词。(见2.3节)对于在模块外部声明的定义,推荐明确包含关键字 EXPLICIT
以防造成歧义。
例1:PKCS #7的ContentInfo
类型中包含一个可选的content
组件,该组件的标签是显式上下文类的:
ContentInfo ::= SEQUENCE {
contentType ContentType,
content
[0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
这里,基础类型是ANY DEFINED BY contentType
,标签类别class缺失(即,它是上下文类型的),在该标签类别中,此类型的标签号码是0。
例2:X.509中Certificate
类型中包含一个带显式上下文类标签的version
组件,它的EXPLICIT
关键词被省略:
Certificate ::= ...
version [0] Version DEFAULT v1988,
...
上述Version
类型的标签是显式的,因为X.509中定义了Certificate
类型的ASN.1“模块”的默认标记方法是显式标记。
使用的是结构化的编码方法。内容八位组是经BER编码的底层值。
例如:对某个ContentInfo
类型值中content
组件的编码为:
A0
ANY DEFINED BY contentType
值经BER编码后的结果的长度ANY DEFINED BY contentType
值经BER编码后的结果使用的是结构化的编码。内容八位组是底层值经DER编码后的结果。
ANY
类型表示任意某个类型的任意某个值,其中具体的类型可能在对象标识符或者某个关联的整数索引被注册时定义。
ANY
类型出现在PKCS #7 ContentInfo
类型中代表某个特定的content
类型的内容,在X.509 AlgorithmIdentifier
类型中代表某个特定的算法的参数,在X.501 Attribute
和AttributeValueAssertion
类型中代表属性值。 Attribute
类型在PKCS #6,#7,#8,#9 和 #10被用到,而AttributeValueAssertion
类型在X.501 的可分辨名称中被用到。
ANY
[DEFINED BY identifier]
这里的identifier是一个可选的标识符。在使用ANY
形式时,实际的类型是不确定的。
ANY
DEFINED BY identifier 这种形式只能出现在SEQUENCE
或SET
类型的某个组件内,其中identifier 是这个SEQUENCE
或SET
类型中的其他组件,其类型是INTERGER
、OBJECT IDENTIFIER
或者由这两者之一导出的标记类型。在这种形式下,ANY
所代表的实际类型 要么是对象标识符值注册时,要么是在列表中的整数值注册时 由其他组件的值确定。
例如:X.509的AlgorithmIdentifier
类型定义了一个ANY
类型的组件:
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
这里,parameter
组件的实际类型取决于algorithm
组件的值,实际的类型将在注册algorithm
组件对应的对象标识符值时被定义。
与实际值的BER编码一致。
例如:parameter
组件的值的BER编码 即为 algorithm
组件对应的对象标识符的注册值所定义的实际类型的值的BER编码。
与实际值的BER编码一致。
BIT STRING
类型表示一个任意的0和1构成的位串。一个BIT STRING
值可以是任意长度的,包括0。这个类型是一个string类型。
BIT STRING
类型被用在PKCS #6 ExtendedCertificate
类型extendedCertificate
所包含的数字签名、X.509 Certificate
类型certificate
所包含的数字签名和X.509 SubjectPublicKeyInfo
类型所包含的公钥上。
BIT STRING
例如:X.509 SubjectPublicKeyInfo
类型中包含了一个BIT STRING
类型的组件:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
publicKey BIT STRING }
BIT STRING
使用原始的或者结构化的编码。
在使用原始的编码的情况下,第一个内容八位组给出该串的实际位长度要凑成8的倍数所欠缺的位数量(亦即,未使用的位的数量);而后续的八位组给出被转换成八位组串的位串值。转换过程如下:
在使用结构化的编码的情况下,内容八位组给出位串所包含的子串的BER编码的级联,其中除了最后一个子串之外,每个子串的长度都必需是8位的整数倍。
例如:根据填充的位值、长度编码和编码方式(原始的或结构化的)的不同选择,BIT STRING
值“0110 1110 0101 1101 11”的BER编码可以如下的任一种:
03 04 06 6e 5d c0
03 04 06 6e 5d e0
03 81 04 06 6e 5d c0
23 09
03 03 00 6e 5d
03 02 06 c0
使用原始的编码方式,除了位串填充值是0值之外,内容八位组跟原始BER编码是一样的。
例如:BIT STRING
值“0110 1110 0101 1101 11”的DER编码为:
03 04 06 6e 5d c0
CHOICE
类型表示一个或者多个备选项的联合。
在PKCS #7 ExtendedCertificateOrCertificate
类型中,CHOICE
类型被用于表示一个扩展证书和一个X.509证书构成的联合。
CHOICE
{
[identifier1] Type1,
…,
[identifier_n] Typen }
其中,identifier1,…,identifiern 是可选的(不同的备选项使用不同的标识符identifier),Type1,…,Typen是可供选择的备选类型。标识符主要用于文档;它们不会以任何方式影响类型的值或其编码。
联合中的类型必需具备不同的标签,这个要求通常可以通过对某些备选项添加显式或者隐式标记得到满足。
例如:PKCS #7中ExtendedCertificateOrCertificate
类型是一个联合类型:
ExtendedCertificateOrCertificate ::= CHOICE {
certificate Certificate, -- X.509
extendedCertificate [0] IMPLICIT ExtendedCertificate
}
这里备选项的标识符分别是certificate
和extendedCertificate
,备选项的类型则是Certificate
和[0] IMPLICIT ExtendedCertificate
。
与被选择的备选项的BER编码一致。备选项具备不同的标签 使得 可以将它们的BER编码区分开。。
例如:如果被选择的是certificate
,其标识符八位组的BER编码为30
;如果被选择的extendedCertificate
,其标识符八位组的编码为A0
。
与被选择的备选项的DER编码一致。
IA5String
类型表示由IA5字符构成的任意字符串。IA5 代表 International Alphabet 5,与 ASCII 相同。 字符集包括无法打印的控制字符。 IA5String 值的长度可以是任何值,包括零。 该类型是string类型。
IA5String
类型被用在PKCS #9 电子邮箱地址、无结构名字和无结构地址属性中。
IA5String
这种类型可以使用原始的或者结构的编码。在原始编码中,内容八位组给出IA5字符串所包含经ACSII编码的字符;在结构化编码中,内容八位组给出IA5字符串的连续子串的BER编码的级联。
例如:根据长度编码和编码方式(原始的或结构化的)的选择的不同,IA5String
类型值“[email protected]"的BER编码可以是如下的任何一种:
16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d
16 81 0d
74 65 73 74 31 40 72 73 61 2e 63 6f 6d
36 13
16 05 74 65 73 74 31
16 01 40
16 07 72 73 61 2e 63 6f 6d
使用原始的编码方式。内容八位组即为使用原始BER编码的结果。
例如:IA5String
值"[email protected]"的DER编码为:
16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d
INTERGER
表示一个任意的整数。INTERGER
的值可以是正数、负数或者零,并可以是任何量级。
INTERGER
在PKCS中被用于指示版本号(version
number),在PKCS #1 的RSAPublicKey
和RSAPrivateKey
类型 以及 PKCS #3的DHParameter
类型中指示模值、指数和素数之类的密码学参数,在PKCS #5的PBEParameter
类型中指示一个消息摘要的迭代次数,在X.509 Certificate
类型中指示版本号和序列号。
INTEGER
[{ identifier1(value1) … identifiern(valuen) }]
这里identifier1,…,identifiern是可选的互不相同的识别码,value1,…,valuen是可选的整数值。识别符如果存在的话,它是与该整数值相关联的。
例如:X.509的Version类型是一个带有识别码的INTERGER
类型:
Version ::= INTEGER { v1988(0) }
识别码v1988
与值0关联。X.509 Certificate
类型使用识别码v1988
来给version组件赋予一个默认值0:
Certificate ::= ...
version Version DEFAULT v1988,
...
使用原始的编码方式。内容八位组给出以256为基、权重最高的数字优先、补码形式的整数值,并将该整数值编码为数量最少的八位组。0值编码为单个00
八位组。
下表为一些INTERGER
类型值的BER编码(DER编码也是一样)的示例:
整数值 | 经BER编码的结果 |
---|---|
0 | 02 01 00 |
127 | 02 01 7F |
128 | 02 02 00 80 |
256 | 02 02 01 00 |
-128 | 02 01 80 |
-129 | 02 02 FF 7F |
表3. 示例整数值的BER编码
使用原始的编码方式,内容八位组的编码即为使用原始方式对该整数值进行BER编码的结果。
NULL
表示一个空值,被应用于PKCS的好些地方来用于指示算法参数。
NULL
使用原始的编码方式,其内容八位组为空。
示例:NULL
值的编码方式可以使用如下的任一种,取决于长度编码的方式:
05 00
05 81 00
使用原始的编码方式,内容八位组为空,一个NULL
值的编码总是05 00
。
OBJECT IDENTIFIER
类型用于指示一个对象标识符,它是一个整数序列,用于识别一个对象,如某个算法、某个属性类型、或者定义了某个对象标识符的注册机构。OBJECT IDENTIFIER
的值可以包含任意数量的整数,这些整数可以是任意的非负值。该类型为非string类型。
IBJECT IDENTIFIER
值的具体含义由注册机构赋予。各注册机构需对以给定序列开头的所有整数序列负责。某个注册机构通常将其域下的序列子集或者特定的对象类型授权给其他的注册机构。每个对象标识符至少包含两个整数。
OBJECT IDENTIFIER
在PKCS #7 ContentInfo
类型中用于识别内容,在X.509 AlgorithmIdentifier
类型中用于识别算法,在X.501 Attribute
和AttributeValueAssertion
类型中用于识别属性。Attribute
类型在PKCS #6、#7、#9和#10中均有被用到,AttributeValueAssertion
类型则被用在X.501的可分辨名称中。OBJECT IDENTIFIER
的相关值在PKCS全文中被定义。
符号:OBJECT IDENTIFIER
值的组成结构:
{ [identifier] component1 … componentn }
componenti = identifieri | identifieri (valuei) | valuei
其中 identifier, identifier1, …, identifiern 为识别码, value1, …, valuen 是可选的整数值。
没有识别码的形式是展示其所有组件的完整值形式;带识别码的形式则是用识别码缩略了其以另一个对象标识符值作为开始的部分。识别码 identifier, identifier1, …, identifiern主要用于文档说明,当识别码与整数值都存在的情况下,识别码必须与整数值对应。仅当这些标识符属于X.208 所定义的一小组标识符时,它们才能在没有整数值的情况下出现。
例如:如下的两组值均表示分配给RSA Data Security公司的同一对象标识符:
{ iso(1) member-body(2) 840 113549 }
{ 1 2 840 113549 }
需要注意,在这个给出ASN.1 值表示法的示例中,对象标识符值是十进制数据而非十六进制。表4给出一些其他的对象标识符的值以及含义。
Object identifier value | Meaning |
---|---|
{1 2} |
ISO member bodies |
{ 1 2 840 } |
US (ANSI) |
{ 1 2 840 113549 } |
RSA Data Security, Inc. |
{ 1 2 840 113549 1 } |
RSA Data Security, Inc. PKCS |
{ 2 5 } |
directory services (X.500) |
{ 2 5 8 } |
directory services-algorithms |
表4. 一些对象标识符值及其含义
使用原始的编码方式,其内容八位组编码方式如下,其中value1,…, valuen表示对象标识符完整值形式中的各组件的整数值:
例如:RSA Data Security, Inc对象标识符的第一个八位组的BER编码为 40 * 1 + 2 = 42 = 2a
;840 = 6(06
) * 128 + 72(48
),因而840的编码为86 48
;113549 = 6(06
) * 128^2 + 119(77
) * 128 + 13(0d
),因此113549的编码为86 f7 0d
。因而,该对象标识符的完整BER编码为:
06 06 2a 86 48 86 f7 0d
使用原始的编码方式,内容八位组的编码即为使用原始方式对该对象标识符值进行BER编码的结果。
OCTET STRING
类型表示一个任意的八位组字符串。OCTET STRING
的值可以是任意长度的,包括0。该类型是string类型。
OCTET STRING
类型在PKCS #5 PBEParameter
类型中表示盐值,在PKCS #7 中表示消息摘要、信息密文摘要和加密的内容,在PKCS #8中表示私钥和加密的私钥。
OCTET STRING
[SIZE
({size | size1…size2})]
其中size,size1,size2是可选的长度约束。OCTET STRING SIZE
(size)所定义的八位组串中,串的长度必须是size个八位组。OCTET STRING SIZE
(size1…size2)所定义的八位组串中,串所包含的八位组数量必须在size1到size2之间。OCTET STRING
定义的八位组串中,字符串可以是任意长度。
例如:PKCS #5 PBEParameter
类型包含一个OCTET STRING
类型的组件:
PBEParameter ::= SEQUENCE {
salt OCTET STRING SIZE(8),
iterationCount INTEGER }
这里salt组件的长度总是8个字节(一个字节占8位,即有一个八位组占一个字节)。
使用原始的或者结构化的编码方式。在原始编码方式中,内容八位组给出串从第一个八位组到最后一个八位组的内容值;在结构化的编码方式中,内容八位组给出该串所包含的各个子串的值的BER编码结果的级联。
例如:OCTET STRING
类型值01 23 45 67 89 ab cd ef
的BER编码结果可以是如下两种形式中的一种,具体由所选择的长度编码形式以及使用的是原始的还是结构化的编码方式决定。
04 08 01 23 45 67 89 ab cd ef
04 81 08 01 23 45 67 89 ab cd ef
24 0c
04 04 01 23 45 67
04 04 89 ab cd ef
使用原始的编码方式,内容八位组为使用原始编码方式所得到的BER编码。
例如:OCTET STRING
类型值01 23 45 67 89 ab cd ef
的DER编码为:
04 08 01 23 45 67 89 ab cd ef
PrintableString
表示由如下字符集所包含的可打印字符所构成的任意字符串:
A, B, ..., Z
a, b, ..., z
0, 1, ..., 9
(space) ' ( ) + , - . / : = ?
该类型是一个string类型。
PrintableString
在PKCS #9用于表示挑战码密码与无结构地址属性以及几个X.521可分辨名称属性。
PrintableString
使用原始的或结构化的编码方式。在使用原始编码方式的情况下,内容八位组给出可打印字符串中所包含的、使用ASCII编码的字符;在使用结构化编码的情况下,内容八位组给出字符串所包含的连续子串的BER编码的级联结果。
例如:根据所使用的长度编码方法和所采取的编码方式的不同,PrintableString
值“Test User 1”的BER编码结果可能如下:
13 0b 54 65 73 74 20 55 73 65 72 20 31
13 81 0b
54 65 73 74 20 55 73 65 72 20 31
33 0f
13 05 54 65 73 74 20
13 06 55 73 65 72 20 31
使用原始的编码方式,内容八位组即为使用原始编码方式的BER编码结果。
例如:PrintableString
值“Test User 1”的DER编码结果如下:
13 0b 54 65 73 74 20 55 73 65 72 20 31
SEQUENCE
类型表示一个或者多个类型的有序集合。
SEQUENCE
类型的使用贯穿PKCS及与之相关的标准规范。
SEQUENCE
{
[identifier1] Type1 [{ OPTIONAL | DEFAULT
value1}],
…,
[identifiern] Typen [{ OPTIONAL | DEFAULT
valuen}]
}
其中,identifier1,…,identifiern是可选的、互不相同的组件识别码,Type1, …,Typen是组件的类型,value1,…,valuen是可选的组件默认值。识别码主要用于文档,它们无法以任何形式影响类型的值或者其编码。
OPTIONAL
修饰词指示该组件值是可选的,即,不是必需要出现在序列中的。DEFAULT
修饰词指示该组件值也是可选的,不过如果该组件缺失的话,该组件被赋予指定的默认值。
SEQUENCE
中带OPTIONAL
或者DEFAULT
修饰词的连续组件,以及在前述组件之后的任何组件,它们的标签必需不同。这个需求通常可以通过在某些组件上添加显式或者隐式标记来满足。
例如:X.509 Validity
类型是一个包含两个组件的SEQUENCE
类型:
Validity ::= SEQUENCE {
start UTCTime,
end UTCTime }
这里,两个组件的识别码分别为start和end,类型都是UTCTime
。
使用结构化的编码方式。内容八位组是序列中的组件值的BER编码的按序级联,对于带OPTIONAL
和DEFAULT
修饰词的组件,其编码规则如下:
OPTIONAL
和DEFAULT
修饰词的组件的值缺失,则该组件的编码不会被包含在内容八位组中;DEFAULT
修饰词的组件的值是默认值,那么该组件的编码是否被包含在内容八位组中均可。使用结构化的编码方式,内容八位组同BER编码,除了如果带DEFAULT
修饰词的组件的值取值为默认值的情况下,内容八位组不会包含该组件的编码。
SEQUENCE OF
表示由一个给定类型的0次或者多次出现构成的有序序列。
SEUQENCE OF
类型被使用在X.501 可分辨名称(distinguished names)中。
SEQUENCE OF
Type
上述的Type是一个类型。
例如:X.501 RDNSequence
类型包含RelativeDistinguishedName
类型的0次或者多次出现,最重要的优先出现。
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
使用结构化的编码方式,内容八位组是集合中所多次出现的类型的值的BER编码的按序级联。
使用结构化的编码方式,内容八位组是集合中所动词出现的类型的值的DER编码的按序级联。
SET
类型表示一个或者多个类型的无序集合。
SET
类型未被使用于PKCS。
SET
{
[identifier1] Type1 [{ OPTIONAL | DEFAULT
value1}],
…,
[identifiern] Typen [{ OPTIONAL | DEFAULT
valuen}]}
其中,identifier1,…,identifiern是可选的、互不相同的组件识别码,Type1, …,Typen是组件的类型,value1,…,valuen是可选的组件默认值。识别码主要用于文档,它们无法以任何形式影响类型的值或者其编码。
OPTIONAL
修饰词指示该组件值是可选的,即,不是必需要出现在集合中的。DEFAULT
修饰词指示该组件值也是可选的,不过如果该组件缺失的话,该组件被赋予指定的默认值。
集合中的组件的标签必需互不相同,这个需求通常可以通过给某些组件赋予显示或者隐式标记实现。
使用结构化的编码方法。内容八位组是集合中的组件的值的BER编码 按照任意顺序的级联,其中带OPTIONAL
和DEFAULT
修饰词的组件的编码规则如下:
OPTIONAL
或者DEFAULT
修饰词的组件的值缺失,那么该组件的编码不会出现在内容八位组中。DEFAULT
修饰的组件的值取值为默认值,则该组件的编码可以出现也可以不出现在内容八位组中。使用结构化的编码方式。内容八位组与BER编码相同,除了如下两种情况:
DEFAULT
修饰词的组件取值为默认值,该组件的编码不会包含在八位组中;SET OF
类型表示一个给定类型的0次或者多次出现。
SET OF
类型在PKCS #6,#7,#8,#9 和 #10 被用于属性集合,在PKCS #7中被用于消息摘要算法标识符、签名者信息和接受者信息集合,在X.501中被用于可分辨名称。
SET OF
Type
其中,Type是一个类型。
例如:X.501 RelativeDistinguishedName
类型包含AttributeValueAssertion
类型的0次或者多次出现,其出现顺序并不重要:
RelativeDistinguishedName ::=
SET OF AttributeValueAssertion
使用结构化的编码方式。内容八位组是集合中所多次出现的类型的值的BER编码的任意顺序级联。
使用结构化的编码方式,内容八位组同BER编码,除了集合的各类型值的BER编码是按照编目序升序级联之外。两个不同的BER编码的编目比较流程如下:在较短的一个BER编码的最后一个八位组之后,使用比任何正常八位组值都小的假八位组值进行逻辑填充;然后从左到右扫描这两个BER 编码直至差异出现,在差异点处具有较小八位组值的BER 编码较小。
T61String
表示一个由T.61字符构成的任意字符串。T.61是ASCII字符集的一个八位扩展。特殊的“转义”序列指定对后续字符值的解释,例如日语;最初的解释是拉丁语。字符集包括不可打印的控制字符。T61String
类型仅允许拉丁语和日语字符解释,并且目录名称的实现不包含控制字符 [NIST92]。T61字符串值可以具有任何长度,包括零。此类型是字符串类型。
T61String
被用在PKCS #9的无结构地址和密码挑战码属性中 以及少数X.521属性中。
T61String
使用原始的或结构化的编码方式。
例如:T.61字符串“cl’es publiques”(公钥的法语表示)的BER编码结果可能如下,实际是哪一种取决于所使用的长度八位组编码方法以及编码所使用的方式是原始的还是结构化的。
14 0f
63 6c c2 65 73 20 70 75 62 6c 69 71 75 65 73
14 81 0f
63 6c c2 65 73 20 70 75 62 6c 69 71 75 65 73
34 15
14 05 63 6c c2 65 73
14 01 20
14 09 70 75 62 6c 69 71 75 65 73
八位字符c2
是一个 T.61 前缀,用于给下一个字符添加重音符号 (')。
使用原始的编码方式,内容八位组与使用原始方式的BER编码结果一致。
例如:T61String
值“cl’es publiques”的DER编码为
14 0f 63 6c c2 65 73 20 70 75 62 6c 69 71 75 65 73
UTCTime
类型表示“协调世界时(coordinated universal time)”或格林威治标准时间 (Greenwich Mean Time,GMT) 值。一个UTCTime
值包括 以分或秒为精度的本地时间 和 其相比于GMT时间的偏移值(表示为小时和分钟)。它使用如下的任一种时间表示格式:
YYMMDDhhmmZ
YYMMDDhhmm+hh’mm’
YYMMDDhhmm-hh’mm’
YYMMDDhhmmssZ
YYMMDDhhmmss+hh’mm’
YYMMDDhhmmss-hh’mm’
其中:
该类型是一个字符串类型。
UTCTime
类型在PKCS #9签名时间属性中用于表示签名的时间,在X.509 Validity
类型中表示整数的有效期。
UTCTime
使用原始的或结构化的编码方式。
UTCTime
值很短,使用结构化的编码方式不是很有意思,但是也是允许的)例如:当前的这句话最开始是在太平洋夏令时1991年5月6日 4:45:40pm 写下的,这个时间可以表示为如下的任一种UTCTime
时间值:
上述值的具有如下的任一种BER编码:
17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a
17 11 39 31 30 35 30 36 31 36 34 35 34 30 2D 30 37 30 30
使用原始的编码方式。其内容八位组与使用原始方式的BER编码结果一致。
本节以X.501类型Name
为说明对象给出一个ASN.1表示法和DER编码的例子。
本节给出X.501类型Name
的ASN.1表示:
Name ::= CHOICE {
RDNSequence }
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::=
SET OF AttributeValueAssertion
AttributeValueAssertion ::= SEQUENCE {
AttributeType,
AttributeValue }
AttributeType ::= OBJECT IDENTIFIER
AttributeValue ::= ANY
在X.500目录中,Name
类型用于辨别一个对象。Name
当前是包含一个可选项RDNSequence
的CHOICE
类型。(X.500的未来版本可能会包含更多的可选项。)
RDNSequence
类型给出其从根开始的X.500目录树路径。RDNSequence
是一个SEQUENCE OF
类型,其包含RelativeDistinguishedName
的一次或多次出现。
RelativeDistinguishedName
类型为对象给出该对象相对于其父目录节点对象的唯一名称。它是一个SET OF
类型,包含AttributeValueAssertion
的一次或多次出现。
AttributeValueAssertion
类型给相对可分辨名称的一些属性,如国家名或者一般名称,分配属性值。AttributeValueAssertion
是一个包含两个组件(一个AttributeType
类型和一个AttributeValue
)的SEQUENCE
类型。
AttributeType
类型通过对象标识符区分一个属性;AttributeValue
类型给出一个任意的属性值。属性值AttributeValue
的实际类型由属性类型AttributeType
决定。
本节自底向上地给出Name
类型值的一个DER编码示例。
本节所使用的名称是PKCS 示例[Kal93]中的Test User 1对应的名称。该名称使用如下的路径表示:
上面的每一层对应一个RelativeDistinguishedName
值,该值包含一个AttributeValueAssertion
值,所对应的AttributeType
值是等号之前的部分,AttributeValue
值是等号之后的部分(一个对应于给定属性类型的可打印字符串)。
countryName
、organizationName
和commonUnitName
是X.520中定义的属性类型,它们的对象标识符分别为:
attributeType OBJECT IDENTIFIER ::=
{ joint-iso-ccitt(2) ds(5) 4 }
countryName OBJECT IDENTIFIER ::= { attributeType 6 }
organizationName OBJECT IDENTIFIER ::=
{ attributeType 10 }
commonUnitName OBJECT IDENTIFIER ::=
{ attributeType 3 }
上述的三个AttributeType
的值都是OCTET STRING
类型,因此它们的DER编码使用原始的、定长的方法:
属性OID DER编码 | 属性类型 |
---|---|
06 03 55 04 06 |
countryName |
06 03 55 04 0a |
organizationName |
06 03 55 04 03 |
commonName |
由于OBJECT IDENTIFIER
的tag是6,其标识符八位组遵循低标签号码编码方式。位8和位7的值为0,指示它是通用类型标签,位6值为0,指示使用原始的编码方式。长度八位组遵循短长度编码方式。内容八位组是由三个八位组值表示,这三个值由对象标识符包含的整数值导出:40 * 2 + 5 = 85 = 0x55;0x04;最后是0x06、0x0a(十进制表示是10)或0x03。
上述的三个AttributeValue
值均为PrintableString
类型值,因此它们的编码遵从原始的定长的编码方式:
属性值DER编码 | 属性值 |
---|---|
13 02 55 53 |
“US” |
13 14 45 78 61 6d 70 6c 65 20 4f 72 67 61 6e 69 7a 61 74 69 6f 6e |
“Example Organization” |
13 0b 54 65 73 74 20 55 73 65 72 20 31 |
“Test User 1” |
由于PrintableString
的tag number是19(十六进制表示为0x13),在0~30范围内,因此其标识符八位组遵从低标签号码编码方式。位8和位7均取值为0,指示该类型是通用类型;位6取值为0,指示使用原始的编码方式。长度编码使用短长度编码方式,内容八位组则是属性值的ASCII表示。
上述提及的三个AttributeValueAssertion
值都是SEQUENCE
类型值,因此它们的DER编码遵循结构化的、定长的编码方式:
countryName
= “US”
30 09
06 03 55 04 06
13 02 55 53
organizationName
= “Example Organization”
30 1b
06 03 55 04 0a
13 14 45 78 61 6d 70 6c 65 20 4f 72 67 61 6e 69 7a 61 74 69 6f 6e
commonName
= “Test User 1”
30 12
06 03 55 04 0b
13 0b 54 65 73 74 20 55 73 65 72 20 31
由于SEQUENCE
的tag number是16(十六进制0x10),在0~30范围内,因此其标识符八位组遵从低标签号码编码方式。由于SEQUENCE
是通用类型,因此标签八位组的位8和位7取值为0;由于使用结构化的编码方式,其位6取值为1。长度使用短长度编码方式。内容八位组则是attributeType和attributeValue组件的DER编码的拼接。
上述提及的三个RelativeDistinguishedName
值都是SET OF
类型值,因此它们的编码遵循结构化的、定长的方法:
31 0b
30 09 ... 55 53
31 1d
30 1b ... 6f 6e
31 14
30 12 ... 20 31
由于SET OF
的tag number是17(十六进制0x11),在0~30范围内,因此其对应的标签八位组使用低标签好吗编码方式。由于SET OF
类型在通用类型行列内,标签八位组的位8和位7取值为0,由于使用的编码方式为结构化的编码方式,因此标签八位组的位6取值为1。长度八位组遵从短长度编码方式,内容八位组即为对应的AttributeValueAssertion
值的DER编码,鉴于集合中只有一个值。
由于RDNSequence
类型值是SEQUENCE OF
类型值,因此其DER编码遵从结构化的、定长的编码方式:
30 42
31 0b ... 55 53
31 1d ... 6f 6e
31 14 ... 20 31
由于SEQUENCE OF
的tag number是16(十六进制0x10),在0~30范围内,因此其标识符八位组遵从低标签号码编码方式。由于SEQUENCE
是通用类型,因此标签八位组的位8和位7取值为0;由于使用结构化的编码方式,其位6取值为1。长度使用短长度编码方式。内容八位组是三个RelativeDistinguishedName
值按照在ASN.1表示中的出现顺序的依次拼接。
Name
值是一个CHOICE
类型值,因此其DER编码就是上述RDNSequence
值的DER编码:
30 42
31 0b
30 09
06 03 55 04 06 attributeType = countryName
13 02 55 53 attributeValue = "US"
31 1d
30 1b
06 03 55 04 0a attributeType = organizationName
13 14 attributeValue = "Example Organization"
45 78 61 6d 70 6c 65 20 4f 72 67
67 61 6e 69 7a 61 74 69 6f 6e
31 14
30 12
06 03 55 04 03 attributeType = commonName
13 0b attributeValue = "Test User 1"
54 65 73 74 20 55 73 65 72 20 31