SNMP ASN.1 OID编码规则
对象标识符(OBJECT IDENTIFIER, OID) 的编码规则
对象标识符类型
对象标识符(OBJECT IDENTIFIER, OID)类型用层次的形式来表示标准规范.标识符树通过一个点分的十进制符号来定义,这个符号以组织,子部分然后是标准的类型和各自的子标识符开始.
例如:MD5的OID 是 1.2.840.113549.2.5 表示为"iso(1) member-body (2) US (840) rsadsi(113549) digestAlgorithm (2) md5 (5)", 所以当解码程序看到这个OID时,就知道是MD5散列.
OID在公钥算法标准中很流行,它指出证书绑定了哪种散列算法. 同样,也有公钥算法,分组算法,和操作模式的OID. 它们是一种高效且可移植的表示数据包中所选算法的形式.
对OID的编码规则:
前两部分如果定义为x.y, 那么它们将合成一个字40*x + y, 其余部分单独作为一个字节进行编码.
每个字首先被分割为最少数量的没有头零数字的7位数字.这些数字以big-endian格式进行组织,并且一个接一个地组合成字节. 除了编码的最后一个字节外,其他所有字节的最高位(位8)都为1.
举例: 30331 = 1 * 128^2 + 108 * 128 + 123 分割成7位数字(0x80)后为{1,108,123}设置最高位后变成{129,236,123}.如果该字只有一个7位数字,那么最高为0.
asn1对OID的编码有一些规定,形如a.b.c.d.e的OID被编码的时候,完全可以按照der的编码规则将整个oid的类型设定为object,然后将每一个点分数字的类型设定为integer,最终编码为[obj|length[[int|lena[a]]][int|lenb[b]][int|lenc[c]]...],可是asn1标准并没有如此编码,而是使用了"more bit"这种方式,这样就少了很多的层次,不必为每一个点分数字进行asn1编码,具体说来就是将一个点分数字拆分为7bit一组的序列,然后除了最后一个的最高位填入0之外其余的最高位都填1,然后将它们合并在一起,最终将每一个经过这样处理的点分数字连接在一起,可以减少编码的长度,起码每个点分数字的type和length都省略了,唯一的不足是8bit的点分数字要编码为16bits。
以上仅仅是对oid编码的规定之一,还有一个很有意思的就是由于OID的前两极的标识数字都不是很大,因此更好的办法就是将OID的前两级编码到一个7bit的数中(由于标识more bit需要最高位,所以只剩下7位可以存数据),第一级OID只有3个,分别是itu-t(0),iso(1),joint-iso-itu-t(2),并且第二级OID标识最多也就23,挂于joint-iso-itu-t之下,现在需要一个算法,将第一级和第二级的OID标识编码到一个7bit的数里面,这就需要用一种平坦的方式来索引前两级的数据,构造一组虚拟的标识,为了对待三个一级OID标识更公平,最好是将127个“位置”平均分到三个一级标识,于是就将127除以3,结果是40,于是头40个虚拟标识分给itu-t,中间40个分给iso,后面的47个分给joint-iso-itu-t,这样,前两级是a.b的OID的a和b就被编码成了40*a+b,如此也就节省了一个编码byte。本质上这种编码的思想是在分级的标识上构造一组平坦的虚拟标识。
实例说明:
CPU空闲值的OID为:1.3.6.1.4.1.2011.11.11.0
其编码后为 2b 06 01 04 01 8f 65 0b 0b 00
编码原因:
ISO规定前两级格式为:第一级 * 40 + 第二级,即为 1*40 + 3 = 43,十六进制为 2b.
后面小于128的直接转换
.6.1.4.1.2011.11.11.0
06 01 04 01 (2011) 0b 0b 00
2011转化为15*128 + 101,为 (15,101),
15最高位置为1,为15+128=143,101最高位不变,为(143,101)
十六进制为 8f 65