这个解析程序使用C++写成,更多详细内容可参考GitHub项目。
X.509证书结构
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate, -- 证书主体
signatureAlgorithm AlgorithmIdentifier, -- 证书签名算法标识
signatureValue BIT STRING -- 证书签名值,是使用signatureAlgorithm部分指定的签名算法
对tbsCertificate证书主题部分签名后的值.
}
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1, -- 证书版本号
serialNumber CertificateSerialNumber, -- 证书序列号,对同一CA所颁发的证书,序列号唯一标识证书
signature AlgorithmIdentifier, -- 证书签名算法标识
issuer Name, -- 证书发行者名称
validity Validity, -- 证书有效期
subject Name, -- 证书主体名称
subjectPublicKeyInfo SubjectPublicKeyInfo, -- 证书公钥
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, -- 证书发行者ID(可选),只在证书版本2、3中才有
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- 证书主体ID(可选),只在证书版本2、3中才有
extensions [3] EXPLICIT Extensions OPTIONAL -- 证书扩展段(可选),只在证书版本3中才有
}
Version ::= INTEGER { v1(0), v2(1), v3(2) } -- 版本号(v1,v2,v3)
CertificateSerialNumber ::= INTEGER -- 证书序列号存储结构
AlgorithmIdentifier ::= SEQUENCE { -- 签名算法标识存储结构
algorithm OBJECT IDENTIFIER, -- 签名算法名称
parameters ANY DEFINED BY algorithm OPTIONAL -- 签名算法参数
}
parameters: -- DSA(DSS)算法时的参数,RSA算法没有此参数
Dss-Parms ::= SEQUENCE {
p INTEGER,
q INTEGER,
g INTEGER
}
signatureValue: -- sha1DSA签名算法时,签名值存储结构
Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER
}
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
Validity ::= SEQUENCE { -- 证书有效期存储结构
notBefore Time, -- 证书有效期起始时间
notAfter Time -- 证书有效期终止时间
}
Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime
}
UniqueIdentifier ::= BIT STRING -- 证书唯一标识存储结构
SubjectPublicKeyInfo ::= SEQUENCE { -- 证书公钥存储结构
algorithm AlgorithmIdentifier, -- 公钥算法
subjectPublicKey BIT STRING -- 公钥值
}
subjectPublicKey: -- RSA算法时的公钥值
RSAPublicKey ::= SEQUENCE {
modulus INTEGER,
publicExponent INTEGER
}
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension -- 拓展部分存储结构
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
}
输出效果
C++代码
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <cstdlib>
using namespace std;
struct Seg {
int num;
Seg(unsigned char s){
num = (int)s;
};
Seg() {
num = -1;
}
};
typedef struct Seg Seg;
struct TLV {
Seg type;
vector<Seg> length;
vector<Seg> value;
};
typedef struct TLV TLV;
struct SignatureAlgorithm {
TLV algorithm;
TLV parameters;
};
struct subjectPublicKey {
TLV algorithm;
TLV parameters;
TLV PKey;
};
struct SignatureValue {
TLV signatureValue;
};
struct signatureArray {
TLV s1, s2;
};
typedef struct SignatureAlgorithm SignatureAlgorithm;
typedef struct subjectPublicKey subjectPublicKey;
typedef struct SignatureValue SignatureValue;
typedef struct signatureArray signatureArray;
struct TbsCertificate{
TLV version;
TLV serialNumber;
SignatureAlgorithm signature;
vector<signatureArray> issuer_;
vector<TLV> validity;
vector<signatureArray> subject_;
subjectPublicKey subjectPublicKeyInfo;
TLV issuerUniqueID;
TLV subjectUniqueID;
vector<TLV> extensions;
};
struct X509cer {
struct TbsCertificate catb;
struct SignatureAlgorithm casa;
struct SignatureValue casv;
};
class X509Reader {
private:
vector<Seg> segList;
vector<TLV> tlvList;
struct X509cer x509cert;
map<string, string> OIDMap;
public:
X509Reader() {
OIDMap.insert(pair<string, string>("1.2.840.10040.4.1","DSA"));
OIDMap.insert(pair<string, string>("1.2.840.10040.4.3","sha1DSA"));
OIDMap.insert(pair<string, string>("1.2.840.113549.1.1.1","RSA"));
OIDMap.insert(pair<string, string>("1.2.840.113549.1.1.2","md2RSA"));
OIDMap.insert(pair<string, string>("1.2.840.113549.1.1.3","md4RSA"));
OIDMap.insert(pair<string, string>("1.2.840.113549.1.1.4","md5RSA"));
OIDMap.insert(pair<string, string>("1.2.840.113549.1.1.5","sha1RSA"));
OIDMap.insert(pair<string, string>("1.2.840.113549.1.1.11","sha256RSA"));
OIDMap.insert(pair<string, string>("1.2.840.10045.2.1","ECC"));
OIDMap.insert(pair<string, string>("1.2.840.10045.3.1.7","ECDSA_P256"));
OIDMap.insert(pair<string, string>("2.5.4.6","C"));
OIDMap.insert(pair<string, string>("2.5.4.8","S"));
OIDMap.insert(pair<string, string>("2.5.4.7","L"));
OIDMap.insert(pair<string, string>("2.5.4.10","O"));
OIDMap.insert(pair<string, string>("2.5.4.11","OU"));
OIDMap.insert(pair<string, string>("2.5.4.3","CN"));
}
void loadFile(string filename) {
std::ifstream file;
file.open(filename.c_str(), ios::in|ios::binary);
while(!file.eof()) {
char first;
file.read(&first, 1);
segList.push_back(Seg((unsigned char)first));
}
file.close();
}
void compileContent() {
for(int i = 0; i < segList.size(); ) {
if(segList[i].num >> 6 == 2) {
int n = segList[i].num & 0x1f;
if(n == 3) {
TLV t;
t.type = segList[i];
if(segList[i+1].num <= 0x7f) {
t.length.push_back(segList[i+1]);
i += 2;
}
else {
int l = segList[i+1].num-0x80;
int s = 0, base = 1;
for(int j = i+2+l-1; j >= i+2; j--) {
s += segList[j].num * base;
base *= 256;
}
for(int j = i+1; j < i+2+l; j++) {
t.length.push_back(segList[j]);
}
i += 2+l;
}
tlvList.push_back(t);
}
else {
TLV t;
t.type = segList[i];
t.length.push_back(segList[i+1]);
tlvList.push_back(t);
i += 2;
}
}
else {
if(segList[i].num >> 5 == 1) {
TLV t;
t.type = segList[i];
if(segList[i+1].num <= 0x7f) {
t.length.push_back(segList[i+1]);
i += 2;
}
else {
int l = segList[i+1].num-0x80;
int s = 0, base = 1;
for(int j = i+2+l-1; j >= i+2; j--) {
s += segList[j].num * base;
base *= 256;
}
for(int j = i+1; j < i+2+l; j++) {
t.length.push_back(segList[j]);
}
i += 2+l;
}
tlvList.push_back(t);
}
else {
TLV t;
t.type = segList[i];
if(segList[i+1].num <= 0x7f) {
t.length.push_back(segList[i+1]);
for(int j = i+2; j < i+2+segList[i+1].num; j++) {
t.value.push_back(segList[j]);
}
i += segList[i+1].num + 2;
}
else {
int l = segList[i+1].num-0x80;
int s = 0, base = 1;
for(int j = i+2+l-1; j >= i+2; j--) {
s += segList[j].num * base;
base *= 256;
}
for(int j = i+1; j < i+2+l; j++) {
t.length.push_back(segList[j]);
}
for(int j = i+2+l; j < i+2+l+s; j++) {
t.value.push_back(segList[j]);
}
i += 2+l+s;
}
tlvList.push_back(t);
}
}
}
}
void showX509() {
int count = 0, extensionSize = 0;
bool isExtension = false;
bool isBlock31 = false;
for(int i = 0; i < tlvList.size()-1; i++) {
if(isExtension){
extensionSize -= 1 + tlvList[i].length.size() + tlvList[i].value.size();
}
if(tlvList[i].type.num == 0x31) {
isBlock31 = true;
continue;
}
else {
if(tlvList[i].type.num == 0x30 && isBlock31 == false) {
count++;
continue;
}
else if(tlvList[i].type.num == 0x30 && isBlock31 == true) {
isBlock31 = false;
continue;
}
else if(tlvList[i].type.num == 0xa3) {
count++;
isExtension = true;
int base = 1;
for(int j = tlvList[i].length.size()-1; j >= 1; j--){
extensionSize += tlvList[i].length[j].num * base;
base *= 256;
}
continue;
}
}
if(count == 2) {
if(tlvList[i].type.num == 0xa0) {
x509cert.catb.version = tlvList[i+1];
i++;
}
else{
x509cert.catb.serialNumber = tlvList[i];
}
}
else if(count == 3) {
if(tlvList[i].type.num == 0x06) {
x509cert.catb.signature.algorithm = tlvList[i];
}
else {
x509cert.catb.signature.parameters = tlvList[i];
}
}
else if(count == 4) {
signatureArray a;
if(tlvList[i].type.num == 0x06) {
a.s1 = tlvList[i];
a.s2 = tlvList[i+1];
x509cert.catb.issuer_.push_back(a);
i+=1;
}
}
else if(count == 5) {
x509cert.catb.validity.push_back(tlvList[i]);
x509cert.catb.validity.push_back(tlvList[i+1]);
i+=1;
}
else if(count == 6) {
signatureArray a;
if(tlvList[i].type.num == 0x06) {
a.s1 = tlvList[i];
a.s2 = tlvList[i+1];
x509cert.catb.subject_.push_back(a);
i+=1;
}
}
else if(count == 8) {
if(tlvList[i].type.num == 0x06) {
subjectPublicKey sbk;
sbk.algorithm = tlvList[i];
sbk.parameters = tlvList[i+1];
sbk.PKey = tlvList[i+2];
x509cert.catb.subjectPublicKeyInfo = sbk;
i+=2;
}
}
else if(count >= 9 && isExtension) {
if(extensionSize >= 0) {
x509cert.catb.extensions.push_back(tlvList[i]);
}
if(extensionSize == 0) {
isExtension = false;
}
}
else {
if(tlvList[i].type.num == 0x06) {
x509cert.casa.algorithm = tlvList[i];
x509cert.casa.parameters = tlvList[i+1];
x509cert.casv.signatureValue = tlvList[i+2];
i += 2;
}
}
}
}
string formatDate(TLV& p) {
string result = "20";
if(p.type.num == 0x17) {
int count = 0;
for(int i = 0; i < p.value.size()-1; i+=2){
result = result + (char)p.value[i].num + (char)p.value[i+1].num;
if(count <= 1){
result += "/";
}
else if(count == 2) {
result += " ";
}
else if(count <= 4){
result += ":";
}
count++;
}
return result + " GMT";
}
else {
return "";
}
}
string formatOID(TLV& p) {
string result = "";
char num[9];
vector<int> V;
if(p.type.num == 0x06) {
for(int i = 0; i < p.value.size(); i++){
if(i == 0) {
int v2 = p.value[i].num % 40;
int v1 = (p.value[i].num -v2) / 40;
V.push_back(v1);
V.push_back(v2);
}
else {
int j = i, res = 0;
int base = 128;
while(p.value[j].num >= 0x80){
j++;
}
res = p.value[j].num;
for(int k = j-1; k >= i; k--) {
res += (p.value[k].num - 0x80) * base;
base *= 128;
}
V.push_back(res);
i = j;
}
}
for(int i = 0; i < V.size(); i++) {
sprintf(num, "%d",V[i]);
result += num;
if(i < V.size()-1){
result += ".";
}
}
return OIDMap[result];
}
else {
return "";
}
}
void displayOrigin() {
int count = 0;
for(int i = 0; i < segList.size(); i++) {
printf("%02x ", segList[i].num);
count++;
if(count == 16){
cout << endl;
count = 0;
}
}
}
void displayTLVOrigin() {
int count = 0;
bool isBlock31 = false;
for(int i = 0; i < tlvList.size(); i++) {
if(tlvList[i].type.num == 0x31) {
isBlock31 = true;
}
else {
if(tlvList[i].type.num == 0x30 && isBlock31 == false) {
count++;
}
else if(tlvList[i].type.num == 0x30 && isBlock31 == true) {
isBlock31 = false;
}
else if(tlvList[i].type.num == 0xa3){
count++;
}
}
cout << "Count: " << count << endl;
printf("type: %02x ", tlvList[i].type);
printf("length: ");
for(int j = 0; j < tlvList[i].length.size(); j++) {
printf("%02x ", tlvList[i].length[j]);
}
printf("value(%02x): ", tlvList[i].value.size());
for(int j = 0; j < tlvList[i].value.size(); j++) {
printf("%02x ", tlvList[i].value[j]);
}
printf("\n");
}
}
void printValue(TLV& p, int mode = 0) {
if(p.value.size() == 0){
printf("NULL");
}
else{
for(int i = 0; i < p.value.size(); i++) {
if(p.type.num == 0x03 && i == 0) continue;
if(p.type.num == 0x13) {
printf("%c", p.value[i].num);
}
else {
if(mode == 0) {
printf("%02x ", p.value[i].num);
}
else{
printf("%02x", p.value[i].num);
}
}
}
if (p.type.num == 0x0c) {
printf("(UTF-8)");
}
}
printf("\n");
}
void displayResult() {
printf("Version: V%d\n", x509cert.catb.version.value[0].num+1);
printf("SerialNumber: ");
printValue(x509cert.catb.serialNumber, 1);
printf("SignatureAlgorithm:\n Algorithm: ");
cout << formatOID(x509cert.catb.signature.algorithm) << endl;
printf(" Params: ");
printValue(x509cert.catb.signature.parameters);
printf("Issuer: \n");
for(int i = 0; i < x509cert.catb.issuer_.size(); i++) {
cout << " " << formatOID(x509cert.catb.issuer_[i].s1);
printf(" = ");
printValue(x509cert.catb.issuer_[i].s2);
}
printf("Validity:\n notBefore: ");
cout << formatDate(x509cert.catb.validity[0]) << endl;
printf(" notAfter: ");
cout << formatDate(x509cert.catb.validity[1]) << endl;
printf("Subject:\n");
for(int i = 0; i < x509cert.catb.subject_.size(); i++) {
cout << " " << formatOID(x509cert.catb.subject_[i].s1);
printf(" = ");
printValue(x509cert.catb.subject_[i].s2);
}
printf("subjectPublicKeyInfo:\n");
printf(" Algorithm: ");
cout << formatOID(x509cert.catb.subjectPublicKeyInfo.algorithm) << endl;
printf(" Params: ");
printValue(x509cert.catb.subjectPublicKeyInfo.parameters);
printf(" PKey: ");
printValue(x509cert.catb.subjectPublicKeyInfo.PKey);
printf("issuerUniqueID: ");
printValue(x509cert.catb.issuerUniqueID);
printf("subjectUniqueID: ");
printValue(x509cert.catb.subjectUniqueID);
printf("Extensions:\n");
printf(" Other: ellipsis\n");
/* 拓展部分不翻译
for(int i = 0; i < x509cert.catb.extensions.size(); i++) {
if(x509cert.catb.extensions[i].type.num == 0x01) {
printf(" isCACertification: ");
printValue(x509cert.catb.extensions[i]);
printf(" Other: ellipsis\n");
break;
}
}*/
printf("SignatureAlgorithm:\n");
printf(" Algorithm: ");
cout << formatOID(x509cert.casa.algorithm) << endl;
printf(" Params: ");
printValue(x509cert.casa.parameters);
printf("SignatureValue: ");
printValue(x509cert.casv.signatureValue);
}
};
int main() {
X509Reader reader;
reader.loadFile("DER_x509.cer");
//reader.displayOrigin();
reader.compileContent();
//reader.displayTLVOrigin();
reader.showX509();
reader.displayResult();
return 0;
}