1. 程式人生 > >OpenSSL之X509系列

OpenSSL之X509系列

net ota 同時 簽發證書 ner 標識 valid 學習 get

OpenSSL之X509系列之1---引言和X509概述

【引言】
X509是系列的函數在我們開發與PKI相關的應用的時候我們都會用到,但是OpenSSL中對X509的描述並不是很多,鑒於些,我將以前工作與學習過程的經驗整理出來,供大家參考,不用多走彎路,可以將精力集中在自己要處理的業務邏輯上,同時也希望更多的人參與到研究與整理信息安全的理論與技術中來,提高中國的科研與應用技術水平。提高中國信息安全意識與能力從我做起。
【X509概述】
X.509是國際標準化組織CCITT建議作為X.500目錄檢索的一部分提供安全目錄檢索服務。一份X.509證書是一些標準字段的集合,這些字段包含有關用戶或設備及其相應公鑰的信息一種非常通用的證書格式,所有的證書都符合X.509 國際標準。目前X.509有不同的版本,例如 X.509 V2和x.509 v3都是目前比較新的版本,2000年還推出V4版本,但是都在原有版本基礎上進行功能的擴充,其中每一版本必須包含下列信息:
  (1) 用來區分X.509的不同版本號既版本號
  (2) 由CA給予每一個證書的分配的編號即序列號;
  (3) 用於產生證書所用的方法以及一切參數即簽名算法
  (4) CA的x.500名字即發出該證書的認證機構
  (5) 證書有效的時間包括兩個日期,在所指定的兩個時間之 間有效即有效期限
  (6) 證書持有人的姓名、服務處所等信息即主題信息
  (7) 認證機構的數字簽名
(8) 被證明的公鑰值,加上使用這個公鑰的方法名稱即公鑰信息
【X.509證書格式】
X.509是另一種非常通用的證書格式。所有的證書都符合ITU-T X.509國際標準;因此(理論上)為一種應用創建的證書可以用於任何其他符合X.509標準的應用。但實際上,不同的公司對X.509證書進行了不同的擴展,不是所有的證書都彼此兼容。在一份證書中,必須證明公鑰及其所有者的姓名是一致的。對PGP證書來說,任何人都可以扮演認證者的角色。對X.509證書來說,認證者總是 CA或由CA指定的人(其實PGP證書也完全支持使用CA來確認證書的體系結構),一份X.509證書是一些標準字段的集合,這些字段包含有關用戶或設備及其相應公鑰的信息。X.509標準定義了證書中應該包含哪些信息,並描述了這些信息是如何編碼的(即數據格式),所有的X.509證書包含以下數據:
 (1)X.509版本號:指出該證書使用了哪種版本的X.509標準,版本號會影響證書中的一些特定信息。目前的版本是3。
 (2)證書持有人的公鑰:包括證書持有人的公鑰,算法(指明密鑰屬於哪種密碼系統)的標示符和其他相關的密鑰參數。
 (3)證書的序列號:創建證書的實體(組織或個人)有責任為該證書指定一個獨一無二的序列號,以區別於該實體發布的其他證書。序列號信息有許多用途;比如當一份證書被回收以後,它的序列號就被放入證書回收列表(CRL)之中。
 (4)證書持有人唯一的標示符:(或稱DN-distinguished name)這個名字在 Internet上應該是唯一的。DN由許多部分組成,看起來象這樣:
  CN=Bob Allen, OU=Total NetworkSecurity Division,
  O=Network Associates, Inc., C=US
這些信息指出該科目的通用名,組織單位,組織和國家
(5)證書的有效期:證書起始日期和時間以及終止日期和時間;指明證書何時失效。
 (6)證書發布者的唯一名字:這是簽發該證書的實體的唯一名字。通常是CA。.使用該證書意味著信任簽發證書的實體。(註意:在某些情況下,比如根或頂級CA證書,發布者自己簽發證書)
 (7)發布者的數字簽名:這是使用發布者私鑰生成的簽名。
 (8)簽名算法的標示符:指明CA簽署證書所使用的算法。
 X.509證書和PGP證書之間有許多不同,最明顯的如下所述:
(1) 用戶可以創建自己的PGP證書,但是必須向CA請求才能得到一份X.509證書。
(2)X.509證書天生只支持密鑰擁有者的一個名字。
(3)X.509證書只支持證明密鑰合法性的一個數字簽名。
要獲得一份X.509證書,必須請求CA發給你證書。用戶提供自己的公鑰,證明自己擁有相應的私鑰,並提供有關自己的某些特定信息。然後在這些信息上數字簽名,並將整個數據包(稱為證書請求)發給CA。CA做一些努力來驗證用戶提供的信息是正確的,然後就生成證書並返回給用戶。
【OpenSSL對X509的支持】
以下是我自己對OpenSSL的理解,可以表達上不是很準確。
(1) 證書請求管理
(2) 證書生成
(3) 證書吊銷及CRL管理
(4) X509名字管理
(5) 屬性管理
(6) 擴展管理
(7) 驗證及信任管理
在隨後的一些篇幅中將對以上的這幾個方面進行展開說明。

OpenSSL之X509系列之2---證書請求管理

【數據結構】
證書請求用到了兩個重要的數據結構:證書請求信息結構X509_REQ_INFO與證書請求結構X509_REQ,二者的定義如下:
typedef struct X509_req_info_st
{
ASN1_ENCODING enc;
ASN1_INTEGER *version;
X509_NAME *subject;
X509_PUBKEY *pubkey;
/* d=2 hl=2 l= 0 cons: cont: 00 */
STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
} X509_REQ_INFO;
其中version就是版本號、subject就是主題(常用的是dn)、pubkey是事先生成的公鑰、attributes是一系列的屬性,用於表達證書主題的額外信息,細節參見PKCS#10與PKCS#9。
typedef struct X509_req_st
{
X509_REQ_INFO *req_info;
X509_ALGOR *sig_alg;
ASN1_BIT_STRING *signature;
int references;
} X509_REQ;
其中req_info就是上面所說的證書請求信息、sig_alg是簽名使用的算法比如md5WithRSAEncryption、signature就是簽名值了。
【基本操作函數概述】
這些基本的操作函數主要是對證書請求項進行設置與讀取操作,它的的定義如下:其中的X509_REQ* req對數指的是要操作的X509_REQ對象,下面不再贅述。
int X509_REQ_set_version(X509_REQ *x,long version);
int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME*name);
int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req);
X509_REQ_extract_key(a)
int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, constEVP_MD *md);
【X509_REQ_set_version】
設置版本號, version就是版本號。
【X509_REQ_set_subject_name】
該函數設置證書請求人的主題名,X509_NAME *name參數就是要設置的主題名。對於名字的操作到時會有一個專題來講。
【X509_REQ_set_pubkey】
設置公鑰,EVP_PKEY *pkey參數就是生成好的公鑰,可以通過RSA_generate_key()來生成。
比如:
EVP_PKEY *pNewRsaKey;
intGenerateRSAKeyPair(char* szKeyLength)
{
if(strlen(szKeyLength)==0) return -1;
intkeylength=atoi(szKeyLength);
if((pNewRsaKey=EVP_PKEY_new()) == NULL) return CA_FAIL;
intret = EVP_PKEY_assign_RSA(pNewRsaKey,RSA_generate_key(keylength,0x10001,
NULL, // req_cb
NULL)); // cb args
if(ret!= 1) return CA_FAIL;
returnCA_OK;
}
【X509_REQ_get_pubkey】
讀取X509_REQ中的公鑰信息,返回的是一個EVP_PKEY對象,X509_REQ_extract_key()是它的一個宏定義,功能相同。
【X509_REQ_sign】
對X509_REQ中X509_REQ_INFO結構用pkey與md進行簽名,並用算法標識與簽名值填充X509_REQ中的sig_alg與signature域。
【X509_REQ_verify】
與簽名相對應,對簽名進行驗證,所以將公鑰pkey傳入就可以了。

OpenSSL之X509系列之3---證書請求的IO函數

【輸入輸出函數】
這些函數有兩類:一類是將X509_REQ信息在文件或BIO抽象層上輸入輸出,另一類是在控制臺上將X509_REQ信息進行顯示。它們的函數定義如下:
X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req);
int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req);
X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req);
int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req);
int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned longcflag);
int X509_REQ_print(BIO *bp,X509_REQ *req);
int X509_REQ_print_fp(FILE *fp, X509_REQ *x)
【d2i_X509_REQ_fp】
將證書請求從文件中讀入並轉化成X509_REQ內部結構。
【i2d_X509_REQ_fp】
將X509_REQ對象進行DER編碼輸出,並寫入fp指定的文件中。
【d2i_X509_REQ_bio】
功能與d2i_X509_REQ_fp相同,只是讀的時候從BIO抽象層上讀,你可以將它與文件相關聯就可以了。
【i2d_X509_REQ_bio】
功能與i2d_X509_REQ_fp相同,只是寫的時候從BIO抽象層上寫,你可以將它與文件或者內存BIO相關聯就可以輸出了。
【X509_REQ_print】
將X509_REQ在BIO上輸出,但輸入是可以讀的,比如Subject=XXX等。其實底層就是調用X509_REQ_print_ex來實現的。
【X509_REQ_print_ex】
這個函數與X509_REQ_print的區別是可以用標誌去控制輸出,nmflags用於控制顯示方式,cflag用於控制哪些不顯示,可以按自己的需要進行定制。它們的定義在x509.h裏。
具體如下:
#define X509_FLAG_COMPAT 0
#define X509_FLAG_NO_HEADER 1L
#define X509_FLAG_NO_VERSION (1L << 1)
#define X509_FLAG_NO_SERIAL (1L << 2)
#define X509_FLAG_NO_SIGNAME (1L << 3)
#define X509_FLAG_NO_ISSUER (1L << 4)
#define X509_FLAG_NO_VALIDITY (1L << 5)
#define X509_FLAG_NO_SUBJECT (1L << 6)
#define X509_FLAG_NO_PUBKEY (1L << 7)
#define X509_FLAG_NO_EXTENSIONS (1L << 8)
#define X509_FLAG_NO_SIGDUMP (1L << 9)
#define X509_FLAG_NO_AUX (1L << 10)
#define X509_FLAG_NO_ATTRIBUTES (1L << 11)
【X509_REQ_print_fp】
其實這個函數就是將可讀的結果保存在文件裏,內存就是生成一個BIO對象BIO_new(BIO_s_file(),然後再將文件句柄傳給他BIO_set_fp(b,fp,BIO_NOCLOSE),再調用X509_REQ_print函數進行輸出。這幾個print函數,具體實現在crypto/asn1/t_req.c中。

OpenSSL之X509系列之4---證書請求的擴展項操作

【擴展項操作函數】
這些函數主要是對證書的請求的擴展項進行讀取與設置操作,
int X509_REQ_extension_nid(int nid);
int * X509_REQ_get_extension_nids(void);
void X509_REQ_set_extension_nids(int *nids);
STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ*req);
int X509_REQ_add_extensions_nid(X509_REQ *req,STACK_OF(X509_EXTENSION) *exts,int nid);
int X509_REQ_add_extensions(X509_REQ *req,STACK_OF(X509_EXTENSION) *exts);
【X509_REQ_extension_nid】
判斷nid是否已經在內部nid_list列表中定義了。未定義返回0,否則返回1。
【X509_REQ_get_extension_nids】
返回已經定義的nid列表。
【X509_REQ_set_extension_nids】
設置定義好的nid列表。
【X509_REQ_get_extensions】
取出證書請求中的擴展項,過程是這樣的,先從屬性中將經過der編碼的擴展項取出來,然後調用d2i_ASN1_SET_OF_X509_EXTENSION函數,將它轉化成內部結構。
【X509_REQ_add_extensions】
將定義好,且賦了值的X509_EXTENSION擴展項加入證書請求中(其實是加到屬性中,這在以後講)。
【X509_REQ_add_extensions_nid】
功能與X509_REQ_add_extensions相同,只不過nid參數可以使用非標準的nid,其實X509_REQ_add_extensions就是通過調用這個函數是實現的,只不過使用了objects.h中定義的ExtensionRequest標準定義。
#define NID_ext_req 172

OpenSSL之X509系列之5---證書請求的其它相關操作

【相關操作函數】
X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY*pkey);
int X509_REQ_digest(const X509_REQ *data,const EVP_MD*type,unsigned char *md, unsigned int *len);
X509_REQ *X509_REQ_dup(X509_REQ *req);
【X509_to_X509_REQ】
用X509證書結構直接生成一個證書請求結構,其中x就是證書結構,pkey是公鑰,md是散列算法,操作的過程就是將證書裏的主題名與公鑰填充到X509_REQ證書請求結構中,然後用指定的pkey與md進行簽名,成功返回X509_REQ證書請求結構。
【X509_REQ_to_X509】
從證書請求結構直接生成一個X509證書,其中的day就是證書的有效期(多少天),pkey就是用於簽名的私鑰。操作過程:從證書請求結構取出主題,將它填充到X509的主題與簽發者中,取出公鑰填充到X509公鑰域裏,有MD5與私鑰進行簽名,所以這樣生成證書應用是一張自簽名的證書。
【X509_REQ_digest】
將X509_REQ用指定的散列算法type進行散列。結果在md中,len是結果的長度。
【X509_REQ_dup】
復制一份X509_REQ結構。它是宏定義,實際上是由ASN1_dup函數來完成復制工作。

轉自:http://blog.csdn.net/u010571535/article/details/8973776

OpenSSL之X509系列