数字证书结构描述+解析的C程序设计和实现

文章目录

  • 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 
# 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;
}

3 编译运行结果

数字证书结构描述+解析的C程序设计和实现_第1张图片
与证书对比:
数字证书结构描述+解析的C程序设计和实现_第2张图片

你可能感兴趣的:(c++,算法,web安全技术,X.509,c++)