ASN.1
在通信和计算机网络领域,ASN.1(Abstract Syntax Notation One) 是一套标准,用于描述数据类型的表示、编码、传输、解码。提供了一套形式(formal)、无歧义和精确的规则以描述独立于特定计算机硬件的数据类型和多种编码表示。[1]ASN.1是一种和平台、语言无关的描述语言。用于跨平台编程的protocol buffers和Apache Thrift具有类似功用。
最初是1984年的CCITT X.409:1984的一部分。由于其广泛应用,1988年ASN.1移到独立标准X.208,1995年进行全面修订后变成X.680系列标准。
ASN.1本身只定义了表示信息的抽象句法,但是没有限定其编码的方法。各种ASN.1的编码规则提供了由ASN.1描述其抽象句法的数据的值的传送语法(具体表达)。标准的ASN.1编码规则有:
- 基本编码规则(BER,Basic Encoding Rules)
- 规范编码规则(CER,Canonical Encoding Rules)
- 唯一编码规则(DER,Distinguished Encoding Rules)
- 压缩编码规则(PER,Packed Encoding Rules)
- XML编码规则(XER,XML Encoding Rules)
给定了协议内容并选定了编码规则,很多工具可以生成读(解码)写(编码)PTU的C/C++、Java、C#、Python等源代码。
基本概念
编辑在ASN.1中,符号的 定义没有先后次序,只要能够找到该符号的定义。即可先使用后定义。例如:
age Age ::= 18 创建Age的实例 Age ::= INTEGER 定义了Age这个类型
标识符、参考、关键字都要以一个字母开头,后接字母、数字或者连字符‘-’ (而不是下划线)。同时不能以连字符结尾,也不能连续出现两个连字符。
关键字全部大写。
在标识符中,只有类型和模块名字是以大写字母开头的,其他标识符都是以小写字母开头
注释以两个连字符“–”开始,结束于行的末尾或者该行中另一个双连字符
ASN.1的数据类型
编辑基本类型
编辑- NULL 值NULL,用于传送一个报告或者作为CHOICE类型中的值 null
- INTEGER 整数类型 int/Integer
- REAL 浮点数 double/Double/Float/float
- ENUMERATED 标识符的枚举
- BITSTRING 比特串 字节的位表示方法,可以给一个byte中的每一个bit进行设值
- OCTETSTRING 字节串 8进制表示的字符串
- OBJECT IDENTIFIER或RELATIVE-OID 一个实体的标识符
- EXTERNAL,EMBEDDED PDV 表示层上下文交换类型
- NumericString
- PrintableString
- VisibleString:ASCII表去除控制字符。
- UTF8String
- ISO64String
- IA5String 实际上是ASCII表的前128个字符。ITU-T recommendation T.50 specifies the International Reference Alphabet (IRA), formerly International Alphabet No. 5 (IA5), a character encoding.
- TeletexStirng
- T61String
- VideotexString
- GraphicString
- GeneralString
- UniversalString
- BMPString
- UTF8String
- CHARACTERSTRING 允许为字符串协商一个明确的字符表
- UTCTime
- GeneralizedTime
- DATE 表示日期,格式是"YYYY-MM-DD":
- TIME-OF-DAY 表示日期中的时间,格式是"HH:MM:SS":
- DATE-TIME 时间加日期的格式,它的格式"YYYY-MM-DDTHH:MM:SS"
- BOOLEAN 有两个可能得值:TRUE和FALSE。
组合类型
编辑- CHOICE 选择类型,该字段可能有多重不同的类型来表示,相当于C语言的union
- SEQUENCE 由不同类型的值组成一个有序的集合
- SET 无序集合(不同类型的值)
- SEQUENCEOF 由相同类型的值组成一个有序的集合
- SETOF 无序集合(相同类型的值)
子类型
编辑子类型(subtype)的值集合是其父类型值集合的子集。
单一值,即在定义中列举出所有可能的取值:
TestResult ::=INTEGER(1|2|3|4) sp1 TestResult ::= 2 Colors ::= UTF8String ("Blue" | "White")
SIZE关键字指示字符串的长度:
WorkstationNumber::=OCTET STRING(SIZE(6)) BitField ::= BIT STRING(SIZE(12)) map1 BitField ::= "100110100100"B map2 BitField ::= "9A4"H
SIZE关键字也可指示数组的长度:
Name ::= IA5String (SIZE (4..7)) NameList ::= SEQUENCE SIZE (1..25) OF Name
使用..可以表示一个范围(range)。只适用于整数和实数类型:
NoID::=INTEGER(1..100) PositiveInteger ::=INTEGER(0..MAX) PositiveInteger ::=INTEGER(1..MAX)
FROM关键字用于限制字符集的取值范围。只适用于字符串类型:
DigitString ::=IA5String((2)|(3)|(4)|5|(6)|(7)) str2 DigitString ::= "46732" PermittedChars ::= IA5String (FROM("ABCDEFG1244"))
PATTERN关键字指示正则表达式:
phoneNumber ::= IA5String (PATTERN "1[0-9]#10")
内部类型(Inner Subtyping)。适用于SEQUENCE,SEQUENCE OF,SET,SET OF和CHOICE类,主要用于对这些结构类型的元素项进行限制:
PDU::=set{ alpha [0] INTEGER, beta [1] IA5striong OPTIONAL, gamma [2] SEQUENCE OF parameter, delta [3] BOOLEAN } TestPDU::=PDU(WITH COMPONENTS{ alpha(min..<0),...,delta(FALSE) })
枚举子类型,说明被定义的新子类型包含原子类型的全部可能值。
Months::=ENUMERATED{ jaunary(1), february(2), ..., december(12) } First-quarter::=Months(january,february,march); Second-quarter::=Months(april,may,june) First-half::=Months (INCLUDES First-quarter|INCLUDE Second-quarter) jan First-quarter ::= 1
类型的定义及赋值
编辑<新类型的名字>::= <类型描述> <新类型的名字>是一个类型的名字,也可以是类型描述 <类型描述>基本类型、组合类型 <新的值的名字><该值的类型> ::= <值描述> <新的值的名字>是以小写字母开头的标识符; <该值的类型>可以是一个类型的名字,也可以是类型描述; <值描述>是基于整数、字符串、标识符的组合
ASN.1信息对象类和信息对象
编辑信息对象类用于表达比注释更为正式的一些信息。
<信息对象类>::= CLASS <类描述> WITHSYNTAX <信息描述> <模块名字> DEFINITIONS <缺省Tag>::= BEGIN EXPORTS <导出描述> IMPORTS <导入描述> <模块体描述> END IMPORTS <名字>,value FROM <其它模块的ObjectIdentifier>; EXPORTS<名字>;
例如:
--<ASN1.HugeInteger World-Schema.Rocket.range>-- World-Schema DEFINITIONS AUTOMATIC TAGS ::= BEGIN Rocket ::= SEQUENCE { range INTEGER, -- huge (see a special directive above) name UTF8String (SIZE(1..16)), message UTF8String DEFAULT "Hello World" , fuel ENUMERATED {solid, liquid, gas}, speed CHOICE { mph INTEGER, kmph INTEGER } OPTIONAL, payload SEQUENCE OF UTF8String } END
Module2 { isomember-body(2) f(250) type-org(1) ft(16) asn1-book(9)chapter5(0) module2(1) } DEFINITIONS AUTOMATIC TAGS ::= BEGIN EXPORTS Type2; IMPORTS Type1, value FROM Module1 {iso member-body(2) f(250) type-org(1)ft(16) asn1-book(9) chapter5(0) module1(0)}; Type2 ::= SEQUENCE OF Choice Choice ::= CHOICE { a INTEGER (0..value), b Type1 } END
注释:
- AUTOMATIC TAGS是指缺省Tag,说明不关注模块的Tag。
- IMPORTS声明在其它模块定义但在本模块会用到的类型或者值。
- EXPORT声明在本模块之外可以访问的类型或者值。
module后面加上了AUTOMATIC TAGS,这是什么意思呢?在ASN.1中,tags是ASN.1消息中每个组件的内部标识符,以Address为例,我们希望给Address中的每个属性都指定一个内部的标识符,如下所示:
Address::= SEQUENCE { street [0] VisibleString (SIZE (5 .. 50)) OPTIONAL, city [1] VisibleString (SIZE (2..30)), state [2] VisibleString (SIZE(2) ^ FROM ("A".."Z")), zipCode [3] NumericString (SIZE(5 | 9)) }
这里面的[0] [1] 就是标识符,当然,我们可以在定义module的时候手动指定这些tags,但是如果我们使用AUTOMATIC TAGS,这些标识符会自动创建,从而避免了手动创建标识符可能带来的问题。
对象标识符
编辑对象标识符(OBJECTIDENTIFIER,OID)类型,用层次的形式来表示标准规范。标识符树通过一个点分的十进制符号来定义,这个符号以组织子部分然后是标准的类型和各自的子标识符开始。
BER基本编码规则
编辑用ASN.1语言书写的变量必须转换为串行的字节流才能在网络中传输。为此,ASN.1又提供了基本编码规则(BER)来描述传输过程中内容的表示。BER的全称是Basic Encoding Rules,它是最早的编码规则,使用Tag-Length-Value(TLV)的格式对所有信息进行编码。在BER中,每个数据元素都被编码为类型标识符、长度描述、实际数据元素,以及可选的内容结束标记。
约定八位位组:八比特组成。八位位组的二进制位编号从8到1,第8位为最高有效位,第1位位最低有效位。
编码结构分为3部分:
- 标签(tag)字段:关于标签类别和编码格式、数据类型的编码信息。
- 长度(Length)字段:定义内容字段的长度。
- 值(Value)字段:包含实际的数据 。
标签tag字段
编辑其中7-8bits表示的是Tag class。
class | value | 描述 |
---|---|---|
Universal | 0 | ASN.1的native类型 |
Application | 1 | 该类型仅对一种特定应用程序有效 |
Context-specific | 2 | 这种类型依赖于context |
Private | 3 |
第6bit表示的是这个类型是简单类型还是组合类型,简单类型用0,组合类型用1。
第1-第5bits只用来表示0-30的值的范围。如果想要表示超出30范围的值,那么可以使用两个byte,前面一个byte的1-5bits全部用1表示,后面一个byte的第8bit用1表示,剩下的7个bits用来表示真实的值。
type名称 | 基础类型还是组合类型 | 编码值(十进制) |
---|---|---|
End-of-Content (EOC) | 基础类型 | 0 |
BOOLEAN | 基础类型 | 1 |
INTEGER | 基础类型 | 2 |
BIT STRING | 两者皆可 | 3 |
OCTET STRING | 两者皆可 | 4 |
NULL | 基础类型 | 5 |
OBJECT IDENTIFIER | 基础类型 | 6 |
Object Descriptor | 两者皆可 | 7 |
EXTERNAL | 组合类型 | 8 |
REAL (float) | 基础类型 | 9 |
ENUMERATED | 基础类型 | 10 |
EMBEDDED PDV | 组合类型 | 11 |
UTF8String | 两者皆可 | 12 |
RELATIVE-OID | 基础类型 | 13 |
TIME | 基础类型 | 14 |
Reserved | 示例 | 15 |
SEQUENCE and SEQUENCE OF | 组合类型 | 16 |
SET and SET OF | 组合类型 | 17 |
NumericString | 两者皆可 | 18 |
PrintableString | 两者皆可 | 19 |
T61String | 两者皆可 | 20 |
VideotexString | 两者皆可 | 21 |
IA5String | 两者皆可 | 22 |
UTCTime | 两者皆可 | 23 |
GeneralizedTime | 两者皆可 | 24 |
GraphicString | 两者皆可 | 25 |
VisibleString | 两者皆可 | 26 |
GeneralString | 两者皆可 | 27 |
UniversalString | 两者皆可 | 28 |
CHARACTER STRING | 组合类型 | 29 |
BMPString | 组合类型 | 30 |
DATE | 基础类型 | 31 |
TIME-OF-DAY | 基础类型 | 32 |
DATE-TIME | 基础类型 | 33 |
DURATION | 基础类型 | 34 |
OID-IRI | 基础类型 | 35 |
RELATIVE-OID-IRI | 基础类型 | 36 |
长度字段
编辑长度字段:用来表示值字段的八位位组的数量。
- 确定格式(编码时知道长度
- 长格式:第8比特为1,剩下7个bit表示1-126个后续byte的个数。
- 短格式:第8比特为0,剩下7个bit表示0-127
- 不确定格式:第8比特为0,剩下7个bit全为1
- 保留:第8比特为0,剩下7个bit全为0
规则如下
- 若编码是简单类型,则使用确定格式;
- 若编码是构造的,并且编码立即可用,既可以使用确定格式,也可以使用不确定格式,由发送者选择;
- 若编码是构造的,但编码不是立即可用,则使用不确定格式。
值字段
编辑值字段:由零个或多个八位位组组成,并按不同类型数据值的不同规定对它们进行编码
- End-of-Content (EOC),编码为00,基础类型
- 布尔值的编码 由1个字节组成。FALSE为00; TRUE为FF。
- TRUE的编码:01 01 FF
- FALSE的编码:01 01 00
- 整数编码 采用二进制补码形式编码。
- 0 编码 02 01 00
- 127 编码 02 01 7F
- 256 编码 02 02 01 00
- -129 编码 02 02 FF 7F
- 空值 标签 UNIVERSAL 5, 编码 05 00
- 位串值的编码
- 简单类型
- 构造类型
- 对象标识符的编码,为简单类型。
- 八位位组串和字符串类型值的编码
- IA5String类型字符串“ACE” 编码 16 03 41 43 45 H
- 八位位组串“ACE0” 编码 04 02 AC E0 H
- 序列值的编码,为构造类型。
- 序列类型{name IAString, ok BOOLEAN},值{name “smith”, ok TRUE}的编码:30 0A 16 05 73 6D 69 74 68 01 01 FF
- 集合值的编码,有多种编码。
参考
编辑- ↑ X.680 : Information technology - Abstract Syntax Notation One (ASN.1): Specification of basic notation.www.itu.int.于2021年4月29日查阅.