1. 程式人生 > WINDOWS開發 >OpenSSL API: asn1_par.c原始碼分析

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,int indent,int dump)
static int asn1_parse2(BIO *bp,const unsigned char **pp,long length,int offset,int depth,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,對內層進行解析