openssl之ASN1系列.doc_第1页
openssl之ASN1系列.doc_第2页
openssl之ASN1系列.doc_第3页
openssl之ASN1系列.doc_第4页
openssl之ASN1系列.doc_第5页
已阅读5页,还剩22页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

此文档收集于网络,如有侵权,请联系网站删除openssl之ASN.1系列之1-引言和ASN.1概述作者:DragonKing(Eric Wang)Mail: 发布于:OpenSSL版本:openssl-0.9.7版权声明:未经作者授权,本文不能在任何商业性质的出版物或网站上进行转载【引言】ASN.1 全称为Abstract Syntax Notation One,是一种描述数字对象的方法和标准。openssl的编码方法就是基于该标准的,目前,很多其他软件的编码方法也是基于该标准。对于直接使用 openssl的API或者应用程序来说,可能对ASN.1的了解并不需要很清楚,但是为了使大家对后续介绍的各个API有一个更深刻的编码知识基础,所以对该ASN.1以及openssl相应提供的API处理函数作介绍。【ASN.1概述】ASN.1 作为一个数字对象描述标准,包括了两部分,分别为数据描述语言(ISO8824)和数据编码规则(ISO8825)。ASN.1的数据描述语言标准允许用户自定义基本数据类型,并可以通过简单的数据类型组成更复杂的数据类型。比如一个复杂的数据对象,如X509证书,就是在其它一些数据类型上定义的,而其它数据类型又是在更基本的数据类型上建立的,直到回溯到定义的最基本的数据类型。比如ASN.1定义的X509证书的一个子域Validity(证书有效期)就定义如下:Validity := SEQUENCE notBeforeUTCTIME,notAfter UTCTIME其意义就是定义Validity为一个有序序列,由两个个UTCTIME类型的数据notBefore和notAfter组成。然后,就需要找出UTCTIME是怎么定义的,当然,事实上UTCTIME是ASN.1定义的一个基本的时间数据类型。在上述数据定义的基础上,ASN.1定义了一组编码规则,以规定怎么将上述描述的对象转换成应用程序能够处理和进行传输的二进制编码形式。ASN.1定义了多种编码方法,包括了BER, DER, PER, 和XER等,不过,虽然最基本最常用的编码方式是BER(Basic Encoding Rules),但是由于该编码方法可能对一个相同的对象有几种不同的合法二进制编码,所以在openssl里面使用的是BER的子集DER (Distinguished Encoding Rules),使用DER编码方法,对于每一个ASN.1对象,其相应的二进制编码是唯一的。ASN.1里定义的每个基本对象都有一个对应的数字标识tag,在进行二进制编码的时候需要使用该标志。【ASN.1定义的基本数据类型】下面列出ASN.1定义的部分基本数据类型,其各字段的意义如下:数据类型数据说明Tag(16进制)BOOLEAN有两个值:false或true01INTEGER整型值02BIT STRING0位或多位03OCTET STRING0字节或多字节04NULLNULL值05OBJECT IDENTIFIER相应于一个对象的独特标识数字06OBJECT DESCRIPTOR一个对象的简称07EXTERNALASN.1没有定义的数据类型08REAL实数值09ENUMERATED数值列表,这些数据每个都有独特的标识符,作为ASN.1定义数据类型的一部分0aSEQUENCE和SEQUENCE OF有序数列,SEQUENCE里面的每个数值都可以是不同类型的,而SEQUENCE OF里是0个或多个类型相同的数据10SET和SET OF无序数列,SET里面的每个数值都可以是不同类型的,而SET OF里是0个或多个类型相同的数据11NumericString09以及空格12PrintableStringA-Z、a-z、0-9、空格以及符号 ()+,-./:=?13UTCTime统一全球时间格式17除了上述基本类型,ASN.1还定义了另外一些专用的数据类型,这里不再一一叙述。openssl之ASN.1系列之2-ASN.1编码方法简介作者:DragonKing(Eric Wang)Mail: 版权声明:未经作者授权,本文不能在任何商业性质的出版物或网站上进行转载发布网站:OpenSSL版本:openssl-0.9.7参考资料:“Computer Network”,“A Layman s Guide to a Subset of ASN.1, BER, and DER”ASN.1对象的编码是ASN.1标准的重要部分,目前,通常采用的是BER,而DER则是其一个子集。本文将对该编码方法作简单的介绍。一个标准的ASN.1编码对象有四个域:对象标识域、数据长度域、数据域以及结束标志(可选,在长度不可知情况下需要,openssl中没有该标志)。【对象标识域】对象标识域有两种形式,低Tag数字(Tag值在0到30)和高Tag数字(Tag值大于30)形式。低Tag 数字形式只有一个字节,包含三部分,从低位为1开始编号,8和7位是Tag类型,共有四种,分别是universal(0 0)、application(0 1)、context-specific(1 0)和private(1 1);第6位是0,表明编码类型是基本类型,第5-1位是Tag值。 高Tag数字形式可以有两个或多个字节,第一个字节跟低Tag数字形式一样,但低5位值全为1,而在后续的第二个和其后的字节中给出Tag值,这些字节都只使用了低7位为数据位,最高位都设为0,但最后一个字节的最高位设为1,采用高位优先,经可能少的数字原则。【数据长度域】数据长度域也有两种形式,短形式和长形式。短形式的数据长度域只有一个字节,第8位为0,其它低7位给出数据长度。长形式的数据长度域有2到127个字节。第一个字节的第8位为1,其它低7位给出后面该域使用的字节的数量,从该域第二个字节开始给出数据的长度,基于256,高位优先。【数据域】数据域给出了具体的数据值。该域的编码对不同的数据类型不一样,这里就不在一一详述了,有兴趣的可以参看参考资料。【一个编码例子】下面是SSLDocument给出的对一个对象进行DER编码的例子,更多的例子可以参看本文给出的参考资料。例子使用的对象是ASN.1定义的BIT STRING类型的对象,其编码的步骤如下:1.对位串使用0进行填补,使其长度为8的整数倍(如果已经是整数倍,则不需要进行填补);2.计算填补的位数并写下来,成为数据内容的第一个字节;3.写入填补后的位串,高位字节优先。这些数据跟前面的一个字节组成数据内容的全部字节;4.在这些数据前面加上一个头字节,这个字节定义如下(编号是从低位为1开始):第8、7位:00(universal类型)第 6 位 :0(表明是基本类型,有限长度的编码)第51位:0x03(表明是BIT STRING)这个字节定义了对象标识域;5.然后在对象标识域字节和数据字节之间加入下面计算的定义的字节:计算有多少字节的数据内容(对象标识域数据除外),如果少于127字节,那么就定义一个字节如下:第8位:0第71位:数据内容的字节数量如果数据内容的字节数量大于127,就需要定义两个或多个字节,其中,第一个字节的定义如下:第8位:1第71位:该域后面还有多少字节其后的字节是数据内容的字节数量,每字节基于256,高位优先下面是一个实际的数据例子:位串: 01000100111011 1.补齐两个0在后面,成为8的整数倍,得到 0100010011101100 ;2. 02 作为第一个数据内容的字节;3. 44 ec 作为其余的数据内容的字节;4. 03 作为前面的对象标识字节;5.因为BIT STRING的tag值3DER)和d2i(DER-内部)开头的。跟其他各个系列的函数一样,OpenSSL虽然提供了针对各种对象类型的函数,但是其基本的函数不多,而其他都是在这个基础上实现的宏定义。这些基本函数如下(cryptoasn1asn1.h):inti2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char *pp);ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char *pp,long length);inti2d_ASN1_BOOLEAN(int a,unsigned char *pp);int d2i_ASN1_BOOLEAN(int *a,unsigned char *pp,long length);int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char *pp, int tag, int xclass);ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING *a, unsigned char *pp,long length, int Ptag, int Pclass);ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING *a,unsigned char *pp,long length,int type);inti2d_ASN1_SET(STACK *a, unsigned char *pp,int (*func)(), int ex_tag, int ex_class, int is_set);STACK *d2i_ASN1_SET(STACK *a, unsigned char *pp, long length,char *(*func)(), void (*free_func)(void *),int ex_tag, int ex_class);【i2d系列函数总体介绍】i2d 系列函数将一个内部的结构(c语言结构体)转换成DER编码的对象。参数a是一个指向一个结构体的指针,参数pp是一个指向并创建的DER编码字符串对象指针的指针。调用成功完成后,pp指针将被指向新生成的DER字符串的结束位置,并返回该字符串的长度。所以参数pp可以被相同的函数多次调用,以处理多个对象,并将这些对象存储成一个长DER编码的字符串。如果参数pp为NULL,则仅仅返回有效数据的长度。这种性质可以在首次调用的时候用来决定要分配的字符串空间的长度,例如下面的例子:len=i2d_my_favorite_type(a,NULL);if (string=(char *)malloc(len) = NULL) complain.i2d_my_favorite_type(a,&string);如果a为NULL,则返回0。【d2i系列函数总体介绍】d2i 系列函数将一个DER编码的对象转换为一个内部的结构(c语言结构体)。参数a是一个指向一个结构体指针的指针,用来存放转换好的内部结构对象;参数pp 是一个指向DER编码字符串对象指针的指针,参数length是*pp里面有效数据的长度。如果a为NULL,则仅仅将内部结构对象作为返回值返回;如果 a不为NULL而*a为NULL,则将为*a分配内存并存储生成的内部结构对象。如果调用失败,返回NULL。调用成功完成后,*pp将被重置到*pp+ length的位置,并返回生成的内部结构对象的地址。所以pp可以被d2i函数多次调用,以处理多个DER编码的对象。出错返回NULL,如果*a不为 NULL,那么它指向的结构会被释放。一般来说,只有在内存分配失败或者DER编码数据有误的情况下才会出错。【ASN1_OBJECT】i2d_ASN1_OBJECT 函数将一个内部结构ASN1_OBJECT的对象a转换成DER编码的对象;d2i_ASN1_OBJECT函数则是将参数pp里DER编码的对象数据转换成一个ASN1_OBJECT结构的对象。其参数a,pp和length跟上面介绍的是一样意义的。【ASN1_BOOLEAN】i2d_ASN1_BOOLEAN 函数将一个内部结构ASN1_BOOLEAN的对象a转换成DER编码的对象;d2i_ASN1_BOOLEAN函数则是将参数pp里DER编码的对象数据转换成一个ASN1_BOOLEAN结构的对象。其参数a,pp和length跟上面介绍的是一样意义的。openssl之ASN.1系列之6-编码转换函数i2d和d2i(二)作者:DragonKing(Eric Wang)Mail: 版权声明:未经作者授权,本文不能在任何商业性质的出版物或网站上进行转载发布网站:OpenSSL版本:openssl-0.9.7【ASN1_bytes】int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char *pp, int tag, int xclass);ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING *a, unsigned char *pp,long length, int Ptag, int Pclass);这两个函数其实是相对来说比较底层的函数,一般不直接使用他们,而是使用基于他们的宏定义函数。可以看到,跟其他i2d和d2i函数一样,这两个函数也有参数a和pp,其含义跟前面介绍是相同的。i2d_ASN1_bytes函数中的参数tag是定义的对象的tag值,可能的值包括在下面:#define V_ASN1_UNDEF-1#define V_ASN1_EOC0#define V_ASN1_BOOLEAN1#define V_ASN1_INTEGER2#define V_ASN1_NEG_INTEGER(2 | V_ASN1_NEG)#define V_ASN1_BIT_STRING3#define V_ASN1_OCTET_STRING4#define V_ASN1_NULL5#define V_ASN1_OBJECT6#define V_ASN1_OBJECT_DESCRIPTOR7#define V_ASN1_EXTERNAL8#define V_ASN1_REAL9#define V_ASN1_ENUMERATED10#define V_ASN1_NEG_ENUMERATED(10 | V_ASN1_NEG)#define V_ASN1_UTF8STRING12#define V_ASN1_SEQUENCE16#define V_ASN1_SET17#define V_ASN1_NUMERICSTRING18#define V_ASN1_PRINTABLESTRING19#define V_ASN1_T61STRING20#define V_ASN1_TELETEXSTRING20#define V_ASN1_VIDEOTEXSTRING21#define V_ASN1_IA5STRING22#define V_ASN1_UTCTIME23#define V_ASN1_GENERALIZEDTIME24#define V_ASN1_GRAPHICSTRING25#define V_ASN1_ISO64STRING26#define V_ASN1_VISIBLESTRING26#define V_ASN1_GENERALSTRING27#define V_ASN1_UNIVERSALSTRING28#define V_ASN1_BMPSTRING30参数xclass可能的值如下:#define V_ASN1_UNIVERSAL0x00#define V_ASN1_APPLICATION0x40#define V_ASN1_CONTEXT_SPECIFIC0x80#define V_ASN1_PRIVATE0xc0这两个参数的信息用来填写DER编码的标识字节,没有这些信息,函数就会只是对ASN1_STRING对象进行没有意义或错误的编码。比如你如果不给ASN1_INTEGER类型对象一个tag值,那么返回的编码就是一堆没有意义的垃圾代码。d2i_ASN1_bytes 函数比其他d2i函数也多两个参数,Ptag和Pxclass,是两个指针,分别是用来存放从标识字节读出的上述tag和class值。没有这两个值,函数就只是将DER对象作为ASN1_STRING对象进行处理,确定不了类型。该函数返回一个ASN1_STRING对象。【ASN1_type_bytes】ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING *a,unsigned char *pp,long length,int type);本函数也是一个底层的函数。相比于其他d2i函数,本函数多了一个参数type,该参数有效的值如下:#define B_ASN1_NUMERICSTRING0x0001#define B_ASN1_PRINTABLESTRING0x0002#define B_ASN1_T61STRING0x0004#define B_ASN1_TELETEXSTRING0x0008#define B_ASN1_VIDEOTEXSTRING0x0008#define B_ASN1_IA5STRING0x0010#define B_ASN1_GRAPHICSTRING0x0020#define B_ASN1_ISO64STRING0x0040#define B_ASN1_VISIBLESTRING0x0040#define B_ASN1_GENERALSTRING0x0080#define B_ASN1_UNIVERSALSTRING0x0100#define B_ASN1_OCTET_STRING0x0200#define B_ASN1_BIT_STRING0x0400#define B_ASN1_BMPSTRING0x0800#define B_ASN1_UNKNOWN0x1000#define B_ASN1_UTF8STRING0x2000#define B_ASN1_UTCTIME0x4000#define B_ASN1_GENERALIZEDTIME0x8000该函数完成的功能跟d2i_ASN1_bytes函数是一样的,不过,如果从DER对象解码得到的对象类型跟type参数给定的类型不一致,那么,就会出错返回NULL。如果没有这个参数,就不能确定得到对象的类型,只是返回一个ASN1_STRING的指针。openssl之ASN.1系列之7-编码转换函数i2d和d2i(三)作者:DragonKing(Eric Wang)Mail: 版权声明:未经作者授权,本文不能在任何商业性质的出版物或网站上进行转载发布网站:OpenSSL版本:openssl-0.9.7【ASN1_SET】inti2d_ASN1_SET(STACK *a, unsigned char *pp,int (*func)(), int ex_tag, int ex_class, int is_set);STACK *d2i_ASN1_SET(STACK *a, unsigned char *pp, long length,char *(*func)(), void (*free_func)(void *),int ex_tag, int ex_class);这两个函数对ASN1_SET和ASN1_SEQUENCE类型的对象进行内部对象和DER编码之间的转换。1.i2d_ASN1_SET函数参数a和pp是跟前面介绍的意义是一样的。参数ex_tag的值可能如如下:V_ASN1_SETV_ASN1_SEQUENCE参数ex_class的值可能如下:V_ASN1_UNIVERSALV_ASN1_CONTEXT_SPECIFIC参数func指向一个i2d_*形式的函数指针,它用来对参数a的STACK中的每一个元素进行内部结构向DER编码转换的操作。这个STACK包括了将要组成整个SET或SEQUENCE的ASN1结构的有序集合。例如,如果STACK中包含了一些列X509_ATTRIBUTE对象,那么你可以调用下面的函数得到DER编码的SET对象:i2d_ASN1_SET(sk,&p,i2d_X509_ATTRIBUTE,V_ASN1_SET,V_ASN1_UNIVERSAL)2.d2i_ASN1_SET函数改函数跟其它d2i函数完成的功能是一样的,其参数a、pp、ex_tag和ex_class跟上面的函数里同名参数的意义是一样的。参数func是 d2i_*形式的函数,用来对DER编码的SET或SEQUENCE对象中的每个对象进行DER解码并创建相应的ASN1结构,然后将创建的对象结构存放在STACK参数a中,返回该对象的指针。如果出错,该函数返回NULL。【ASN1_STRING相关的宏定义函数】前面我们介绍过,OpenSSL里面许多ASN1对象类型的底层其实是ASN1_STRING类型的宏定义,所以OpenSSL提供了一系列宏定义函数对这些类型相应的tag和class进行正确的DER编解码处理,这些函数的形式一般为:M_i2d_*M_d2i_*他们的参数也跟前面介绍过的同名参数意义一样。为了方便查找,把这些宏定义函数列出如下:#define M_i2d_ASN1_OCTET_STRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,V_ASN1_UNIVERSAL)#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,a-type,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_PRINTABLE(a,pp,l) d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l, B_ASN1_PRINTABLE)#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,a-type,V_ASN1_UNIVERSAL)#define M_d2i_DIRECTORYSTRING(a,pp,l) d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l, B_ASN1_DIRECTORYSTRING)#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,a-type,V_ASN1_UNIVERSAL)#define M_d2i_DISPLAYTEXT(a,pp,l) d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_DISPLAYTEXT)#define M_i2d_ASN1_PRINTABLESTRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_PRINTABLESTRING)#define M_i2d_ASN1_T61STRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_T61STRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_T61STRING(a,pp,l) (ASN1_T61STRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_T61STRING)#define M_i2d_ASN1_IA5STRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_IA5STRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_IA5STRING(a,pp,l) (ASN1_IA5STRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_IA5STRING)#define M_i2d_ASN1_GENERALSTRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_GENERALSTRING(a,pp,l) (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_GENERALSTRING)#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_UNIVERSALSTRING)#define M_i2d_ASN1_BMPSTRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_BMPSTRING(a,pp,l) (ASN1_BMPSTRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_BMPSTRING)#define M_i2d_ASN1_VISIBLESTRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_VISIBLESTRING)#define M_i2d_ASN1_UTF8STRING(a,pp) i2d_ASN1_bytes(ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,V_ASN1_UNIVERSAL)#define M_d2i_ASN1_UTF8STRING(a,pp,l) (ASN1_UTF8STRING *)d2i_ASN1_type_bytes(ASN1_STRING *)a,pp,l,B_ASN1_UTF8STRING)下面是有关的OpenSSL内部结构和ASN.1定义的对象的对照列表:ASN1_BIT_STRING BIT STRING ASN1_BMPSTRINGBMPString ASN1_GENERALIZEDTIMEGeneralizedTime ASN1_GENERALSTRING GeneralString ASN1_INTEGER INTEGER ASN1_OCTET_STRING OCTET STRING AS

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论