查看openssl可用命令
因為openssl沒有查看可用命令的命令,但是我們可以輸入一個錯誤的命令來讓openssl顯示所有可用的命令。
openssl help
創建trust store
因為openssl并沒有帶有任何受信任的根證書,所以我們必須從別的地方獲取。一種方式是使用操作系統自帶的,但通常不是最新的;另一種方式是使用Mozilla花費很大努力維護的信任庫,我們可以直接下載。下載到的文件格式并不能直接使用我們可以使用第三方工具將其轉換為Privacy-Enhanced Mail(PEM)格式。我們使用Curl項目提供的一個Perl腳本,來轉換格式。
wget https://raw.github.com/bagder/curl/master/lib/mk-ca-bundle.pl
./mk-ca-bundle.pl
私鑰與證書
一般我們使用openssl的目的是為了讓我們的web服務器支持ssl,這個過程包含三步。
- 創建增強的私鑰。
- 生成一個Certificate Signing Report (CSR),并把它放送給CA。
- 在web服務器上安裝CA提供的證書。
生成私鑰
生成私鑰是第一步,在生成私鑰前我們需要了解三個概念:
私鑰算法
openssl支持RSA,DSA,ECDSA,所有的網站服務器都使用RSA,因為DSA尺寸被限制1024位(Internet Explorer不能支持更多的尺寸),ECDSA還并未被CA廣泛支持。
私鑰尺寸
默認的私鑰尺寸可能不安全,所以我們要手動指定私鑰尺寸,RSA默認尺寸是512位。目前,2048位的RSA、2048位的DSA、至少256位的ECDSA被認為是安全的尺寸。
私鑰加密
使用密碼加密私鑰是可選的,但是是被推薦的。被加密的私鑰可以安全的存儲、傳輸、備份。但同時這卻不方便,因為使用的時候必須使用密碼,例如每次重啟網站服務器時都要重新輸入密碼。
使用以下命令來生成私鑰和公鑰:
#生成2048位的pem格式的rsa私鑰,并使用128位的aes進行加密
openssl genrsa -aes128 -out private.key 2048
#查看生成的私鑰
openssl rsa -text -in private.key
#生成公鑰
openssl rsa -in private.key -pubout -out public.key
生成證書注冊請求CSR(Certificate Signing Requests)
有了私鑰后就能生成CSR,CSR是我們向CA請求簽發證書的正式請求格式,CSR中包含公鑰和相關的實體信息。在生成CSR的過程中,我們可以輸入.
來設置默認值。
#生成csr
openssl req -new -key private.key -out request.csr
#驗證生成內容
openssl req -text -in request.csr -noout
#使用現有證書生成CSR
openssl x509 -x509toreq -in web.crt -out request.csr -signkey private.key
創建自簽名證書
如果我們安裝TLS服務器是自用的,那么我們就不需要向CA申請證書,我們可以創建一個自簽名的證書。
#使用CSR創建自簽名證書
openssl x509 -req -days 365 -in request.csr -signkey private.key -out web.crt
#不生成中間文件CSR,直接生成自簽名證書
openssl req -new -x509 -days 365 -key private.key -out web.crt
#驗證證書內容
openssl x509 -text -in web.crt -noout
有關自簽名證書和TLS如何工作的,可以參考這里。
私鑰與證書的存儲格式
私鑰和證書的存儲格式有很多種,我們可能經常需要在各種格式中轉換,常用格式如下:
Binary(DER)格式證書
包含X.509證書原始格式,使用DER ASN.1編碼。
ASCII(PEM)格式證書
使用base64編碼的DER格式證書,以-----BEGIN CERTIFICATE-----
作為文件第一行內容,-----END CERTIFICATE-----
作為文件最后一行內容
Binary(DER)格式密鑰
包含密鑰原始內容,使用DER ASN.1編碼。
ASCII(PEM)格式密鑰
包含使用base64編碼的DER格式密鑰,有時會包含額外信息,例如保護私鑰的密碼。
PKCS#7格式證書
用來傳輸被簽名或者加密的數據的復雜格式,常見擴展名有p7b、p7c,可包含整個證書鏈,Java的keytool工具支持這種格式。
PKCS#12(PFX)格式的密鑰和證書
一種用來存儲和保存密鑰及證書的復雜格式,常見擴展名有p12、pfx,微軟的產品經常會使用到。
PEM與DER格式之間的轉換:
#證書 PEM格式轉DER
openssl x509 -inform PEM -in web.crt -outform DER -out web.der
#證書 DER格式轉PEM
openssl x509 -inform DER -in web.der -outform PEM -out web.crt
#密鑰 PEM格式轉DER,替換rsa為你使用的密鑰算法即可
openssl rsa -inform PEM -in private.key -outform DER -out private.der
#密鑰 DER格式轉PEM,替換rsa為你使用的密鑰算法即可
openssl rsa -inform DER -in private.der -outform PEM -out private.key
PEM與PKCS#7證書格式之間的轉換:
- 將PEM格式的證書(web.crt),中間證書(web-intermediate.crt)轉換為PKCS#7文件。
openssl crl2pkcs7 -nocrl -out saved.p7b -certfile web.crt -certfile web-intermediate.crt
- 將PKCS#7轉換為PEM格式,由于結果都存放在一個文件中,我們需要將combined.pem文件里的內容手動分離出來。
openssl pkcs7 -in saved.p7b -print_certs -out combined.pem
PEM與PKCS#12格式之間的轉換:
- 將PEM格式的私鑰(private.key),證書(web.crt),中間證書(web-intermediate.crt)轉換為PKCS#12文件。
openssl pkcs12 -export -name "Certificate Name" -out saved.p12 -inkey private.key -in web.crt -certifile web-intermediate.crt
- 將PKCS#12轉換為PEM格式就不這么直接了,因為轉換的結果放在一個文件里面,所以我們必須手動的將combined.pem里的內容分離。
openssl pkcs12 -in saved.p12 -out combined.pem -nodes
TLS配置
在發布TLS時,第一步就是加密套件的選擇,所有使用OpenSSL的軟件都要使用其提供的套件配置機制。例如nginx中配置加密套件:
ssl_ciphers HIGH:!aNULL:!MD5
其中HIGH:!aNULL:!MD5
是加密套件的關鍵字和相關操作符的組合來選擇一組加密套件。
以下是四類操作符的說明。
-
:
與即冒號與空格
通過這兩個操作符都可添加新的加密套件到結果列表中,例如RSA:AES
或者RSA AES
。 -
-
與關鍵字組合從現有列表中移除指定的加密套件,被移除的套件可以被后續的關鍵字再次引入。例如RSA-DES
。 -
!
永久移除關鍵字指定的加密套件。例如!MD5
。 -
+
通過制定多個關鍵字來組合起來篩選加密套件。例如RSA+AES
。
有關于所有可用的關鍵字,可以參考這里。
我們可以使用以下命令來驗證關鍵字與操作符組合選擇的加密套件:
#"RSA:AES"可換乘其他組合
openssl ciphers -v "RSA:AES"
測量指定加密算法或者摘要算法速度時(測量的結果只是大概,如果想多線程測試,可查詢speed的選項),我們可以使用以下命令:
#aes可替換為其他值
openssl speed aes
創建私有CA
- 創建CA配置信息。
對于創建CA這種復雜的操作,我們可以創建一個配置文件(root_ca.conf)來簡化我們的操作。
一個配置文件可以分為很多節,每一節都以[section_name]作為起始行,直到碰到另一節的起始行或者到文件結尾,則該節結束。每節的名稱只能是字母數字下劃線。
配置文件中的第一節是特殊的,被認為是[default]節,通常是不命令的,當碰到另一個命名的節時,該默認節即結束。當查詢一個名字時,先從命名的節中查詢,最后再查詢默認節。
環境變量被映射到名為ENV的節中。
配置文件中的注釋以#開頭。
配置文件中的每一節都包含有鍵值對,形式如name=value. 鍵的可選字符集是[alphanumeric . , ; _], 值對應著=后面的所有字符,去除頭尾空格。值中可以包含變量展開,形式是$name或者${name},這將會使用在本節中查找到的name對應的值進行替換;如果想要使用其他節中的值進行替換,可以使用$section::name或者${section::name};如果想要使用環境變量進行替換可以使用形式$ENV::name。如果value最后一個字符是\,則value是可以跨行的,同時也可以包含任意轉義字符。
以下是配置信息的示例。
#基本的CA配置信息
[default]
name=root_ca
domain_suffix=example.com
aia_url=http://$name.$domain_suffix/$name.crt
crl_url=http://$name.$domain_suffix/$name.crl
ocsp_url=http://ocsp.$name.$domain_suffix:9080
default_ca=ca_default
name_opt=utf8,esc_ctrl,multiline,lname,align
#供req節中鍵distinguished_name使用
[ca_dn]
countryName="GB"
organizationName="Example"
commonName="Root CA"
#控制CA操作的配置信息,可通過man ca命令來查看所有可選參數
[ca_default]
home=.
database=$home/db/index
serial=$home/db/serial
crlnumber=$home/db/crlnumber
certificate=$home/$name.crt
private_key=$home/private/$name.key
RANDFILE=$home/private/random
new_certs_dir=$home/certs
unique_subject=no
copy_extensions=none
default_days=3650
default_crl_days=365
default_md=sha256
#指定所有從本CA簽發的證書的策略,策略內容在policy_c_o_match節中
policy=policy_c_o_match
#策略要求被簽發證書的countryName和organizationName必須匹配根CA
[policy_c_o_match]
countryName=match
stateOrProvinceName=optional
organizationName=match
organizationalUnitName=optional
commonName=supplied
emailAddress=optional
#req命令的配置信息,僅被使用一次來創建自簽名根證書
[req]
default_bits=4096
encypt_key=yes
default_md=sha256
utf8=yes
string_mask=utf8only
prompt=no
distinguished_name=ca_dn
req_extensions=ca_ext
[ca_ext]
#標識證書是CA
basicConstraints=critical,CA:true
keyUsage=critical,keyCertSign,cRLSign
subjectKeyIdentifier=hash
#由根CA簽發的證書的配置信息
[sub_ca_ext]
authorityInfoAccess=@issuer_info
authorityKeyIdentifier=keyid:always
#CA:true表示創建的證書是CA,pathlen:0表示由CA簽發的證書創建的下級證書不能是CA
basicConstraints=critical,CA:true,pathlen:0
crlDistributionPoints=@crl_info
#TLS客戶端和服務器
extendedKeyUsage=clientAuth,serverAuth
keyUsage=critical,keyCertSign,cRLSign
nameConstraints=@name_constraints
subjectKeyIdentifier=hash
[crl_info]
URI.0=$crl_url
[issuer_info]
caIssuers;URI.0=$aia_url
OCSP;URI.0=$ocsp_url
[name_constraints]
#限定域名
permitted;DNS.0=example.com
permitted;DNS.1=example.org
#以下兩個限制來源于 CA/Browser Forum‘s Baseline Requirements
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0
#用于OCSP報文簽名的證書拓展項,為了運行OCSP服務器,我們創建一個特殊證書并且代理OCSP簽名。
[ocsp_ext]
authorityKeyIdentifier=keyid:always
#該證書不是CA
basicConstraints=critical,CA:false
extendedKeyUsage=OCSPSigning
keyUsage=critical,digitalSignature
subjectKeyIdentifier=hash
目前對于nameConstraints的支持還不是很全面,詳情可以參照這里和這里。
- 創建CA目錄
mkdir root_ca
cd root_ca
mkdir certs db private
chmod 700 private
touch db/index
#如果創建共用distinguished_name的CA證書時,每次都要重新生成serial
openssl rand -hex 16 > db/serial
echo 1001 > db/crlnumber
以下是各個目錄作用的說明:
-
certs/
存儲生成的證書。 -
db/
存放證書數據庫(index),證書和CRL的序列號,或者openssl創建的額外文件。 -
private/
CA和OCSP的私鑰。
- 創建根CA
第一步創建私鑰和CSR。
openssl req -new -config root_ca.conf -out root_ca.csr -keyout private/root_ca.key
第二步創建自簽名證書。
openssl ca -selfsign -config root_ca.conf -in root_ca.csr -out root_ca.crt -extensions ca_ext
創建完CA證書后我們會在當前文件夾(root_ca.crt)和certs文件夾內(XXXX.pem)得到一樣的證書。我們可以查看db/index得到生成的證書的記錄。
V 270818135219Z DDBBFB87753B0599CC2C6B26C36017CB unknown/C=GB/O=Example/CN=Root CA
第一列:狀態標識,可選值有V (valid)R (revoked)E(expired)。
第二列:過期日期,格式為(YYMMDDHHMMSSZ)。
第三列:注銷日起,如果沒有即為空。
第四列:序列號,十六進制。
第五列:文件位置,如果未知值為unknown。
第六列:標識名。
- 根CA操作
- 從CA生成CRL
openssl ca -gencrl -config root_ca.conf -out root_ca.crl
- 簽發證書
生成的證書存儲在certs/存在certs文件夾內,文件名是序列號,你可以通過db/index的標識名來在certs文件夾內查詢對應的證書文件。同時你指定的web.crt文件也會被生成。
#sub_ca.csr是你生成證書的請求
openssl ca -config root_ca.conf -in request.csr -out web.crt -extensions sub_ca_ext
- 撤銷證書
撤銷原因可以通過crl_reason來指定,可選值有unspecified、keyCompromise、CACompromise、CACompromise、affiliationChanged、superseded、cessationOfOperation、certificateHold、removeFromCRL
#DDBBFB87753B0599CC2C6B26C36017CB.pem是你要吊銷的證書,通過db/index文件來查詢。
openssl ca -config root_ca.conf -revoke certs/DDBBFB87753B0599CC2C6B26C36017CB.pem -crl_reason keyCompromise
- 創建OCSP簽名證書
第一步為OCSP響應器創建私鑰和CSR。
#rsa:2048代表創建2048位的rsa私鑰;subj選項對應的值中C代表countryName,O代表organizationName,CN代表commonName。
openssl req -new -newkey rsa:2048 -subj "/C=GB/O=Example/CN=OCSP Root Responder" -keyout private/root_ocsp.key -out root_ocsp.csr
第二步使用根CA簽發證書,使用-extensions ocsp_ext
來確保正確簽發OCSP證書,同時通過days 30
調整證書過期時間,越短越好,因為OCSP證書不包含撤銷信息,無法被撤銷。
openssl ca -config root_ca.conf -in root_ocsp.csr -out root_ocsp.crt -extensions ocsp_ext -days 30
我們可以通過以下命令來測試生成的OCSP證書。
#啟動本地的OCSP響應器,一般不要放在根CA所在的機器
openssl ocsp -port 9080 -index db/index -rsigner root_ocsp.crt -rkey private/root_ocsp.key -CA root_ca.crt -text
#驗證OCSP響應器操作
openssl ocsp -issuer root_ca.crt -CAfile root_ca.crt -cert root_ocsp.crt -url http://127.0.0.1:9080
驗證成功后,會得到類似于以下的內容:
Response verify OK
root_ocsp.crt: good
This Update: Aug 21 09:37:03 2017 GMT
創建下級CA
- 創建下級CA和創建根CA步驟是一樣的,我們以根CA的配置文件(sub_ca.conf)為基礎,做了以下列出來的修改,注意單詞拼寫,如果有錯誤的話對照著錯誤提示或者下面的示例來更改:
[default]
name=sub_ca
ocsp_url=http://ocsp.$name.$domain_suffix:9081
[ca_dn]
countryName="GB"
organizationName="Example"
commonName="Sub CA"
[ca_default]
default_days=365
default_crl_days=30
#copy代表CSR的extensions會被拷貝到證書中
copy_extensions=copy
新增了server_ext和client_ext兩個節:
[server_ext]
authorityInfoAccess=@issuer_info
authorityKeyIdentifier=keyid:always
basicConstraints=critical,CA:false
crlDistributionPoints=@crl_info
extendedKeyUsage=clientAuth,serverAuth
keyUsage=critical,digitalSignature,keyEncipherment
subjectKeyIdentifier=hash
[client_ext]
authorityInfoAccess=@issuer_info
authorityKeyIdentifier=keyid:always
basicConstraints=critical,CA:false
crlDistributionPoints=@crl_info
extendedKeyUsage=clientAuth
keyUsage=critical,digitalSignature
subjectKeyIdentifier=hash
- 生成下級CA
- 首先參照根CA創建CA目錄。
- 生成下級CA私鑰和CSR
openssl req -new -config sub_ca.conf -out sub_ca.csr -keyout private/sub_ca.key
- 使用根CA簽發下級CA證書
#開關extensions指定root_ca.conf中的sub_ca_ext節來配置下級CA的extensions。注意文件路徑。
openssl ca -config root_ca.conf -in sub_ca.csr -out sub_ca.crt -extensions sub_ca_ext
- 下級CA的操作
- 簽發服務端證書
執行以下命令時可能會提示db/index.attr文件找不到,該文件內僅僅包含一條信息unique_subject=no/yes
對應著我們在sub_ca.conf文件中的配置,我們可以創建這個文件并將信息輸入進去。有關這個錯誤的介紹可以參照這里。
openssl ca -config sub_ca.conf -in server.csr -out server.crt -extensions server_ext
- 簽發客戶端證書
openssl ca -config sub_ca.conf -in client.csr -out client.crt -extensions client_ext