天天看點

使用OpenSSL工具制作X.509證書的方法及其注意事項總結如何使用OpenSSL工具生成根證書與應用證書零、寫在前面一、步驟簡記二、各步詳解三、常見問題及其解決

如何使用OpenSSL工具生成根證書與應用證書

本文由CSDN-蚍蜉撼青松 【首頁:http://blog.csdn.net/howeverpf】原創,轉載請注明出處!

零、寫在前面

       最近出于工作需要,倒騰了一下如何生成X.509證書。在此過程中遇到一些問題,也查過網上很多資料,磕磕碰碰,總算按照既定要求達到了目标。因為感覺網上的資料太散,查找起來不很友善,是以在這裡做一個總結。

       主要的參考資訊來源是以下三個:

  • 《OpenSSL程式設計》(趙春平 著)【一本難得的中文資料,未出版】
  • 《OpenSSL官方文檔---OpenSSL指令》(英文),幾乎可以找到所有問題的答案和原因,但是由于很多時候不知道問題出在哪裡,是以還是需要另外查資料
  • 《互動百科---SSL》,說明了證書中各DN字段的含義

        一些前輩的博文,也對我快速定位問題提供了很大的幫助,在此表示感謝!并列舉如下:

  • 部落格園 - rusty,《Openssl使用生成CA總結》 ,提到了需要提前建好一些目錄和檔案
  • 百度空間 - mars208,《使用openssl建立CA》,提到了簽發政策的問題
  • ChinaUnix - ehyyngp,《使用openssl簽發證書》,提到了中級證書的簽發問題

一、步驟簡記

       以生成一個二級證書鍊為例,将會用到以下指令:

// 生成頂級CA的公鑰證書和私鑰檔案,有效期10年(RSA 1024bits,預設)
openssl req -new -x509 -days 3650 -keyout CARoot.key -out CARoot.crt 
// 為頂級CA的私鑰檔案去除保護密碼
openssl rsa -in CARoot.key -out CARoot.key

// 生成頂級CA的公鑰證書和私鑰檔案,有效期15年(RSA 2048bits,指定)
openssl req -newkey rsa:2048 -x509 -days 5480 -keyout CARoot.key -out CARoot.crt
// 為頂級CA的私鑰檔案去除保護密碼
openssl rsa -in CARoot.key -out CARoot.key

// 為應用證書/中級證書生成私鑰檔案
openssl genrsa -out app.key 2048
// 根據私鑰檔案,為應用證書/中級證書生成 csr 檔案(證書請求檔案)
openssl req -new -key app.key -out app.csr
// 使用CA的公私鑰檔案給 csr 檔案簽名,生成應用證書,有效期5年
openssl ca -in app.csr -out app.crt -cert CARoot.crt -keyfile CARoot.key -days 1826 -policy policy_anything
// 使用CA的公私鑰檔案給 csr 檔案簽名,生成中級證書,有效期5年
openssl ca -extensions v3_ca -in app.csr -out app.crt -cert CARoot.crt -keyfile CARoot.key -days 1826 -policy policy_anything
           

       根據生成目标不同,以上指令可以分為三組。其中,前面兩組都用于生成自簽名的頂級CA(差別隻在于密鑰長度不同),實際應用中隻需根據需求選擇一組即可。

       最後一組用于生成非自簽名的證書,包括中級證書與應用證書。所謂中級證書,是具有繼續頒發下級證書權限的子CA,而本文中所說的應用證書,特指不能用來繼續頒發下級證書,隻能用來證明個體身份的證書。頂級CA在簽發二者的時候,隻是多少一個 -extensions v3_ca 選項的差別,這個選項賦予被簽發的證書繼續簽發下級證書的權力。【詳參2.5[3]小節相關介紹】

二、各步詳解

2.1 生成自簽名根證書(即頂級CA)

典型示例:openssl req -new -x509 -days 5480 -keyout CA.key -out CA.crt

[1] 指令選項和參數解讀

       示例中,各選項(及參數)的意義如下:

req              //使用openssl的req子指令
-new             //生成新的證書請求
-x509            //生成自簽名證書
-days 5480       //自簽名證書的有效期5480天(15年)【僅當使用了 -x509 選項後有效】
-keyout CA.key   //私鑰檔案名指定為CA.key【此選項的一般作用是新生成檔案命名;但若同時使用了-key選項,則此選項用于原私鑰檔案的更名】
-out CA.crt      //指定輸出所生成自簽名證書的資訊到檔案,且檔案名為CA.crt【建議不要省略】
           

       其中,-days,-keyout 兩個選項可以省略,省略的話使用預設值,有效期預設為 30 天【由程式内部在變量初始化的時候指定,與配置檔案無關】,私鑰檔案名的預設值由配置檔案 openssl.cnf 中相關條目指定,沒改過的話為 privkey.pem。

       選項 -out 若是省略的話,openssl不會以檔案形式輸出生成的 證書/證書請求,而是會預設将檔案的資訊直接列印到螢幕上,這在大多數情況下,是不符合我們要求的。是以建議這個選項最好不要省略!

       req子指令可以通過 -key 選項為證書請求指定使用一個已存在的私鑰檔案。但在示例中的情況下,雖然使用了-new 和 -x509兩個選項,但沒有使用 -key 選項,這時,req子指令會自動為自簽名證書生成一個RSA私鑰,密鑰長度的預設值由配置檔案 openssl.cnf 中的相關條目指定,沒改過的話為 1024 bits。

[2] 關于私鑰檔案加密密碼的指定

       運作中會提示輸入加密密碼,如下:

writing new private key to 'CA.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
           

       此密碼用于加密私鑰檔案 CA.key 中的私鑰資訊,如果不想在運作過程中還要輸入加密密碼,則可以使用選項 -passout 在指令中直接指定。選項 -passout 的使用形式為:

-passout arg

其中,arg是選項 -passout 的參數,其格式有多種,詳參《OpenSSL官方文檔》中關于"PASS_PHRASE_ARGUMENTS"的介紹。

       本小節典型示例中的指令,可以用選項 -passout 改造如下:

openssl req -new -x509 -days 5480 -keyout CA.key -out CA.crt -passout pass:1314

       由于Linux系統中可以使用history指令檢視曆史指令記錄,是以出于安全方面的考量,一般如非必要,不建議在指令中直接指定密碼。這與mysql登入的時候不在 -p 選項裡直接指定登入密碼的原因是一緻的。

[3] 關于證書請求檔案中的DN字段

       運作中會提示輸入一些 Distinguished Name fields,即證書的識别名資訊字段,簡稱為DN字段,如下:

You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:California
Locality Name (eg, city) [Newbury]:
Organization Name (eg, company) [My Company Ltd]:GeoAuth Inc.
Organizational Unit Name (eg, section) []:.
Common Name (eg, your name or your server's hostname) []:Authentication Global Root
Email Address []:.
           

       這些DN字段大部分有預設值,預設值由配置檔案 openssl.cnf中相關條目指定。如要在某一個DN字段使用預設值,則無需輸入任何資訊,直接點選"Enter"鍵;如果确實某個DN字段的值要置為空,則輸入一個 '.' 後,點選"Enter"鍵。

       這些DN字段主要是拿來識别證書持有者身份的,下表是關于它們的縮寫、說明和一些填寫說明。【此部分參考了互動百科的SSL條目】

DN字段名 縮寫 說明 填寫要求
Country Name C 證書持有者所在國家 要求填寫國家代碼,用2個字母表示
State or Province Name ST 證書持有者所在州或省份 填寫全稱,可省略不填
Locality Name L 證書持有者所在城市 可省略不填
Organization Name O 證書持有者所屬組織或公司 最好還是填一下
Organizational Unit Name OU 證書持有者所屬部門 可省略不填
Common Name CN 證書持有者的通用名

必填。

對于非應用證書,它應該在一定程度上具有惟一性;

對于應用證書,一般填寫伺服器域名或通配符樣式的域名。

Email Address 證書持有者的通信郵箱 可省略不填

表2-1 DN字段的說明

注:表中所謂,證書不是應用證書時,其持有者的通用名要有“唯一性”,是指其通用名不要與一般主機上常見的信任證書清單或撤銷證書清單中的證書産生重複。

       如果不想在運作過程中逐個輸入這些DN字段的值,則可以使用 -subj 選項在指令中直接指定。選項 -subj 的使用形式為:

-subj arg

其中,arg是選項 -subj 的參數,其格式類似于:/type0=value0/type1=value1/type2=... 形式。每一個 /type=value 形式的單元,都對應了一個完整的DN字段。其中,

  • / 是每一個DN字段的開始标志;
  • type0、type1等等,就是表2-1中提到的DN字段名的縮寫;
  • =是DN字段的名和值之間的間隔符;
  • value0、value1等等,就是原本你要在運作過程中逐個輸入的DN字段的值。

       對于您要将值置為空的DN字段,您可以略去不寫。本小節典型示例中的指令,可以用 -subj 選項改造如下【略去了 L 與 OU 兩個DN字段】:

openssl req -new -x509 -days 5480 -subj /C=US/ST=California/O=GeoAuth\ Inc./CN=Authentication\ Global\ Root -keyout CA.key -out CA.crt

       需要特别注意的是,如果您設定的DN字段的值如果存在一些特殊字元【比如  (空格)、((半角左括号)、)(半角右括号)……】,必須經過\(反斜杆)轉義。上例中已經給出了空格轉義的情況。

[4] 如何指定自簽名證書的密鑰長度和類型

       如前所述,示例隻能生成密鑰長度為1024bits的RSA公私鑰對。如果要生成密鑰長度不為1024bits的RSA公私鑰對,或是其他類型的【比如DSA、EC】公私鑰對,則必須使用選項 -newkey 來代替 -new 。選項 -newkey 的用法比較複雜,如需詳細了解,請參看《OpenSSL官方文檔》的相關頁面。本小節典型示例中的指令等效于以下指令:

openssl req -newkey rsa:1024 -x509 -days 5480 -keyout CA.key -out CA.crt

要生成一個密鑰長度為2048bits的RSA公私鑰對,指令為:

openssl req -newkey rsa:2048 -x509 -days 5480 -keyout CA2048.key -out CA2048.crt

2.2 為頂級CA的私鑰檔案去除加密保護

       上節提到,頂級CA的私鑰檔案是經過加密保護的,以後每當需讀取 CA.key 檔案中的私鑰資訊時,都需輸入解密密碼。這種做法适合有安全需求的場合,但如果覺得不友善,也可以去除這個密碼。

典型示例:openssl rsa -in CA.key -out CA.key

[1] 指令選項和參數解讀

       示例中,各選項/參數的意義如下:

rsa           //使用openssl的rsa子指令
-in CA.key    //經加密保護的私鑰檔案
-out CA.key   //解除加密保護後的私鑰檔案【可以改名】
           

[2] 關于私鑰檔案解密密碼的指定

       運作中會提示輸入解密密碼,如下:,

Enter pass phrase for CA.key:
writing RSA key
           

       如果不想在運作過程中還要輸入解密密碼,則可以使用選項 -passin 在指令中直接指定。選項 -passin 的使用形式為:

-passin arg

其中,arg是選項 -passin 的參數,其格式同選項 -passout 的參數,詳參《OpenSSL官方文檔》中關于"PASS_PHRASE_ARGUMENTS"的介紹。

       本小節典型示例中的指令,可以用選項 -passin 改造如下:

openssl rsa -in CA.key -out CA.key -passin pass:1314

       基于同選項 -passout 一樣的考量,一般不建議直接在指令中指定解密密碼。

[3] rsa子指令的實際功能

       rsa子指令的功能,更完整來說,應該是RSA密鑰的管理。除了此處用到的去除加密保護,還可以用來:更換加解密密碼,更換加解密算法【DES、三重DES、IDEA(官方文檔上提到過,但是有些版本好像不支援,比如說我安裝的)、AES(官方文檔上沒提到,我安裝的版本支援)】,更換密鑰檔案的編碼方式等等。

2.3 為應用證書/中級證書生成私鑰檔案

典型示例:openssl genrsa -out app.key 2048

[1] 指令選項和參數解讀

       示例中,各選項/參數的意義如下:

genrsa         //使用openssl的genrsa子指令
-out app.key   //指定輸出生成的私鑰資訊到檔案,且檔案名為app.key【建議别省略】 
2048           //指定所生成私鑰的比特長度【務必放在最後一個】
           

       其中,選項 -out 若是省略的話,openssl不會以檔案形式輸出生成的 私鑰資訊,而是會預設将私鑰的資訊直接列印到螢幕上,這不符合我們的要求。是以建議這個選項不要省略!

       genrsa子指令還可以有其他一些選項及參數,但不論還有多少選項,都必須把指定私鑰長度的參數放在最後一個。【如果指定私鑰長度的參數不是最後一個,則其後的參數好像會被舍棄。】

[2] 私鑰檔案的加密保護

        本小節典型示例所給出的指令,生成的是未經任何加密保護的私鑰檔案。這種方式用起來比較友善,但非常不安全。如果要為私鑰檔案附加加密保護,則有兩種方式:

  • A.在生成私鑰檔案的同時就指定輸出前要用某種加密算法加密保護;
  • B.生成明文的私鑰檔案後用 rsa 子指令附加某種加密算法的加密保護。

       我計算機上安裝的openssl版本,在兩種方式下都支援這些加密算法選項:-des,-des3,-aes128,-aes192,-aes256。以加密選用192位的AES算法為例,指令如下:

// 在生成私鑰檔案的同時就指定輸出前要用192位的AES算法加密保護
openssl genrsa -aes192 -out app.key 1024
// 生成明文的私鑰檔案後用 rsa 子指令附加192位的AES算法加密保護
openssl rsa -aes192 -in app.key -out app.key 
           

       上例中的兩個指令,都會要求在運作中輸入加密密碼。同樣的,雖然不建議,但是openssl依然支援在指令中使用選項 -passout 指定加密密碼,選項 -passout 的用法參考2.1[2]小節。唯一需要額外注意的是,對于genrsa子指令,選項 -passout 應放在 指定密鑰長度的參數 前面。

2.4 為應用證書/中級證書生成 csr 檔案【證書請求檔案】

典型示例:openssl req -key app.key -out app.csr

[1] 指令選項和參數解讀

       示例中,各選項/參數的意義如下:

req             //使用openssl的req子指令
-new            //生成新的證書請求
-key app.key    //指定是為app.key檔案中的私鑰生成證書請求
-out app.csr    //指定輸出所生成證書請求的資訊到檔案,且檔案名為app.csr
           

       這和2.1節使用的是openssl的同一個子指令,是以參數的意義很多具有共通性。指令運作中也會要求輸入一些DN字段的值,參看本文2.1 [3] 小節中的相關介紹。同樣的,可以使用-subj選項在指令中直接指定這些DN字段的值。

2.5 為 csr 檔案簽名,生成應用證書/中級證書

典型示例:openssl ca -in app.csr -out app.crt -cert CA.crt -keyfile CA.key -days 1826 -policy policy_anything

[1] 指令選項和參數解讀

       示例中,各選項/參數的意義如下:

ca                        //使用openssl的ca子指令
-in app.csr               //指定待簽發證書的 CSR檔案為 app.csr
-out app.crt              //指定輸出所簽發證書的資訊到檔案,且檔案名為app.crt【建議不要省略】 
-cert CA.crt              //指定為應用/中級證書簽名的CA的公鑰證書為CA.crt【用到CA憑證的持有者資訊】
-keyfile CA.key           //指定為應用/中級證書簽名的CA的私鑰檔案為CA.key【用CA私鑰實際執行簽名】
-days 1826                //指定所簽發證書的有效期為1826天(5年)
-policy policy_anything   //指定簽發政策為 policy_anything 【即,允許所簽發證書的持有者資訊和頒發者資訊之間不遵守任何比對政策】
           

       其中,選項 -out 若是省略的話,openssl不會以檔案形式輸出生成的 應用證書/中級證書資訊,而是會預設将證書的資訊直接列印到螢幕上,這一般不符合我們的要求。是以建議這個選項不要省略!

[2] 關于簽發政策

        在本節的典型示例中,我們使用了選項-policy來指定簽發政策為 policy_anything。如果沒有使用此選項,則簽發政策使用由配置檔案 openssl.cnf 中相關條目指定的預設政策。如果您沒動過該配置檔案的話,則預設政策為 policy_match。此政策要求CA的公鑰證書和應用證書請求檔案中的Country Name、State or Province Name、Organization Name這三個字段必須 match 【也就是一樣】。如果您在應用證書請求檔案中指定了和CA的公鑰證書不一樣的Country Name,且沒有使用選項-policy,則會得到類似于下方的提示:

The countryName field needed to be the same in the
CA certificate (US) and the request (CN)
           

        檢視配置檔案 openssl.cnf 中相關條目,我們可以看到以下内容,

# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy		= policy_match

# For the CA policy
[ policy_match ]
countryName		= match
stateOrProvinceName	= match
organizationName	= match
organizationalUnitName	= optional
commonName		= supplied
emailAddress		= optional

# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName		= optional
stateOrProvinceName	= optional
localityName		= optional
organizationName	= optional
organizationalUnitName	= optional
commonName		= supplied
emailAddress		= optional
           

       看到這,原因就很顯然了。是以若是您要在應用證書請求檔案中指定和CA的公鑰證書不一樣的C/ST/O,且要簽名成功,則有以下三種方式:

  1. 加上-policy選項,指定本次使用的簽發政策為 policy_anything;
  2. 将配置檔案 openssl.cnf 中的預設政策由 policy_match改成 policy_anything;
  3. 将政策 policy_match 中的相關條目由 match改成 optional ;

       為什麼openssl會使用這樣的預設政策呢?其實很簡單,openssl認定,僅當您建立組織内部的信任關系時,您才需要自己做CA。既然是組織内部的信任關系,當然CA和應用證書就該有一樣的所在國家、所在省份,以及所屬組織。

[3] 關于簽發中級證書(二級/三級CA,子CA)

        由本節典型示例指令生成的證書隻能作為應用證書,因為它不具有繼續簽署下級證書的權限。下圖展示了中級證書與應用證書的差別。

使用OpenSSL工具制作X.509證書的方法及其注意事項總結如何使用OpenSSL工具生成根證書與應用證書零、寫在前面一、步驟簡記二、各步詳解三、常見問題及其解決

圖2-1 中級證書與應用證書的差別

        由上圖可以看出,二者主要是在證書的擴充字段Subject Type的取值有所不同。中級證書該字段取值為"CA",表明此證書依然可以作為CA,繼續簽發下級證書;一般應用證書該字段的取值為"End Entity",表明這已經是證書鍊的最後一個結點,自然也就不能繼續簽發下級證書。

        檢視配置檔案 openssl.cnf 中相關條目,可以看到如下内容:

[ ca ]
default_ca	= CA_default		# The default ca section
……………………
[ CA_default ]
……………………
x509_extensions	= usr_cert		# The extentions to add to the cert
……………………
[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE
……………………
[ v3_ca ]
……………………
# This is what PKIX recommends but some broken software chokes on critical
# extensions.
#basicConstraints = critical,CA:true
# So we do this instead.
basicConstraints = CA:true
……………………
           

        由此可以看出,為什麼預設生成的都是純應用證書。若要生成中級證書(一般是出于信任關系建立的便利),則有以下方式:

  1. 上級CA在簽署此證書時,加上 -extensions 選項,且選項參數設為 v3_ca (如步驟簡記中所示);
  2. 将 CA_default 條目中 x509_extensions 的值由 usr_cert改為 v3_ca;
  3. 将 usr_cert 條目中 basicConstraints的值由 CA:FALSE 改為 CA:true;

[4] 關于批處理模式

        執行本節典型示例指令生成證書時,會遇到類似于下面的提示:

Certificate is to be certified until Mar 27 03:44:08 2015 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
           

        也就是說,這個指令是有互動的,你必須在運作過程中手工完成兩次确認輸入。但我們在自己生成證書鍊的時候,證書請求檔案和CA憑證都是由我們自己生成的,一般并不需要确認。另外,我們一旦需要用程式自動化/批量化處理,也會顯得麻煩。

        說到底,一句話,如果你不想有互動,那麼可以使用 -batch 選項。本小節典型示例中的指令,可以用選項 -batch  改造如下:

openssl ca -in app.csr -out app.crt -cert CA.crt -keyfile CA.key -days 1826 -policy policy_anything -batch

三、常見問題及其解決

        留待下次補充。

------本文由CSDN-蚍蜉撼青松【首頁:http://blog.csdn.net/howeverpf】原創,轉載請注明出處!------