x509

X.509是一種非常通用的證書格式。所有的證書都符合ITU-T X.509國際標準,因此(理論上)為一種套用創建的證書可以用於任何其他符合X.509標準的套用。

簡介

在一份證書中,必須證明公鑰及其所有者的姓名是一致的。對X.509證書來說,認證者總是CA或由CA指定的人,一份X.509證書是一些標準欄位的集合,這些欄位包含有關用戶或設備及其相應公鑰的信息。X.509標準定義了證書中應該包含哪些信息,並描述了這些信息是如何編碼的(即數據格式)

詳細特徵

所有的X.509證書包含以下數據:

1、X.509版本號:指出該證書使用了哪種版本的X.509標準,版本號會影響證書中的一些特定信息。目前的版本是3。

2、證書持有人的公鑰:包括證書持有人的公鑰、算法(指明密鑰屬於哪種密碼系統)的標識符和其他相關的密鑰參數。

3、證書的序列號:由CA給予每一個證書分配的唯一的數字型編號,當證書被取消時,實際上是將此證書序列號放入由CA簽發的CRL(Certificate Revocation List證書作廢表,或證書黑名單表)中。這也是序列號唯一的原因。

4、主題信息:證書持有人唯一的標識符(或稱DN-distinguished name)這個名字在 Internet上應該是唯一的。DN由許多部分組成,看起來象這樣:

CN=Bob Allen, OU=Total Network Security Division

O=Network Associates, Inc.

C=US

這些信息指出該科目的通用名、組織單位、組織和國家或者證書持有人的姓名、服務處所等信息。

5、證書的有效期:證書起始日期和時間以及終止日期和時間;指明證書在這兩個時間內有效。

6、認證機構:證書發布者,是簽發該證書的實體唯一的CA的X.509名字。使用該證書意味著信任簽發證書的實體。(注意:在某些情況下,比如根或頂級CA證書,發布者自己簽發證書)

7、發布者的數字簽名:這是使用發布者私鑰生成的簽名,以確保這個證書在發放之後沒有被撰改過。

8、簽名算法標識符:用來指定CA簽署證書時所使用的簽名算法。算法標識符用來指定CA簽發證書時所使用的公開密鑰算法和HASH算法。

X.509證書格式

為了利用公共密鑰這種密碼系統,必須將公共密鑰分發出去。最通用的一種簽名證書格式被稱為X.509格式。X.509格式的證書被VeriSign、微軟   、網景和其他許多公司廣泛套用於對電子郵件訊息進行簽名,對程式代碼進行認證,以及對許多其他類型的數據進行認證等等。X.509標準是由國際電話標準機構,即國際電報電話諮詢委員會(CCITT)提出的用於目錄服務的X.500系列建議的組成部分。

X.509證書的具體結構是用一種形式化表示來描述的,稱為"抽象語法表示法#1"(abstract syntax notation)即ASN.1。圖9-13顯示了第三版X.509格式的ASN.1定義。雖然具體的語法對我們並不重要,但是你可以看到,ASN.1為證書檔案的結構給出了精確的定義。"基本編碼規則"(basic encoding rules),即BER,精確地描述了如何將該結構保存為二進制檔案。也就是說,BER描述了如何對整數、字元串、位串以及諸如SEQUENCE、CHOICE和OPTIONAL的結構進行編碼的方法。

[Certificate ::= SEQUENCE { tbsCertificate TBSCertificate, signatureAlgorithm AlgorithmIdentifier, signature BIT STRING } 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, -- If present, version must be v2or v3 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version must be v2or v3 extensions [3] EXPLICIT Extensions OPTIONAL -- If present, version must be v3 } Version ::= INTEGER { v1(0), v2(1), v3(2) } CertificateSerialNumber ::= INTEGER Validity ::= SEQUENCE { notBefore CertificateValidityDate, notAfter CertificateValidityDate } CertificateValidityDate ::= CHOICE { utcTime UTCTime, generalTime GeneralizedTime } UniqueIdentifier ::= BIT STRING SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING } Extensions ::= SEQUENCE OF Extension Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING }

解析X509證書

1.從磁碟上的證書檔案中讀取證書數據

unsigned char* pbX509Data; // 證書數據

unsigned long ulX509DataLen; // 證書數據長度

2.獲取CertContext

PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, pbX509Data, ulX509DataLen);

3.獲取證書信息

pCertContext->pCertInfo->dwVersion; // 證書版本號

CRYPT_INTEGER_BLOB snBlob = pCertContext->pCertInfo->SerialNumber; // 證書SN

CERT_NAME_BLOB issuerBlob = pCertContext->pCertInfo->Issuer; // 證書頒發者

CERT_NAME_BLOB subjectBlob = pCertContext->pCertInfo->Subject; // 證書主題

// 證書有效起始日期

SYSTEMTIME sysTime;

memset(&sysTime, 0, sizeof(sysTime));

FileTimeToSystemTime(&pCertContext->pCertInfo->NotBefore, &sysTime);

char szTime[128] = {0};

sprintf_s(szTime, 128, "%d年%d月%d日 %d:%d:%d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);

// 證書有效終止日期

memset(&sysTime, 0, sizeof(sysTime));

FileTimeToSystemTime(&pCertContext->pCertInfo->NotAfter, &sysTime);

memset(szTime, 0, sizeof(szTime));

sprintf_s(szTime, 128, "%d年%d月%d日 %d:%d:%d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);

4.創建臨時密鑰容器

HCRYPTPROV hTmpProv = NULL;

CryptAcquireContext(&hTmpProv, "My_Temporary_Container", NULL, PROV_RSA_AES, 0); // NULL表示使用系統默認CSP

5.向容器中導入公鑰,獲取公鑰句柄

HCRYPTKEY hKey = NULL;

CERT_PUBLIC_KEY_INFO certPubKeyInfo = pCertContext->pCertInfo->SubjectPublicKeyInfo;

CryptImportPublicKeyInfo(hTmpProv, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, &certPubKeyInfo, &hKey);

6.導出公鑰(最好採用二次調用方式)

unsigned char* pBuf = NULL;

unsigned long ulBufLen = 0;

CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, pBuf, &ulBufLen);

pBuf = new unsigned char[ulBufLen];

memset(pBuf, 0, ulBufLen);

CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, pBuf, &ulBufLen);

7.獲取公鑰信息

unsigned char* p = pBuf + sizeof(PUBLICKEYSTRUC);

(*(RSAPUBKEY*)p).bitlen; // 公鑰模長(以bit為單位)

(*(RSAPUBKEY*)p).pubexp; // 公鑰的e(注意位元組順序)

p += sizeof(RSAPUBKEY); // 公鑰的n(注意位元組順序)

8.清理工作

delete[] pBuf;

pBuf = NULL;

CryptDestroyKey(hKey);

CryptReleaseContext(hTmpProv, 0);

CertFreeCertificateContext(pCertContext);

相關詞條

熱門詞條

聯絡我們