证书内容、签名算法、签名结果。
tbsCertificate | TBSCertificate |
---|---|
signatureAlgorithm | AlgorithmIdentifier |
signatureValue | BIT STRING |
成员 | 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中出现。
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)才会出现。
# include
# include
# include
# include
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;
}