zoukankan      html  css  js  c++  java
  • X.509证书的编码及解析:程序解析以及winhex模板解析

    一、证书的整体结构:证书内容、签名算法、签名结果。

    用ASN.1语法描述如下:

    Certificate::=SEQUENCE{
        tbsCertificate      TBSCertificate,
        signatureAlgorithm  AlgorithmIdentifier,
        signatureValue      BIT STRING
    }

    其中,签名算法为CA对tbsCertificate进行签名所使用的算法;类型为AlgorithmIdentifier,其ASN.1语法描述如下:

    AlgorithmIdentifier::=SEQUENCE{
        algorithm       OBJECT IDENTIFIER,
        parameters      ANY DEFINED BY algorithm OPTIONAL
    }

    其中,algorithm给出了算法的OID;可选的parameters给出算法的参数。

    需要注意,algorithm同时说明了杂凑算法和数字签名算法,常见的有:(1)MD5wihRSAEncryption, MD5 Hash函数和RSA签名算法配合使用,OID为1.2.840.113549.1.1.4。(2)SHA1withRSAEncryption, SHA-1 Hash函数和RSA签名算法配合使用,OID为1.2.840.113549.1.1.5。

    签名结果是CA对tbsCertificate进行签名的结果,类型为BIT STRING。

    证书内容是需要被CA签名的信息,ASN.1语法描述如下:

    TBSCertificate::=SEQUENCE{
        version           [0]   EXPLICIT Version DEFAULT v1,
        serialNumber            CertificateSerialNumber,
        signature               AlgorithmIdentifier,
        issuer                  Name,
        validity                Validity,
        subject                 Name,
        subjectPublicKeyInfo    SubjectPublicKeyInfo,
        issuerUniqueID    [1]   IMPLICIT UniqueIdentifier OPTIONAL,
        subjectUniqueID   [2]   IMPLICIT UniqueIdentifier OPTIONAL,
        extensions        [3]   EXPLICIT Extensions OPTIONAL
    }

    其中,issuerUniqueID和subjectUniqueID只能在版本2或者3中出现;extensions只能在版本3中出现。

    下面我们逐一说明TBSCertificate中的每一个字段。

    1>版本号

    版本(version)为整数格式。到目前为止,证书格式的版本只有v1、v2、v3,分别用整数0、1、2表示。

    其类型Version的ASN.1描述如下:

    Version::=INTEGER {v1(0),v2(1),v3(2)}

    目前最常用的版本是v3。

    2>序列号

    证书序列号(serialNumber)为整数格式。

    其类型CertificateSerialNumber的ASN.1描述如下:

    CertificateSerialNumber::=INTEGER

    证书序列号用来在某一个CA范围内唯一地标识一张证书。由此,“签发者”和“证书序列号”配合起来就能唯一地标识一张数字证书。在很多PKI的通信协议中使用的就是这种方式。

    RFC 3280标准要求证书序列号必须是正整数,且长度不应该大于20字节。

    3>签名算法

    签名算法(signature)给出了CA签发证书时所使用的数字签名算法,它的类型与signatureAlgorithm的类型相同,都为AlgorithmIdentifier,它们的值必须一致,否则该证书无效。

    4>签发者和主体

    证书的签发者(issuer)和证书主体(subject)分别标识了签发证书的CA实体和证书持有者实体,两者类型均为Name。ASN.1描述如下:

    Name::=CHOICE{
        RDNSequence
    }
    RDNSequence::=SEQUENCE OF RelativeDistinguishedName
    RelativeDistinguishedName::=SET OF AttributeTypeAndValue
    AttributeTypeAndValue::=SEQUENCE{
        type    AttributeType,
        value   AttributeValue
    }
    AttributeType::=OBJECT IDENTIFIER
    AttributeValue::=ANY DEFINED BY AttributeType

    证书的签发者和证书主体用X.509 DN表示,DN是由RDN构成的序列。RDN用“属性类型=属性值”的形式表示。常用的属性类型名称以及简写如下:

    常用RDN属性类型
    属性类型名称 含义 简写
    Common Name 通用名称 CN
    Organizational Unit name 机构单元名称 OU
    Organization name 机构名 O
    Locality 地理位置 L
    State or province name 州/省名 S
    Country 国名 C

    5>有效期

    证书有效期(validity)给出证书的有效使用期,包含起、止两个时间值。时间值可以使用UTCTime或者GeneralizedTime的形式表示。ASN.1描述如下:

    Validity::=SEQUENCE{
        notBefore       Time,
        notAfter        Time
    }
    Time::=CHOICE{
        utcTime         UTCTime,
        generalTime     GeneralizedTime
    }

    6>主体公钥信息

    主体公钥信息(subjectPublicKeyInfo)给出了证书所绑定的加密算法和公钥。其ASN.1描述如下:

    SubjectPublicKeyInfo::=SEQUENCE{
        algorithm           AlgorithmIdentifier,
        subjectPublicKey    BIT STRING
    }

    其中,algorithm表示被绑定的、证书主体持有的公钥密码算法;subjectPublicKey是具体的公钥数据,内容和格式依算法不同而异。对于RSA算法,它包含公钥参数e和n。

    7>签发者唯一标识符和主体唯一标识符

    签发者唯一标识符(issuerUniqueID)和主体唯一标识符(subjectUniqueID)给出了证书签发者和证书主体的唯一标识符。UniqueIdentifier类型的ASN.1描述如下:

    UniqueIdentifier::=BIT STRING

    二、证书编码

    针对ASN.1的语法,编码可以采用“TLV”方式,即依次对数据的类型(type)、长度(length)、值(value)编码,这样就可以完整地表示一个特定类型的数据。“TLV”方式的编码有多种,下面介绍DER这种编码方式。都是big-endian字节序。

    1.简单类型的编码

    1>BOOLEAN:01

    布尔类型,两种取值:TRUE(0xFF)、FALSE(0x00)。

    编码为:

            T      L      V
    TRUE    01     01     FF
    FALSE   01     01     00

    2>INTEGER:02

    整数类型。两种情况:

    第一种,数据长度不大于0x7F,称为“短形式”,length占1字节,直接把长度赋给length。举例:0x123456的DER编码为:

    T   L   V
    02  03  12  34 56

    第二种,数据长度大于0x7F,称为“长形式”,把数据长度L表示为字节码,计算其长度n,然后把n与0x80进行“位或”运算的结果赋给length的第一个字节。举例:0x1234...34(长0100字节),即n=2,编码为:

    T   L           V
    02  82  01  00  12  34 ...  34

    此外,对于整数,还有正负的问题。规定value的最高位表示符号---0(+) 1(-)  负数用补码表示。

    1)对于正数,如最高位为1,则向左扩展00。

    2)对于负数,如其补码的最高位为0,则向左扩展FF。

    3>BIT STRING:03

    比特串的长度可能不是8的倍数,而DER编码以字节为单位。故而,如果需要,则在比特串的最后填若干位“0”,使其长度达到8的倍数;在最前面增加1字节,写明填充的位数。特别注意:value部分的第一字节,即表示填充位数的那个字节,也要计入数据的总长度。如果不需要填充,则第一字节也需要用00来表示填充位数。举例:1011010010编码为:

    T   L   V
    03  03  06  B4 80

    4>OCTET STRING:04

    字节码串。举例:AB CD EF 01 23的编码为:

    T   L   V
    04  05  AB  CD  EF  01  23

    5>NULL:05

    编码是固定的,value部分为空,一共两字节:

    T   L
    05  00

    6>OBJECT IDENTIFIER:06

    对象标识符(OID),是一个用“.”隔开的非负整数组成的序列。下面说下OID的编码设计:设OID=V1.V2.V3.V4.V5....Vn,则DER编码的value部分规则如下:(1)计算40*V1+V2作为第一字节;(2)将Vi(i>=3)表示为128进制,每一个128进制位作为一个字节,再将除最后一个字节外的所有字节的最高位置1;(3)依次排列,就得到了value部分。举例:OID=1.2.840.11359.1.1的编码如下:

    说明:Vi的最后一个字节不对最高位置1,系统以此来识别这里是这个字段的最后一字节。

    7>PrintableString:13

    表示任意长度的ASCII字符串。举例:“Hello, world”的编码为:

    T   L   V
    13  0C  48  65  6C  6C  6F  2C  20  77  6F  72  6C  64

    8>UTCTime:17

    表示时间,可以用GMT格林威治时间(结尾标“Z”)来表示,或者是用本地时间和相对于GMT的偏移量来表示。

    UTCTime的格式如下多种:
    YYMMDDhhmmZ
    YYMMDDhhmm+hh'mm'
    YYMMDDhhmm-hh'mm'
    YYMMDDhhmmssZ
    YYMMDDhhmmss+hh'mm'
    YYMMDDhhmmss-hh'mm'

    其中,

    YY:年的最后2位
    MM:月,01-12
    DD:日,01-31
    hh:小时,00-23
    mm:分钟,00-59
    ss:秒,00-59
    Z/+/-:Z表示GMT时间,+/-表示本地时间与GMT时间的差距
    hh’:与GMT的差
    mm’:与GMT的差

    举例:北京时间2008年8月8日晚8时表示成UTCTime为:080808120000Z 或 080808200000-0800 其编码为:

    T   L   V
    17  0D  30  38  30  38  30  38  31  32  30  30  30  30  5A
    或
    T   L   V
    17  11  30  38  30  38  30  38  32  30  30  30  30  30  2D  30  38  30  30

    9>GeneralizedTime:18

    与UTCTime类似,差别只在于用4位数字表示“年”,以及“秒”可精确到千分位。举例:北京时间2008年8月8日晚8时1分2.345秒表示成GeneralizedTime为:20080808120102.345Z 或 20080808200102.345-0800 其编码为:

    T   L   V
    18  13  32  30  30  38  30  38  30  38  31  32  30  31  30  32  2E  33  34  35  5A
    或
    T   L   V
    18  17  32  30  30  38  30  38  30  38  32  30  30  31  30  32  2E  33  34  35  2D  30  38  30  30

    2.构造类型数据的编码

    1>序列构造类型:30

    SEQUENCE与SEQUENCE OF的type相同,都是30。value部分为序列内所有项目的编码的依次排列。length为这些项目编码的总长度。举例:一天中几次温度测量的结果:temperatureInADay SEQUENCE(7) OF INTEGER::={21,15,5,-2,5,10,5}, 其DER编码为:

    T   L   V
    30  15  02  01  15
            02  01  0F
            02  01  05
            02  01  FE
            02  01  05
            02  01  0A
            02  01  05

    构造类型的定义中,常常包含CHOICE、ANY、OPTIONAL、DEFAULT等关键字,其编码规则如下:

    (1)CHOICE

    多选一,按照实际选中的类型编码。举例:

    Time::=CHOICE{
        utcTime         UTCTime,
        generalizedTime GeneralizedTime
    }

    若实际用到的类型是UTCTime,则数据用UTCTime的编码规则编码。

    (2)ANY

    类型依赖于另一个域的值,则按照实际类型编码。举例:

    AlgorithmIdentifier::=SEQUENCE{
        algorithm       OBJECT IDENTIFIER,
        parameters      ANY DEFINED BY algorithm OPTIONAL
    }

    若algorithm的值表示RSA,则parameters按RSA算法的参数类型编码;若algorithm的值表示Diffie-Hellman算法,则parameters按Diffie-Hellman算法的参数类型编码。

    (3)OPTIONAL

    所标记的字段在实际中可能存在,也可能不存在。如果有值,则编码;如果无值,则直接跳过。举例:

    AlgorithmIdentifier::=SEQUENCE{
        algorithm       OBJECT IDENTIFIER,
        parameters      ANY DEFINED BY algorithm OPTIONAL
    }

    实际中,如果没有参数parameters,则相当于

    AlgorithmIdentifier::=SEQUENCE{
        algorithm       OBJECT IDENTIFIER
    }

    (4)DEFAULT

    如果所标记的字段在实际中正好等于缺省值,则可以编码也可以不编码,相当于是OPTIONAL;如果不等于缺省值,则应该如实编码。举例:

    Certificate::=SEQUENCE{
        version           Version DEFAULT 0
        ......
    }

    若version的值恰好等于0(缺省值),则可以不编码;否则,必须按其类型编码。

    2>集合构造类型:31

    SET和SET OF的type都是31,value部分包括集合内所有项目的编码,length为其总长度。需要注意的是,集合构造类型中的各字段是并列的,逻辑上不分先后,但为了编码的唯一性,在DER编码中,编码的排列是有一定顺序的。SET按标签的顺序排列。举例:

    Name::=SET{
        surname     [0] PrintableString,
        mid-name    [1] PrintableString,
        first-name  [2] PrintableString
    }

    编码时则按照surname,mid-name,first-name的顺序。

    SET OF按字典升序排列,即将各项目的DER结果看做字节码从小到大排列。举例:一天中几次温度测量的结果:temperatureInADay SET(7) OF INTEGER::={21,15,5,-2,5,10,5}, 其DER编码为:

    T   L   V
    30  15  02  01  05
            02  01  05
            02  01  05
            02  01  0A
            02  01  0F
            02  01  15
            02  01  FE

    由于排序需要一定的时间和空间代价,故而实际情况中,应避免使用集合构造类型。

    3.标签

    仅仅以上的编码规则是不够的,会有些出现歧义的情况。比如:有相邻的字段属于相同的数据类型。type相同,则根据编码的排列顺序来区分他们。一旦其中有字段是可选的,解码时就不能再仅仅根据排列顺序来判断下一个是哪个字段了,产生歧义。故而,引入了标签,目的是把相同的type标签为不同的type,以便区分。

    标签分为隐式标签和显式标签两种。分别如下:

    隐式标签:

    举例:

    Contact::=SEQUENCE{
        name                        PrintableString,
        sex                         BOOLEAN,
        title       [0] IMPLICIT    PrintableString OPTIONAL,
        locality    [1] IMPLICIT    PrintableString OPTIONAL,
        telephone   [2] IMPLICIT    PrintableString OPTIONAL,
        fax         [3] IMPLICIT    PrintableString OPTIONAL
    }

    DER编码时,对于加了标签的项目,按如下规则编码:

    对于简单类型,type=80+tag序号;对于构造类型,type=A0+tag序号。length和value不变。

    例如,上例中如果项目fax被赋值为“86-10-12345678”,则编码为

    T   L   V
    83  0E  38  36  2D  31  30  2D  31  32  33  34  35  36  37  38

    显式标签:

    举例:(隐式标签的例子)

    Record::=SEQUENCE{
        ......
        time    [1] IMPLICIT    Time    OPTIONAL,
        ......
    }
    Time::=CHOICE{
        utcTime             UTCTime,
        generalizedTime     GeneralizedTime
    }

    假设time被赋值为UTCTime类型的值080808120000Z,而由于隐式标签的type编码覆盖了表示这一类型的type编码,导致编码时无法判断time究竟是哪种类型,造成混乱。于是这里需要使用显式标签。运用显式标签,上例描述为:

    Record::=SEQUENCE{
        ......
        time    [1] EXPLICIT    Time    OPTIONAL,
        ......
    }
    Time::=CHOICE{
        utcTime             UTCTime,
        generalizedTime     GeneralizedTime
    }

    编码规则如下:

    T           L                       V
    A0+Tag序号  原TLV格式编码的总长度   原TLV格式编码  

    上例中time=080808120000Z的编码为:

    T   L   V
    A1  0F  17  0D  30  38  30  38  30  38  31  32  30  30  30  30  5A

    事实上,显式标签就是在原编码外再封装一层。

    三、证书解析 C程序

    附件(证书ca.cer):http://files.cnblogs.com/files/jiu0821/ca.cer.zip

    代码:

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 
      5 typedef struct L{
      6     int len,tag;
      7     L(){}
      8     L(int len,int tag){
      9         this->len=len;
     10         this->tag=tag;
     11     }
     12 }Len;
     13 typedef struct{
     14     char s1[50],s2[50];
     15 }TLV;
     16 typedef struct{
     17     char s1[50],s2[5000];
     18 }TLV2;
     19 struct SignatureAlgorithm{
     20     TLV algorithm;
     21     TLV parameters;
     22 };
     23 struct subjectPublicKey{
     24     TLV algorithm;
     25     TLV parameters;
     26     TLV2 PKey;
     27 };
     28 struct signatureArray{
     29     char s1[50],s2[50];
     30 }sA[7],is[6];
     31 struct SignatureValue{
     32     TLV2 signatureValue;
     33 };
     34 struct TbsCertificate{
     35     TLV version;
     36     TLV serialNumber;
     37     struct SignatureAlgorithm signature;
     38     struct signatureArray issuer_[6];
     39     TLV validity[2];
     40     struct signatureArray subject_[6];
     41     struct subjectPublicKey subjectPublicKeyInfo;
     42     TLV issuerUniqueID;
     43     TLV subjectUniqueID;
     44     TLV extensions;
     45 };
     46 struct X509cer{
     47     struct TbsCertificate cat;
     48     struct SignatureAlgorithm casa;
     49     struct SignatureValue casv;
     50 }ca_cer;//证书ca.cer的结构
     51 
     52 char s[5000];
     53 int nc,tis;
     54 bool bk=1;
     55 bool btag=1;//0-隐式  1-显式
     56 FILE *fp;
     57 
     58 void sAfill();//绑定OID
     59 void isFill();//绑定RDN
     60 void fill(int);//switch结构,把证书结构的各字段调用tlv函数的序号与证书结构内容绑定一起,对ca_cer结构进行填充
     61 Len tlv();//TLV匹配的递归
     62 void bitfill(int);//从文件里获取连续字节码(字符串),赋给字符串s
     63 void output();//依次输出ca_cer内容
     64 
     65 int main(){
     66     char *filename="D:\exercise_cpp\ca.cer";
     67     fp=fopen(filename,"rb");
     68     if(fp==NULL){
     69         puts("can't open the file!");
     70         exit(0);
     71     }
     72     sAfill();
     73     isFill();
     74     tlv();
     75     fclose(fp);
     76     output();
     77     return 0;
     78 }
     79 void sAfill(){
     80     strcpy(sA[0].s1,"1.2.840.10040.4.1");
     81     strcpy(sA[0].s2,"DSA");
     82     strcpy(sA[1].s1,"1.2.840.10040.4.3");
     83     strcpy(sA[1].s2,"sha1DSA");
     84     strcpy(sA[2].s1,"1.2.840.113549.1.1.1");
     85     strcpy(sA[2].s2,"RSA");
     86     strcpy(sA[3].s1,"1.2.840.113549.1.1.2");
     87     strcpy(sA[3].s2,"md2RSA");
     88     strcpy(sA[4].s1,"1.2.840.113549.1.1.3");
     89     strcpy(sA[4].s2,"md4RSA");
     90     strcpy(sA[5].s1,"1.2.840.113549.1.1.4");
     91     strcpy(sA[5].s2,"md5RSA");
     92     strcpy(sA[6].s1,"1.2.840.113549.1.1.5");
     93     strcpy(sA[6].s2,"sha1RSA");
     94 }
     95 void isFill(){
     96     strcpy(is[0].s1,"2.5.4.6");
     97     strcpy(is[0].s2,"Country ");
     98     strcpy(is[1].s1,"2.5.4.8");
     99     strcpy(is[1].s2,"Sate or province name ");
    100     strcpy(is[2].s1,"2.5.4.7");
    101     strcpy(is[2].s2,"Locality ");
    102     strcpy(is[3].s1,"2.5.4.10");
    103     strcpy(is[3].s2,"Organization name ");
    104     strcpy(is[4].s1,"2.5.4.11");
    105     strcpy(is[4].s2,"Organizational Unit name ");
    106     strcpy(is[5].s1,"2.5.4.3");
    107     strcpy(is[5].s2,"Common Name ");
    108 }
    109 void fill(int n){
    110     switch(n){//表示第几次调用tlv
    111         case 4:
    112             strcpy(ca_cer.cat.version.s1,"version:   ");
    113             if(strcmp(s,"0")==0)   strcpy(s,"v1");
    114             else if(strcmp(s,"1")==0)   strcpy(s,"v2");
    115             else    strcpy(s,"v3");
    116             strcpy(ca_cer.cat.version.s2,s);
    117             break;
    118         case 5:
    119             strcpy(ca_cer.cat.serialNumber.s1,"serialNumber:   ");
    120             strcpy(ca_cer.cat.serialNumber.s2,s);
    121             break;
    122         case 7:
    123             strcpy(ca_cer.cat.signature.algorithm.s1,"name of algorithm of signature:   ");
    124             for(int i=0;i<7;i++){
    125                 if(strcmp(s,sA[i].s1)==0){
    126                     strcpy(ca_cer.cat.signature.algorithm.s2,sA[i].s2);
    127                     break;
    128                 }
    129             }
    130             break;
    131         case 8:
    132             strcpy(ca_cer.cat.signature.parameters.s1,"parameters of signature:   ");
    133             strcpy(ca_cer.cat.signature.parameters.s2,s);
    134             break;
    135         case 12:
    136             for(int i=0;i<6;i++){
    137                 if(strcmp(s,is[i].s1)==0){
    138                     strcpy(ca_cer.cat.issuer_[i].s1,is[i].s2);
    139                     strcat(ca_cer.cat.issuer_[i].s1,"of issuer:	");
    140                     tis=i;
    141                     break;
    142                 }
    143             }
    144             break;
    145         case 13:
    146             strcpy(ca_cer.cat.issuer_[tis].s2,s);
    147             break;
    148         case 16:
    149             for(int i=0;i<6;i++){
    150                 if(strcmp(s,is[i].s1)==0){
    151                     strcpy(ca_cer.cat.issuer_[i].s1,is[i].s2);
    152                     strcat(ca_cer.cat.issuer_[i].s1,"of issuer:	");
    153                     tis=i;
    154                     break;
    155                 }
    156             }
    157             break;
    158         case 17:
    159             strcpy(ca_cer.cat.issuer_[tis].s2,s);
    160             break;
    161         case 20:
    162             for(int i=0;i<6;i++){
    163                 if(strcmp(s,is[i].s1)==0){
    164                     strcpy(ca_cer.cat.issuer_[i].s1,is[i].s2);
    165                     strcat(ca_cer.cat.issuer_[i].s1,"of issuer:	");
    166                     tis=i;
    167                     break;
    168                 }
    169             }
    170             break;
    171         case 21:
    172             strcpy(ca_cer.cat.issuer_[tis].s2,s);
    173             break;
    174         case 24:
    175             for(int i=0;i<6;i++){
    176                 if(strcmp(s,is[i].s1)==0){
    177                     strcpy(ca_cer.cat.issuer_[i].s1,is[i].s2);
    178                     strcat(ca_cer.cat.issuer_[i].s1,"of issuer:	");
    179                     tis=i;
    180                     break;
    181                 }
    182             }
    183             break;
    184         case 25:
    185             strcpy(ca_cer.cat.issuer_[tis].s2,s);
    186             break;
    187         case 28:
    188             for(int i=0;i<6;i++){
    189                 if(strcmp(s,is[i].s1)==0){
    190                     strcpy(ca_cer.cat.issuer_[i].s1,is[i].s2);
    191                     strcat(ca_cer.cat.issuer_[i].s1,"of issuer:	");
    192                     tis=i;
    193                     break;
    194                 }
    195             }
    196             break;
    197         case 29:
    198             strcpy(ca_cer.cat.issuer_[tis].s2,s);
    199             break;
    200         case 32:
    201             for(int i=0;i<6;i++){
    202                 if(strcmp(s,is[i].s1)==0){
    203                     strcpy(ca_cer.cat.issuer_[i].s1,is[i].s2);
    204                     strcat(ca_cer.cat.issuer_[i].s1,"of issuer:	");
    205                     tis=i;
    206                     break;
    207                 }
    208             }
    209             break;
    210         case 33:
    211             strcpy(ca_cer.cat.issuer_[tis].s2,s);
    212             break;
    213         case 35:
    214             strcpy(ca_cer.cat.validity[0].s1,"the begin of validity:    ");
    215             strcpy(ca_cer.cat.validity[0].s2,s);
    216             break;
    217         case 36:
    218             strcpy(ca_cer.cat.validity[1].s1,"the end of validity:    ");
    219             strcpy(ca_cer.cat.validity[1].s2,s);
    220             break;
    221         case 40:
    222             for(int i=0;i<6;i++){
    223                 if(strcmp(s,is[i].s1)==0){
    224                     strcpy(ca_cer.cat.subject_[i].s1,is[i].s2);
    225                     strcat(ca_cer.cat.subject_[i].s1,"of subject:	");
    226                     tis=i;
    227                     break;
    228                 }
    229             }
    230             break;
    231         case 41:
    232             strcpy(ca_cer.cat.subject_[tis].s2,s);
    233             break;
    234         case 44:
    235             for(int i=0;i<6;i++){
    236                 if(strcmp(s,is[i].s1)==0){
    237                     strcpy(ca_cer.cat.subject_[i].s1,is[i].s2);
    238                     strcat(ca_cer.cat.subject_[i].s1,"of subject:	");
    239                     tis=i;
    240                     break;
    241                 }
    242             }
    243             break;
    244         case 45:
    245             strcpy(ca_cer.cat.subject_[tis].s2,s);
    246             break;
    247         case 48:
    248             for(int i=0;i<6;i++){
    249                 if(strcmp(s,is[i].s1)==0){
    250                     strcpy(ca_cer.cat.subject_[i].s1,is[i].s2);
    251                     strcat(ca_cer.cat.subject_[i].s1,"of subject:	");
    252                     tis=i;
    253                     break;
    254                 }
    255             }
    256             break;
    257         case 49:
    258             strcpy(ca_cer.cat.subject_[tis].s2,s);
    259             break;
    260         case 52:
    261             for(int i=0;i<6;i++){
    262                 if(strcmp(s,is[i].s1)==0){
    263                     strcpy(ca_cer.cat.subject_[i].s1,is[i].s2);
    264                     strcat(ca_cer.cat.subject_[i].s1,"of subject:	");
    265                     tis=i;
    266                     break;
    267                 }
    268             }
    269             break;
    270         case 53:
    271             strcpy(ca_cer.cat.subject_[tis].s2,s);
    272             break;
    273         case 56:
    274             for(int i=0;i<6;i++){
    275                 if(strcmp(s,is[i].s1)==0){
    276                     strcpy(ca_cer.cat.subject_[i].s1,is[i].s2);
    277                     strcat(ca_cer.cat.subject_[i].s1,"of subject:	");
    278                     tis=i;
    279                     break;
    280                 }
    281             }
    282             break;
    283         case 57:
    284             strcpy(ca_cer.cat.subject_[tis].s2,s);
    285             break;
    286         case 60:
    287             for(int i=0;i<6;i++){
    288                 if(strcmp(s,is[i].s1)==0){
    289                     strcpy(ca_cer.cat.subject_[i].s1,is[i].s2);
    290                     strcat(ca_cer.cat.subject_[i].s1,"of subject:	");
    291                     tis=i;
    292                     break;
    293                 }
    294             }
    295             break;
    296         case 61:
    297             strcpy(ca_cer.cat.subject_[tis].s2,s);
    298             break;
    299         case 64:
    300             strcpy(ca_cer.cat.subjectPublicKeyInfo.algorithm.s1,"name of algorithm of subjectPublicKey:   ");
    301             for(int i=0;i<7;i++){
    302                 if(strcmp(s,sA[i].s1)==0){
    303                     strcpy(ca_cer.cat.subjectPublicKeyInfo.algorithm.s2,sA[i].s2);
    304                     break;
    305                 }
    306             }
    307             break;
    308         case 65:
    309             strcpy(ca_cer.cat.subjectPublicKeyInfo.parameters.s1,"parameters of algorithm of subjectPublicKey:   ");
    310             strcpy(ca_cer.cat.subjectPublicKeyInfo.parameters.s2,s);
    311             break;
    312         case 66:
    313             strcpy(ca_cer.cat.subjectPublicKeyInfo.PKey.s1,"subjectPublicKey:   ");
    314             strcpy(ca_cer.cat.subjectPublicKeyInfo.PKey.s2,s);
    315             break;
    316         case 69:
    317             strcpy(ca_cer.casa.algorithm.s1,"name of signatureAlgorithm:   ");
    318             for(int i=0;i<7;i++){
    319                 if(strcmp(s,sA[i].s1)==0){
    320                     strcpy(ca_cer.casa.algorithm.s2,sA[i].s2);
    321                     break;
    322                 }
    323             }
    324             break;
    325         case 70:
    326             strcpy(ca_cer.casa.parameters.s1,"parameters of signatureAlgorithm:   ");
    327             strcpy(ca_cer.casa.parameters.s2,s);
    328             break;
    329         case 71:
    330             strcpy(ca_cer.casv.signatureValue.s1,"signatureValue:   ");
    331             strcpy(ca_cer.casv.signatureValue.s2,s);
    332             bk=0;
    333             break;
    334     }
    335 }
    336 Len tlv(){
    337     if(bk==0)   return Len(1000,0);
    338     nc++;
    339     bool b=true;
    340     unsigned char type=fgetc(fp);//type
    341     unsigned char len0=fgetc(fp);//len
    342     int len=len0;
    343     int lem=0;
    344     if(type<0xa0){
    345         if(type==1){
    346             unsigned char vc=fgetc(fp);
    347             if(vc==0)   strcpy(s,"FALSE");
    348             else    strcpy(s,"TRUE");
    349         }else if(type==2){
    350             if(len0>0x80){
    351                 int tn2=len0-0x80;
    352                 unsigned char tl;
    353                 len=0;
    354                 for(int i=0;i<tn2;i++){
    355                     tl=fgetc(fp);
    356                     len*=256;
    357                     len+=tl;
    358                 }
    359             }
    360             bitfill(len);
    361         }else if(type==3){
    362             if(len0>0x80){
    363                 int tn2=len0-0x80;
    364                 unsigned char tl;
    365                 len=0;
    366                 for(int i=0;i<tn2;i++){
    367                     tl=fgetc(fp);
    368                     len*=256;
    369                     len+=tl;
    370                 }
    371             }
    372             bitfill(len);
    373         }else if(type==4){
    374             if(len0>0x80){
    375                 int tn2=len0-0x80;
    376                 unsigned char tl;
    377                 len=0;
    378                 for(int i=0;i<tn2;i++){
    379                     tl=fgetc(fp);
    380                     len*=256;
    381                     len+=tl;
    382                 }
    383             }
    384             bitfill(len);
    385         }else if(type==5){
    386             strcpy(s,"NULL");
    387         }else if(type==6){
    388             strcpy(s,"");
    389             int dd=len0;
    390             unsigned char tl=fgetc(fp);
    391             int d=tl/40;
    392             char ts2[10];
    393             sprintf(ts2,"%d",d);
    394             strcat(s,ts2);
    395             strcat(s,".");
    396             d=tl-d*40;
    397             sprintf(ts2,"%d",d);
    398             strcat(s,ts2);
    399             for(int i=1;i<dd;i++){
    400                 strcat(s,".");
    401                 i--;
    402                 int t=0;
    403                 while(1){
    404                     tl=fgetc(fp);
    405                     i++;
    406                     bool b2=false;
    407                     if(tl&0x80){
    408                         b2=true;
    409                     }
    410                     if(b2){
    411                          tl&=0x7f;
    412                     }
    413                     t*=128;
    414                     t+=tl;
    415                     if(!b2) break;
    416                 }
    417                 sprintf(ts2,"%d",t);
    418                 strcat(s,ts2);
    419             }
    420         }else if(type==0x13){
    421             int d=len0;
    422             fread(s,1,d,fp);
    423             s[d]='';
    424         }else if(type==0x17||type==0x18){
    425             int d=len0;
    426             fread(s,1,d,fp);
    427             s[d]='';
    428         }else if(type==0x30||type==0x31){
    429             b=false;
    430             if(len0>0x80){
    431                 len=0;
    432                 len0-=0x80;
    433                 unsigned char tl;
    434                 for(int i=0;i<len0;i++){
    435                     tl=fgetc(fp);
    436                     len*=256;
    437                     len+=tl;
    438                 }
    439             }
    440             int dlen=len;
    441             while(dlen>0){
    442                 dlen-=tlv().len;
    443             }
    444         }else{
    445             printf("the cer has errors!
    ");
    446             exit(0);
    447         }
    448     }else{
    449         b=false;
    450         lem=type-0xa0;
    451         if(len0>0x80){
    452             int tn2=len0-0x80;
    453             unsigned char tl;
    454             len=0;
    455             for(int i=0;i<tn2;i++){
    456                 tl=fgetc(fp);
    457                 len*=256;
    458                 len+=tl;
    459             }
    460         }
    461         if(btag){
    462             //这里做个简化,对扩展域进行忽略处理。
    463             if(nc==67)  fseek(fp,len,SEEK_CUR);
    464             else    tlv();
    465         }else{
    466             //这里不作具体实现,依具体类型的证书而定
    467         }
    468     }
    469     if(b)   fill(nc);
    470     return Len(len,lem);
    471 }
    472 void bitfill(int dd){
    473     strcpy(s,"");
    474     for(int i=0;i<dd;i++){
    475         unsigned char tl=fgetc(fp);
    476         int d=tl;
    477         char ts2[10];
    478         sprintf(ts2,"%02x",d);
    479         strcat(s,ts2);
    480     }
    481 }
    482 void output(){
    483     puts("ca.cer解析如下:");
    484     printf("【版本】%s%s
    ",ca_cer.cat.version.s1,ca_cer.cat.version.s2);
    485     printf("【序列号】%s%s
    ",ca_cer.cat.serialNumber.s1,ca_cer.cat.serialNumber.s2);
    486     printf("【签名算法】%s%s
    ",ca_cer.cat.signature.algorithm.s1,ca_cer.cat.signature.algorithm.s2);
    487     printf("【签名算法的参数】%s%s
    ",ca_cer.cat.signature.parameters.s1,ca_cer.cat.signature.parameters.s2);
    488     printf("【签发者标识信息】issuer
    %s%s
    %s%s
    %s%s
    %s%s
    %s%s
    %s%s
    ",ca_cer.cat.issuer_[0].s1,ca_cer.cat.issuer_[0].s2,ca_cer.cat.issuer_[1].s1,ca_cer.cat.issuer_[1].s2,ca_cer.cat.issuer_[2].s1,ca_cer.cat.issuer_[2].s2,ca_cer.cat.issuer_[3].s1,ca_cer.cat.issuer_[3].s2,ca_cer.cat.issuer_[4].s1,ca_cer.cat.issuer_[4].s2,ca_cer.cat.issuer_[5].s1,ca_cer.cat.issuer_[5].s2);
    489     printf("【有效期】validity:      %s-%s
    ",ca_cer.cat.validity[0].s2,ca_cer.cat.validity[1].s2);
    490     printf("【主体标识信息】subject
    %s%s
    %s%s
    %s%s
    %s%s
    %s%s
    %s%s
    ",ca_cer.cat.subject_[0].s1,ca_cer.cat.subject_[0].s2,ca_cer.cat.subject_[1].s1,ca_cer.cat.subject_[1].s2,ca_cer.cat.subject_[2].s1,ca_cer.cat.subject_[2].s2,ca_cer.cat.subject_[3].s1,ca_cer.cat.subject_[3].s2,ca_cer.cat.subject_[4].s1,ca_cer.cat.subject_[4].s2,ca_cer.cat.subject_[5].s1,ca_cer.cat.subject_[5].s2);
    491     printf("【公钥的加密算法】%s%s
    ",ca_cer.cat.subjectPublicKeyInfo.algorithm.s1,ca_cer.cat.subjectPublicKeyInfo.algorithm.s2);
    492     printf("【公钥的加密算法参数】%s%s
    ",ca_cer.cat.subjectPublicKeyInfo.parameters.s1,ca_cer.cat.subjectPublicKeyInfo.parameters.s2);
    493     printf("【公钥数据】%s%s
    ",ca_cer.cat.subjectPublicKeyInfo.PKey.s1,ca_cer.cat.subjectPublicKeyInfo.PKey.s2);
    494     printf("【签发者唯一标识符】issuerUniqueID:     无
    ");
    495     printf("【主体唯一标识符】subjectUniqueID:     无
    ");
    496     printf("【扩展】extendsions:     省略
    ");
    497     printf("【签名算法】%s%s
    ",ca_cer.casa.algorithm.s1,ca_cer.casa.algorithm.s2);
    498     printf("【签名算法的参数】%s%s
    ",ca_cer.casa.parameters.s1,ca_cer.casa.parameters.s2);
    499     printf("【签名结果】%s%s
    ",ca_cer.casv.signatureValue.s1,ca_cer.casv.signatureValue.s2);
    500 }

    结果截图:

    四、证书解析 winhex自制模板

    附件(证书ca.cer):同上

    代码:

     1 template "x.509"
     2 description "ca.cer"
     3 applies_to file
     4 fixed_start 0x00
     5 big-endian
     6 read-only
     7 begin
     8 move 2
     9 uint16 "size of cer"
    10 move 2
    11 uint16    "size of info of cer"
    12 move 4
    13 uint8        "version"
    14 move 2
    15 hex 16    "serialNumber"
    16 move 4
    17 hex 9        "signature: sha1RSA"
    18 move 15
    19 string 2        "Country of issuer"
    20 move 11
    21 string 2        "Sate or province name of issuer"    //04a
    22 move 11
    23 string 2        "Locality of issuer"        //057
    24 move 11
    25 string 5        "Organization name of issuer"        //067
    26 move 11
    27 string 2        "Organizational Unit name of issuer"    //074
    28 move 11
    29 string 6        "Common Name of issuer"    //085
    30 move 4
    31 string 13    "the begin of validity"
    32 move 2
    33 string 13    "the end of validity"        //0a5
    34 move 13
    35 string 2        "Country of subject"
    36 move 11
    37 string 2        "Sate or province name of subject"    
    38 move 11
    39 string 2        "Locality of subject"        
    40 move 11
    41 string 5        "Organization name of subject"    
    42 move 11
    43 string 2        "Organizational Unit name of subject"    
    44 move 11
    45 string 6        "Common Name of subject"    //0fc
    46 move 8
    47 hex 9        "subjectPublicKey's algorithm:RSA"    //10d
    48 move 6
    49 hex 271    "subjectPublicKey"
    50 move 188        //2de
    51 move 4
    52 hex 9        "signatureAlgorithm: sha1RSA"
    53 move 6
    54 hex 257    "sinatureValue"
    55 end

    结果截图:

    五、小结
    程序写得比较粗糙,本意只是借此来掌握x.509证书的结构,也是想玩一下,后面写得比较花时间,就在证书一些结构的细节上写得比较粗糙,比如整数的正负显示,bit串的补位等以及证书扩展没有分析(里面一些OID不认识,原理与前面类似,就作罢)。因为扩展项省略的原因,导致tlv递归函数前后不是很平衡,便加了一个return语句强行退出。总之,写完这个还是比较高兴的。O(∩_∩)O~而最大的问题在于fill函数,这个地方对我的证书依赖性太强,没有去特意解决。不过我想加几个变量监控下就可以解决。这里先纸上谈兵好了。同时也得承认,自己编程能力需要提高了。

  • 相关阅读:
    个人冲刺第七天6.15
    个人冲刺第六天6.14
    个人冲刺第五天6.11
    个人冲刺第四天6.10
    个人冲刺第三天6.9
    个人冲刺第二天6.8
    个人冲刺第一天6.7
    每日总结6.4
    oracle中CAST函数使用简介【转】
    rabbitmq安装
  • 原文地址:https://www.cnblogs.com/jiu0821/p/4598352.html
Copyright © 2011-2022 走看看