OpenSSL API: asn1_par.c源码分析
序
openssl有关asn1编解码的函数都定义在crypto/asn1/asn1_par.c
下,这些函数直接在官方文档里是找不到的,也就是说openssl其实没有直接暴露asn1编解码的接口,而是在这之上又封装了一层证书格式,比如X509
。
但是由于我们要做的是asn1的解码器,而不是针对证书格式的解码,所以无法直接调用openssl暴露的接口,只能通过学习源码来编写API供后面的软件使用。
概览
原型
一共有五个函数
static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, int indent)
int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, int dump)
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, int offset, int depth, int indent, int dump)
const char *ASN1_tag2str(int tag)
功能
ASN1_parse()
,ASN1_parse_dump()
openssl asn1parse
命令直接调用的函数,其实内部都调用了asn1_parse2()
,唯一的区别就是输出格式的不同,详情看后面的分析asn1_parse2()
真正进行解码的函数。本函数用于将pp
和len
指明的DER编码值写在BIO中,其中indent
和dump
用于设置打印的格式。indent用来设置打印出来当列之间空格个数,ident
越小,打印内容越紧凑。dump
表明当asn1单元为BIT STRING
或OCTET STRING
时,打印内容的字节数ASN1_tag2str()
根据tag的值返回对应类型的名称字符串asn1_print_info()
按格式打印解码出的asn1信息
ASN1_parse/ASN1_parse_dump
不多说
ASN1_tag2str
将tag值和类型名称对应起来
asn1_print_info
输出传入的结构是结构化的还是原始的,以及对应的tag
asn1_parse2
重头戏,首先要明白这是个递归函数
参数
BIO *bp
解析过程中所有的结果都会写入这个BIO中const unsigned char *pp
其中包含需要解析的二进制数据long length
,pp
中需要解析二进制数据的长度int offset
偏移量,初始值0,在递归过程中会被修改int depth
深度。众所周知,asn1其实也是个树形结构,depth也就是当前所在树的深度,初始值为0,在递归过程中会被修改int indent
用来设置打印出来当列之间空格个数,ident
越小,打印内容越紧凑int dump
表明当asn1单元为BIT STRING
或OCTET STRING
时,打印内容的字节数
整体结构
asn1_parse2(){
while (length > 0) {
if(xxx){
...
goto end;
}
if(xxx){
asn1_parse2()
}
length -= len
}
end:
free();
return ret;
}
详细分析
接下来一步一步分析
超过最大递归层数时退出
ASN1_get_object
定义在asn1_lib.c
中,会在其中修改传入的指针位置,hl
计算出头部长度,然后length
从中减掉hl
(long)offset + (long)(op - *pp)
算出偏移
依次输出层数、头部长度、长度,以及调用asn1_print_info
如果当前解析的结构是结构化的,那么递归调用asn1_parse2,对内层进行解析