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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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:\t");
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]='\0';
424         }else if(type==0x17||type==0x18){
425             int d=len0;
426             fread(s,1,d,fp);
427             s[d]='\0';
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!\n");
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\n",ca_cer.cat.version.s1,ca_cer.cat.version.s2);
485     printf("【序列號】%s%s\n",ca_cer.cat.serialNumber.s1,ca_cer.cat.serialNumber.s2);
486     printf("【簽名算法】%s%s\n",ca_cer.cat.signature.algorithm.s1,ca_cer.cat.signature.algorithm.s2);
487     printf("【簽名算法的參數】%s%s\n",ca_cer.cat.signature.parameters.s1,ca_cer.cat.signature.parameters.s2);
488     printf("【簽發者標識信息】issuer\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n",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\n",ca_cer.cat.validity[0].s2,ca_cer.cat.validity[1].s2);
490     printf("【主體標識信息】subject\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n",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\n",ca_cer.cat.subjectPublicKeyInfo.algorithm.s1,ca_cer.cat.subjectPublicKeyInfo.algorithm.s2);
492     printf("【公鑰的加密算法參數】%s%s\n",ca_cer.cat.subjectPublicKeyInfo.parameters.s1,ca_cer.cat.subjectPublicKeyInfo.parameters.s2);
493     printf("【公鑰數據】%s%s\n",ca_cer.cat.subjectPublicKeyInfo.PKey.s1,ca_cer.cat.subjectPublicKeyInfo.PKey.s2);
494     printf("【簽發者唯一標識符】issuerUniqueID:     無\n");
495     printf("【主體唯一標識符】subjectUniqueID:     無\n");
496     printf("【擴展】extendsions:     省略\n");
497     printf("【簽名算法】%s%s\n",ca_cer.casa.algorithm.s1,ca_cer.casa.algorithm.s2);
498     printf("【簽名算法的參數】%s%s\n",ca_cer.casa.parameters.s1,ca_cer.casa.parameters.s2);
499     printf("【簽名結果】%s%s\n",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函數,這個地方對我的證書依賴性太強,沒有去特意解決。不過我想加幾個變量監控下就可以解決。這里先紙上談兵好了。同時也得承認,自己編程能力需要提高了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM