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()
    真正进行解码的函数。本函数用于将pplen指明的DER编码值写在BIO中,其中indentdump用于设置打印的格式。indent用来设置打印出来当列之间空格个数,ident越小,打印内容越紧凑。dump表明当asn1单元为BIT STRINGOCTET 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 lengthpp中需要解析二进制数据的长度
  • int offset偏移量,初始值0,在递归过程中会被修改
  • int depth深度。众所周知,asn1其实也是个树形结构,depth也就是当前所在树的深度,初始值为0,在递归过程中会被修改
  • int indent用来设置打印出来当列之间空格个数,ident越小,打印内容越紧凑
  • int dump表明当asn1单元为BIT STRINGOCTET 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,对内层进行解析

原文地址:https://www.cnblogs.com/20175211lyz/p/12815469.html