openssl中ASN.1源码解读
ASN.1简介
Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.
抽象语法记法(ASN.1)是一种对数据和协议进行表示、编码、传输和解码的形式化描述方法。
该标准可分为:抽象语法( 数据类型的ASN.1描述)、传送语法(网络中对等实体之间通信时,对用户信息的描述规则)。
The standard ASN.1 encoding rules include:
- Basic Encoding Rules 基本编码规则 (BER)
- Canonical Encoding Rules 正则编码规则 (CER)
- Distinguished Encoding Rules 非典型编码规则 (DER)
- XML Encoding Rules XML编码规则 (XER)
- Canonical XML Encoding Rules (CXER)
- Extended XML Encoding Rules(E-XER)
- Packed Encoding Rules 压缩编码规则 (PER, unaligned: UPER, canonical: CPER)
- Generic String Encoding Rules (GSER)
Example encoded in DER
Below is the data structure shown above encoded in DER format (all numbers are in hexadecimal):
30 — type tag indicating SEQUENCE
13 — length in octets of value that follows
02 — type tag indicating INTEGER
01 — length in octets of value that follows
05 — value (5)
16 — type tag indicating [[IA5String]]
(IA5 means the full 7-bit ISO 646 set, including variants,
but is generally US-ASCII)
0e — length in octets of value that follows
41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f — value ("Anybody there?")
(Note: DER uses a pattern of [[type-length-value]] triplets, and uses well known byte constants for encoding type tags)
The result is the string of 21 octets (8-bit bytes):
<pre>30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f</pre>
The scope of ASN.1 and DER ends here. It is possible to transmit the encoded message to the recipient by any means ([[Transmission Control Protocol]] (TCP) or any other protocol). The party should be able to decode the octets from the DER.
Example encoded in XER
Alternatively, it is possible to encode the same ASN.1 data structure with [[XML Encoding Rules]] (XER) to achieve greater human readability "over the wire". It would then appear as the following 108 octets, (space count includes the spaces used for indentation):
<FooQuestion>
<trackingNumber>5</trackingNumber>
<question>Anybody there?</question>
</FooQuestion>
</source>
Example encoded in PER (unaligned)
Alternatively, if [[Packed Encoding Rules]] are employed, the following 122 bits (16 octets amount to 128 bits, but here only 122 bits carry information and the last 6 bits are merely padding) will be produced:
<pre>01 05 0e 83 bb ce 2d f9 3c a0 e9 a3 2f 2c af c0</pre>
In this format, type tags for the required elements are not encoded, so it cannot be parsed without knowing the expected schemas used to encode. Additionally, the bytes for the value of the IA5String are packed using 7-bit units instead of 8-bit units, because the encoder knows that encoding an IA5String byte value requires only 7 bits. However the length bytes are still encoded here, even for the first integer tag 01 (but a PER packer could also omit it if it knows that the allowed value range fits on 8 bits, and it could even compact the single value byte 05 with less than 8 bits, if it knows that allowed values can only fit in a smaller range).
Note also that the last 6 bits in the encoded PER are padded with null bits in the 6 least significant bits of the last byte c0 : these extra bits may not be transmitted or used for encoding something else if this sequence is inserted as a part of a longer unaligned PER sequence.
This means that unaligned PER data is essentially an ordered stream of bits, and not an ordered stream of bytes like with aligned PER, and that it will be a bit more complex to decode by software on usual processors because it will require additional contextual bit-shifting and masking and not direct byte addressing (but the same remark would be true with modern processors and memory/storage units whose minimum addressable unit is larger than 1 octet). However modern processors and signal processors include hardware support for fast internal decoding of bit streams with automatic handling of computing units that are crossing the boundaries of addressable storage units (this is needed for efficient processing in data codecs for compression/decompression or with some encryption/decryption algorithms).
If alignment on octet boundaries was required, an aligned PER encoder would produce:
<pre>01 05 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f</pre>
(in this case, each octet is padded individually with null bits on their unused most significant bits).
===============================================================
ASN.1详解
【ASN.1定义的基本数据类型】
下面列出ASN.1定义的部分基本数据类型,其各字段的意义如下:
[数据类型]-[数据说明]-[Tag(16进制)]
[BOOLEAN]-[有两个值:false或true]-[01]
[INTEGER]-[整型值]-[02]
[BIT STRING]-[0位或多位]-[03]
[OCTET STRING]-[0字节或多字节]-[04]
[NULL]-[NULL值]-[05]
[OBJECT IDENTIFIER]-[相应于一个对象的独特标识数字]-[06]
[OBJECT DESCRIPTOR]-[一个对象的简称]-[07]
[EXTERNAL]-[ASN.1没有定义的数据类型]-[08]
[REAL]-[实数值]-[09]
[ENUMERATED]-[数值列表,这些数据每个都有独特的标识符,作为ASN.1定义数据类型的一部分]-[0a]
[SEQUENCE和SEQUENCE OF]-[有序数列,SEQUENCE里面的每个数值都可以是不同类型的,而SEQUENCE OF里是0个或多个类型相同的数据]-[10]
[SET和SET OF]-[无序数列,SET里面的每个数值都可以是不同类型的,而SET OF里是0个或多个类型相同的数据]-[11]
[NumericString]-[0-9以及空格]-[12]
[PrintableString]-[A-Z、a-z、0-9、空格以及符号 ()+,-./:=?]-[13]
[UTCTime]-[世界时间]-[17]
[GeneralizedTime]-[通用时间]-[18]
ASN.1对象的编码是ASN.1标准的重要部分,下面讲述DER编码的方法。
一个标准的ASN.1编码对象有四个域:对象标识域、数据长度域、数据域以及结束标志(可选,在长度不可知情况下需要,openssl中没有该标志)。
【对象标识域】
对象标识域有两种形式,低Tag数字(Tag值在0到30)和高Tag数字(Tag值大于30)形式。
低Tag数字形式只有一个字节,包含三部分,从低位为1开始编号,8和7位是Tag类型,共有四种,分别是universal(00)、application(0 1)、context-specific(1 0)和private(11);第6位是0,表明编码类型是基本类型,第5-1位是Tag值。
高Tag数字形式可以有两个或多个字节,第一个字节跟低Tag数字形式一样,但低5位值全为1,而在后续的第二个和其后的字节中给出Tag值,这些字节都只使用了低7位为数据位,最高位都设为0,但最后一个字节的最高位设为1,采用高位优先,经可能少的数字原则。
【数据长度域】
数据长度域也有两种形式,短形式和长形式。
短形式的数据长度域只有一个字节,第8位为0,其它低7位给出数据长度。
长形式的数据长度域有2到127个字节。第一个字节的第8位为1,其它低7位给出后面该域使用的字节的数量,从该域第二个字节开始给出数据的长度,基于256,高位优先。
【数据域】
数据域给出了具体的数据值。该域的编码对不同的数据类型不一样,这里就不在一一详述了,有兴趣的可以参看参考资料。
=================================================================================================
openssl中ASN.1源码解读
【ASN.1函数库概述】
因为X509相关的协议都是基于ASN.1和DER编码的,所以openssl提供了一组函数,这些函数可以读取DER编码的对象,并将它们转换成openssl能够处理的内部格式;这些函数也可以将openssl里定义的C格式的对象结构转换成DER编码的对象。此外,该系列还提供了一些对这些对象进行比较、读取和设定指定值的函数。该系列函数还包括了一些签名函数,这是因为在签名之前,有些对象需要进行DER编码。
【ASN1_CTX】
首先,看ASN1_CTX结构体,该结构用来在ASN1处理过程中维护跟踪各种相关变量
typedef struct asn1_ctx_st {
unsigned char *p; /* work char pointer */
int eos; /* end of sequence read for indefinite
* encoding */
int error; /* error code to use when returning an error */
int inf; /* constructed if 0x20, indefinite is 0x21 */
int tag; /* tag from last 'get object' */
int xclass; /* class from last 'get object' */
long slen; /* length of last 'get object' */
unsigned char *max; /* largest value of p allowed */
unsigned char *q; /* temporary variable */
unsigned char **pp; /* variable */
int line; /* used in error processing */
} ASN1_CTX;
- 参数p是工作字符指针,其最大长度由参数max指定;
- eos是indefinite编码模式的结束标识标志;
- error是错误代码;
- inf值为0x20代表constructd模式,为0x21代表indefinite模式;
- tag是最后取得的对象的tag值;
- xclass是最后取得的对象的类型;
- slen是最后取得的对象的长度;
- line变量在出错处理的时候使用。
该结构用来保存一个ASN1对象。
struct asn1_object_st {
const char *sn, *ln;
int nid;
int length;
const unsigned char *data; /* data remains const after init */
int flags; /* Should we free this one */
};
typedef struct asn1_object_st ASN1_OBJECT;
- nid是openssl内部定义的每个数字对象的独特标识码;
- sn是对象的简称;
- ln是对象的长名或小写名;
- data是相应对象的数据,
- length是该data字段的长度,
- flags是一个释放标志。
该结构是openssl里一个很基本的ASN.1对象结构,Openssl里定义的很多类型的对象都是采用该结构的,他们包括ASN1_INTEGER、ASN1_BIT_STRING、ASN1_OCTET_STRING、ASN1_PRINTABLESTRING、ASN1_T61STRING、ASN1_IA5STRING、ASN1_UTCTIME、ASN1_GENERALIZEDTIME、ASN1_GENERALSTRING、ASN1_UNIVERSALSTRING和ASN1_BMPSTRING。该结构的定义如下:
/* This is the base type that holds just about everything :-) */
struct asn1_string_st {
int length;
int type;
unsigned char *data;
/*
* The value of the following field depends on the type being held. It
* is mostly being used for BIT_STRING so if the input data has a
* non-zero 'unused bits' value, it will be handled correctly
*/
long flags;
};
typedef struct asn1_string_st ASN1_INTEGER;
typedef struct asn1_string_st ASN1_ENUMERATED;
typedef struct asn1_string_st ASN1_BIT_STRING;
typedef struct asn1_string_st ASN1_OCTET_STRING;
typedef struct asn1_string_st ASN1_PRINTABLESTRING;
typedef struct asn1_string_st ASN1_T61STRING;
typedef struct asn1_string_st ASN1_IA5STRING;
typedef struct asn1_string_st ASN1_GENERALSTRING;
typedef struct asn1_string_st ASN1_UNIVERSALSTRING;
typedef struct asn1_string_st ASN1_BMPSTRING;
typedef struct asn1_string_st ASN1_UTCTIME;
typedef struct asn1_string_st ASN1_TIME;
typedef struct asn1_string_st ASN1_GENERALIZEDTIME;
typedef struct asn1_string_st ASN1_VISIBLESTRING;
typedef struct asn1_string_st ASN1_UTF8STRING;
typedef struct asn1_string_st ASN1_STRING;
- type参数指明对象的类型;
- data参数是对象的数据,
- length指定了其长度;
- flags值跟type有关,一般来说,在BIT_STRING对象中使用。
【ASN1_TYPE】
该结构可以保存任意类型的ASN.1对象,其定义如下:
typedef struct asn1_type_st {
int type;
union {
char *ptr;
ASN1_BOOLEAN boolean;
ASN1_STRING *asn1_string;
ASN1_OBJECT *object;
ASN1_INTEGER *integer;
ASN1_ENUMERATED *enumerated;
ASN1_BIT_STRING *bit_string;
ASN1_OCTET_STRING *octet_string;
ASN1_PRINTABLESTRING *printablestring;
ASN1_T61STRING *t61string;
ASN1_IA5STRING *ia5string;
ASN1_GENERALSTRING *generalstring;
ASN1_BMPSTRING *bmpstring;
ASN1_UNIVERSALSTRING *universalstring;
ASN1_UTCTIME *utctime;
ASN1_GENERALIZEDTIME *generalizedtime;
ASN1_VISIBLESTRING *visiblestring;
ASN1_UTF8STRING *utf8string;
/*
* set and sequence are left complete and still contain the set or
* sequence bytes
*/
ASN1_STRING *set;
ASN1_STRING *sequence;
ASN1_VALUE *asn1_value;
} value;
} ASN1_TYPE;
其中,参数type指定了对象的类型。
【ASN1_TEMPLATE】
/*
* This is the ASN1 template structure that defines a wrapper round the
* actual type. It determines the actual position of the field in the value
* structure, various flags such as OPTIONAL and the field name.
*/
struct ASN1_TEMPLATE_st {
unsigned long flags; /* Various flags */
long tag; /* tag, not used if no tagging */
unsigned long offset; /* Offset of this field in structure */
# ifndef NO_ASN1_FIELD_NAMES
const char *field_name; /* Field name */
# endif
ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */
};
typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
【ASN1_VALUE】
/* This is just an opaque pointer */
typedef struct ASN1_VALUE_st ASN1_VALUE;
【ASN1_ITEM】
/* This is the actual ASN1 item itself */
struct ASN1_ITEM_st {
char itype; /* The item type, primitive, SEQUENCE, CHOICE
* or extern */
long utype; /* underlying type */
const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains
* the contents */
long tcount; /* Number of templates if SEQUENCE or CHOICE */
const void *funcs; /* functions that handle this type */
long size; /* Structure size (usually) */
# ifndef NO_ASN1_FIELD_NAMES
const char *sname; /* Structure name */
# endif
};
typedef struct ASN1_ITEM_st ASN1_ITEM;