天天看點

OpenSSL中文手冊之X509庫詳解(未完待續)1 X509概述2 證書請求管理2.4 證書請求的擴充項操作2.5 證書請求的其它相關操作

  版權聲明:本文根據DragonKing牛,E-Mail:[email protected]釋出在https://openssl.126.com的系列文章整理修改而成(這個網站已經不能通路了),我自己所做的工作主要是針對新的1.0.2版本進行驗證,修改錯别字,和錯誤,重新排版,以及整理分類,配圖。 未經作者允許,嚴禁用于商業出版,否則追究法律責任。網絡轉載請注明出處,這是對原創者的起碼的尊重!!!

1 X509概述

  提到X509就不得不提到X500協定族。如下:

  • X.500 包括了DAP DSP DISP DOP, 是用于目錄服務的一系列規範、協定,用于解決國際電話、電報互聯互通、郵件發送時的人員查找、身份認證等問題。
  • X.501 定義X.500協定族的資料模型
  • X.509 現在廣泛用于X.500目錄服務之外,作為公鑰證書的标準格式
  • X.520 定義X.500協定族資料模型的attributes
  • X.521定義X.500協定族資料模式的object class

  X.509是國際标準化組織CCITT建議作為X.500目錄檢索的一部分提供安全目錄檢索服務。一份X.509證書是一些标準字段的集合,這些字段包含有關使用者或裝置及其相應公鑰的資訊一種非常通用的證書格式,所有的證書都符合X.509 國際标準。目前X.509有不同的版本,例如 X.509 V2和x.509 v3都是目前比較新的版本,2000年還推出V4版本,但是都在原有版本基礎上進行功能的擴充,其中每一版本必須包含下列資訊:

  • Version ——X509的版本号
  • Serial Number——證書序列号
  • Signature algorithm ——簽名所使用的算法,就是指的這個數字證書的對指紋進行簽名時所使用的加密算法,這樣就可以使用證書釋出機構的證書裡面的公鑰,根據這個算法對簽名進行解密。指紋(也叫hash值)摘要後再用私鑰加密結果就是數字簽名。
  • Signature hash algorithm——簽名雜湊演算法
  • Issuer—— 證書的釋出機構,指出是什麼機構釋出的這個證書,也就是指明這個證書是哪個公司建立的(隻是建立證書,不是指證書的使用者)。
  • Valid from , Valid to——證書的有效期,也就是證書的有效時間,或者說證書的使用期限。 過了有效期限,證書就會廢棄,不能使用了。
  • Subject (主題)——這個證書是釋出給誰的,或者說證書的所有者,一般是某個人或者某個公司名稱、機構的名稱、公司網站的網址等。
Country Name ( letter code)[XX]:cn--------國家
State or Province Name (full name)[]:ning---------省份
Locality Name (eg, city) [DefaultCity]:ning--------------地區名字
Organization Name (eg, company)[Default Company Ltd]:ning------公司名
Organizational Unit Name (eg,section) []:ning-----部門
Common Name (eg, your name or yourserver's hostname) []:wukui----CA主機名
Email Address []:---------郵箱
Please enter the following 'extra'attributes
to be sent with your certificaterequest
A challenge password []:-----------證書請求密鑰,CA讀驗證書的時候需要輸入密碼
An optional company name[]:-----------公司名稱,CA讀驗證書的時候需要輸入名稱
           
  • Public key (公鑰)——這個我們在前面介紹公鑰密碼體制時介紹過,公鑰是用來對消息進行加密的。
  • Thumbprint, Thumbprint algorithm (指紋以及指紋算法)——這個是用來保證證書的完整性的,也就是說確定證書沒有被修改過。 其原理就是在釋出證書時,釋出者根據摘要算法(一個hash算法)計算整個證書的hash值(也叫指紋)并用私鑰加密後成為簽名和證書放在一起,使用者在打開證書時,先用公鑰解密簽名,獲得指紋,然後自己根據摘要算法計算一下證書的hash值(指紋),如果和附帶的指紋對的上,就說明證書沒有被修改過,因為證書的内容被修改後,根據證書的内容計算的出的hash值(指紋)是會變化的。

  X.509證書和PGP證書之間有許多不同,最明顯的如下所述:

  • 使用者可以建立自己的PGP證書,但是必須向CA請求才能得到一份X.509證書。
  • X.509證書天生隻支援密鑰擁有者的一個名字。
  • X.509證書隻支援證明密鑰合法性的一個數字簽名。

  要獲得一份X.509證書,必須請求CA發給你證書。使用者提供自己的公鑰,并提供有關自己的某些特定資訊。然後在這些資訊上用私鑰做數字簽名,并将整個資料包(稱為證書請求)發給CA。CA做一些努力來驗證使用者提供的資訊是正确的,然後就生成證書并傳回給使用者。

  OpenSSL對的主要工作就是對證書的操作,包括:

  • 證書請求管理
  • 證書生成
  • 證書吊銷及CRL管理
  • X509名字管理
  • 屬性管理
  • 擴充管理
  • 驗證及信任管理

2 證書請求管理

2.1 基本資料結構

  證書請求用到了兩個重要的資料結構:證書請求資訊結構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就是簽名值了。

2.2基本操作函數

  這些基本的操作函數主要是對證書請求項進行設定與讀取操作,它的的定義如下:其中的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;
int GenerateRSAKeyPair(char* szKeyLength)
{
  if(strlen(szKeyLength)==) 
      return -;
  int keylength=atoi(szKeyLength);
  if((pNewRsaKey=EVP_PKEY_new()) == NULL) 
      return CA_FAIL;
  int ret = EVP_PKEY_assign_RSA(pNewRsaKey,RSA_generate_key(keylength,,NULL,  NULL)); 
  if(ret!= ) 
      return CA_FAIL;
  return CA_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域。成功傳回位元組數,失敗傳回0.

【X509_REQ_verify】

  與簽名相對應,對簽名進行驗證,是以将公鑰pkey傳入就可以了。

2.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中。

2.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标準定義。

2.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函數來完成複制工作。

  版權聲明:本文根據DragonKing牛,E-Mail:[email protected]釋出在https://openssl.126.com的系列文章整理修改而成(這個網站已經不能通路了),我自己所做的工作主要是針對新的1.0.2版本進行驗證,修改錯别字,和錯誤,重新排版,以及整理分類,配圖。 未經作者允許,嚴禁用于商業出版,否則追究法律責任。網絡轉載請注明出處,這是對原創者的起碼的尊重!!!