文章目錄
- 1 X.509 證書結構描述
- 1.1 整體結構
- 1.2 證書内容
- 1.3 編碼
- 2 源代碼
- 3 編譯運作結果
1 X.509 證書結構描述
1.1 整體結構
證書内容、簽名算法、簽名結果。
tbsCertificate | TBSCertificate |
---|---|
signatureAlgorithm | AlgorithmIdentifier |
signatureValue | BIT STRING |
1.2 證書内容
成員 | ASN.1文法(類型) |
---|---|
版本号Version | Version |
序列号Serial Number | CertificateSerialNumber |
簽名算法signature | AlgorithmIdentifier |
頒布者issuer | Name |
有效期validity | Validity |
主體subject | Name |
主體公鑰資訊subjectPublicKeyInfo | SubjectPublicKeyInfo |
頒發者唯一辨別符issuerUniqueID | IMPLICIT UniqueIdentifier OPTIONAL |
主體唯一辨別符subjectUniqueID | IMPLICIT UniqueIdentifier OPTIONAL |
拓展項extensions | EXPLICIT Extensions OPTIONAL |
其中:
1.2.1 版本号
版本(version)為整數格式。到目前為止,證書格式的版本隻有v1、v2、v3,分别用整數0、1、2表示。
ASN.1描述如下:
Version::=INTEGER {v1(0),v2(1),v3(2)}
複制
1.2.2 序列号
整數格式。
ASN.1描述如下:
CertificateSerialNumber::=INTEGER
複制
證書序列号用來在某一個CA内唯一地辨別一張證書。由此,“頒布者”和“證書序列号”配合起來就能唯一地辨別一張數字證書。
1.2.3 簽名算法
CA簽發證書時所使用的數字簽名算法,與signatureAlgorithm的值必須一緻。
1.2.4 頒布者和主體
簽發證書的CA實體和證書持有者實體。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
複制
RDN(Relative Distinguished Name)用“屬性類型=屬性值”的形式表示。常用的屬性類型名稱以及簡寫如下:
屬性類型名稱 | 含義 | 簡寫 |
---|---|---|
Common Name | 通用名稱 | CN |
Organizational Unit name | 機構單元名稱 | OU |
Organization name | 機構名 | O |
Locality | 地理位置 | L |
State or province name | 州/省名 | S |
Country | 國名 | C |
1.2.5 有效期
證書的有效使用期,包含起、止兩個時間值。
ASN.1描述:
Validity::=SEQUENCE{
notBefore Time,
notAfter Time
}
Time::=CHOICE{
utcTime UTCTime,
generalTime GeneralizedTime
}
複制
2049年以前的,采用UTCTime。
1.2.6 主體公鑰資訊
證書所綁定的加密算法和公鑰。
SubjectPublicKeyInfo::=SEQUENCE{
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
複制
1.2.7 頒布者唯一辨別符和主體唯一辨別符
issuerUniqueID和subjectUniqueID隻能在版本2或者3中出現;extensions隻能在版本3中出現。
ASN.1描述:
UniqueIdentifier::=BIT STRING
複制
1.2.8 拓展項
隻能在版本3中出現。
1.3 編碼
X.509證書的結構用ASN1(Abstract Syntax Notation One)描述資料結構,并使用ASN1文法進行編碼。
ASN1采用一個個的資料塊來描述整個資料結構,每個資料塊都有四個部分組成。
1.3.1 資料塊資料類型辨別(一個位元組)
資料類型包括簡單類型和結構類型。
1.3.1.1 bit8-bit7
用來标示 TAG (bit5-bit1)類型,共有四種,分别是universal(00)、application(01)、context-specific(10)和private(11)。
1.3.1.2 bit6
表示是否為結構類型。1為結構類型,0為簡單類型。
1.3.1.3 bit5-bit1
類型的TAG值。根據bit8-bit7的不同值有不同的含義。
整個位元組表示資料類型。常見的有:
BOOLEAN:01
INTEGER:02
BIT STRING:03
OCTET STRING:04
NULL:05
OBJECT IDENTIFIER:06
PrintableString:13
UTCTime:17
GeneralizedTime:18
序列構造類型SEQUENCE與SEQUENCE OF:0x30
集合構造類型SET和SET OF:0x31
1.3.2 資料塊長度(1-128個位元組)
長度字段,有兩種編碼格式。
若長度值小于等于127,則用一個位元組表示,bit8 = 0,bit7-bit1存放長度值;
若長度值大于127,則用多個位元組表示,可以有2到127個位元組。第一個位元組的第8位為1,其它低7位給出後面該域使用的位元組數量,從該域第二個位元組開始給出資料的長度,高位優先。
還有一種特殊情況,這個位元組為0x80,表示資料塊長度不定,由資料塊結束辨別結束資料塊。
1.3.3 資料塊的值
存放資料塊的值,具體編碼随資料塊類型不同而不同。
1.3.4 資料塊結束辨別(可選)
結束标示字段,兩個位元組(0x0000),隻有在長度值為不定時(資料塊長度字段為0x80)才會出現。
2 源代碼
# include <iostream>
# include <string.h>
# include <stdlib.h>
# include <map>
using namespace std;
typedef unsigned char byte;
struct Algorithm{
string algorithm;
string parameters;
};
struct SubjectPublicKeyInfo{
Algorithm algorithm;
string SubjectPublicKey;
};
struct TBSCertificate{
char version;
string serialNumber;
Algorithm signature;
string issuer[8];
string validity[2];
string subject[8];
SubjectPublicKeyInfo subjectPublicKeyInfo;
string issuerUniqueID;
string subjectUniqueID;
};
struct Certificate{
TBSCertificate tbsCertificate;
Algorithm signatureAlgorithm;
string Signature;
};
Certificate certificate;
char value[1000];
map<string, string> sa; // OID對應的算法
map<string, string> issuerInfo; // OID對應的屬性名
int end = 1;
FILE *fp;
int count = 0;
void OID();
void show(int);
int block();
int main(){
// 打開檔案
string file = "../測試證書/ca.cer";
fp = fopen(file.c_str(), "rb");
if (fp == NULL){
cout << "Can't open the file!";
exit(0);
}
cout << "Certificate" << endl
<< "\tTBS Certificate" << endl;
OID();
block();
fclose(fp);
}
void OID(){
sa.insert(pair<string, string>("1.2.840.113549.1.1.1", "RSA"));
sa.insert(pair<string, string>("1.2.840.113549.1.1.2", "md2RSA"));
sa.insert(pair<string, string>("1.2.840.113549.1.1.3", "md4RSA"));
sa.insert(pair<string, string>("1.2.840.113549.1.1.4", "md5RSA"));
sa.insert(pair<string, string>("1.2.840.113549.1.1.5", "sha1RSA"));
sa.insert(pair<string, string>("1.2.840.10040.4.1", "DSA"));
sa.insert(pair<string, string>("1.2.840.10040.4.3", "sha1DSA"));
issuerInfo.insert(pair<string, string>("2.5.4.3", "Common Name"));
issuerInfo.insert(pair<string, string>("2.5.4.6", "Country"));
issuerInfo.insert(pair<string, string>("2.5.4.7", "Locality"));
issuerInfo.insert(pair<string, string>("2.5.4.8", "Sate or province name"));
issuerInfo.insert(pair<string, string>("2.5.4.10", "Organization name"));
issuerInfo.insert(pair<string, string>("2.5.4.11", "Organizational Unit name"));
}
void show(int count){
switch(count){
case 4:
cout << "\tVersion: ";
if(strcmp(value, "00")) cout << "v1" << endl;
else if(strcmp(value, "01")) cout << "v2" << endl;
else if(strcmp(value, "02")) cout << "v3" << endl;
break;
case 5:
cout << "\tSerial Number: " << value << endl;
break;
case 7:{
string s = value;
cout << "\tSignature: " << sa.at(s) << endl;
break;
}
case 8:
cout << "\t\tParameters: " << value << endl;
break;
case 9:
cout << "\tIssuer: " << endl;
break;
case 12:
case 16:
case 20:
case 24:
case 28:
case 32:
case 40:
case 44:
case 48:
case 52:
case 56:
case 60:
{
string s = value;
if(issuerInfo.find(s) != issuerInfo.end()) cout << "\t\t" << issuerInfo.at(s) << ": ";
break;
}
case 13:
case 17:
case 21:
case 25:
case 29:
case 33:
case 41:
case 45:
case 49:
case 53:
case 57:
case 61:
cout << value << endl;
break;
case 34:
cout << "\tValidity: " << endl;
break;
case 35:
cout << "\t\tNot Before: " << value << endl;
break;
case 36:
cout << "\t\tNot After: " << value << endl;
break;
case 37:
cout << "\tSubject: " << endl;
break;
case 62:
cout << "\tSubject Public Key Info: " << endl;
break;
case 64:{
string s = value;
cout << "\t\tAlgorithm: " << sa.at(s) << endl;
break;
}
case 65:{
cout << "\t\t\tParameters: " << value << endl;
break;
}
case 66:{
cout << "\t\tSubject Public Key: " << value << endl;
break;
}
case 69:{
string s = value;
cout << endl << "Signature Algorithm: " << sa.at(s) << endl;
break;
}
case 70:
cout << "\tParameters: " << value << endl;
break;
case 71:
cout << "Signature: " << value << endl;
end = 0;
break;
}
}
int block(){
if(end == 0) return 1000;
count++;
bool flag = true;
byte type = fgetc(fp); // type
byte len0 = fgetc(fp); // length
int len = len0;
if(len > 0x80){ // 計算長度
int lenOfLen = len - 0x80;
byte b;
len = 0;
for(int i = 0; i < lenOfLen; i++){
b = fgetc(fp);
len *= 256;
len += b;
}
}
if(type < 0xa0){
switch(type){
case 1:{ // BOOLEAN
byte temp = fgetc(fp);
if(temp == 0) strcpy(value, "FALSE");
else strcpy(value, "TRUE");
break;
}
case 2: // INTEGER
case 3: // BIT STRING
case 4: // OCTET STRING
strcpy(value,"");
for(int i = 0; i < len; i++){
byte b = fgetc(fp);
int d = b;
char temp[5];
sprintf(temp, "%02x", d);
strcat(value, temp);
}
break;
case 5: // NULL
strcpy(value, "NULL");
break;
case 6:{ // OBJECT IDENTIFIER
strcpy(value, "");
byte t = fgetc(fp);
int i = t / 40;
char temp[5];
sprintf(temp, "%d", i);
strcat(value, temp);
strcat(value, ".");
i = t % 40;
sprintf(temp, "%d", i);
strcat(value, temp);
for(int i = 1; i < len;){
strcat(value, ".");
int next = 0; //下一個整數
while(true){
t = fgetc(fp);
i++;
bool over = true;
if(t & 0x80){ // 最高位為1
over = false;
t &= 0x7f; // 将最高位還原為0
}
next *= 128;
next += t;
if(over) break;
}
sprintf(temp, "%d", next);
strcat(value, temp);
}
}
break;
case 0x13: // PrintableString
case 0x17: // UTCTime
case 0x18: // GeneralizedTime
fread(value, 1, len, fp);
value[len] = '\0';
break;
case 0x30:
case 0x31:
flag = false;
if(count == 9 || count == 34 || count == 37 || count == 62){
show(count);
}
for(int i = 0; i < len; i += block())
;
break;
default:
cout << "Error!";
exit(0);
}
}
else{
flag = false;
if(type == 0xa0) block();
else if(count == 67) fseek(fp, len, SEEK_CUR);
}
if(flag) show(count);
return len;
}
複制
3 編譯運作結果
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcuQ2YwYjYjZGM2ImY3EGO0MWOzM2YzQ2NlR2Y5MjN4EWOvwlN5EDN2gzNtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
與證書對比: