建立私有CA,我就用openSSL

2022-07-21 15:00:25

簡介

一般情況下我們使用的證書都是由第三方權威機構來頒發的,如果我們有一個新的https網站,我們需要申請一個世界範圍內都獲得認可的證書,這樣我們的網站才能被無障礙的存取。

如果在某些情況下,我們的網站或者系統並不是公開的,但是也需要使用tls協定的話,那麼就需要自己搭建一個CA伺服器。這樣的CA伺服器就叫做private CA。

熟悉證書的朋友可能會說了,為什麼不使用自簽名證書呢?也可以達到安全通訊的目的。

這是因為自簽名證書的作用比較有限,它沒有CRL和OCSP的能力,並且使用起來也不是很方便。所以我們需要一整套有效的CA簽發體系,這也是我們需要搭建private CA的目的。

搭建root CA

在搭建root CA之前我們需要建立幾個合適的目錄來儲存CA的相關資訊,比如我們需要一個儲存證書的目錄certs,一個儲存金鑰的地方keys,一個CA資料庫db。

其中db需要一個index檔案,serial檔案和crlnumber檔案。

我們用下面的命令建立對應的檔案和目錄:

mkdir certs db keys
touch db/index
openssl rand -hex 16  > db/serial
echo 1001 > db/crlnumber

目錄建好之後,我們還需要一個非常重要的root ca組態檔。後續可以根據這個組態檔來建立CA相關的資訊。

一般情況下CA組態檔是不需要的,只有我們需要建立比較複雜CA的情況下才需要使用ca組態檔。

下面是一個CA組態檔的例子:

[default]
name                    = root-ca
domain_suffix           = flydean.com
default_ca              = ca_config
name_opt                = utf8,esc_ctrl,multiline,lname,align

[ca_config]
database                = db/index
serial                  = db/serial
crlnumber               = db/crlnumber
certificate             = root-ca.crt
private_key             = keys/root-ca.key
RANDFILE                = keys/random
new_certs_dir           = certs
unique_subject          = no
copy_extensions         = none
default_days            = 365
default_crl_days        = 100
default_md              = sha256
policy                  = ca_policy

[ca_policy]
countryName             = match
stateOrProvinceName     = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[req]
default_bits            = 4096
encrypt_key             = yes
default_md              = sha256
utf8                    = yes
string_mask             = utf8only
prompt                  = no
distinguished_name      = ca_dist
req_extensions          = ca_req_ext

[ca_dist]
countryName             = "CN"
organizationName        = "flydean"
commonName              = "Root CA"

[ca_req_ext]
basicConstraints        = critical,CA:true
keyUsage                = critical,keyCertSign,cRLSign
subjectKeyIdentifier    = hash

[sub_ca_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:true,pathlen:0
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth,serverAuth
keyUsage                = critical,keyCertSign,cRLSign
subjectKeyIdentifier    = hash

[crl_info]
URI.0                   = http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl

[issuer_info]
caIssuers;URI.0         = http://cacerts.digicert.com/DigiCertTLSRSASHA2562020CA1-1.crt
OCSP;URI.0              = http://ocsp.digicert.com

[ocsp_ext]
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
extendedKeyUsage        = OCSPSigning
noCheck                 = yes
keyUsage                = critical,digitalSignature
subjectKeyIdentifier    = hash

生成root CA

有了上面的組態檔和目錄資訊,就可以生成root CA了。

首先我們需要建立私鑰和root ca的csr檔案如下:

openssl req -new -config root-ca.conf  -out root-ca.csr  -keyout keys/root-ca.key

接下來我們建立一個自簽名的證書,這裡我們需要用到組態檔中的ca_req_ext部分:

 openssl ca -selfsign  -config root-ca.conf  -in root-ca.csr   -out root-ca.crt -extensions ca_req_ext

執行該命令之後,我們會在certs資料夾中建立一個自簽名證書檔案。

除此之外,還向db中的index檔案中寫入了下面的內容:

V	230501041451Z		4445DE5C0285EAEF2E58757D5CB1E949	unknown	/C=CN/O=flydean/CN=Root CA

這是一個文字檔案,裡面儲存的是生成的證書索引,證書中的欄位是通過tab來進行分割的。

第一個欄位V表示valid也就是有效的意思,這個欄位還可以有其他幾個值,比如R表示revoked,E表示expired。

第二個欄位是過期時間,格式是YYMMDDHHMMSSZ。

第三個欄位是Revocation日期,如果空表示沒有revoked。

第四個欄位是序列號,也就是生成的CA名字。

第五個欄位是檔案的位置,unknown表示未知。

最後一個欄位是這個證書的名字,用於和其他的證書做區分。

使用CRL

有了root-ca.conf之後,我們可以使用它來建立CRL:

openssl ca -gencrl  -config root-ca.conf  -out root-ca.crl

現在生成的root-ca.crl檔案還沒有任何證書資訊。

如果我們想要復原某個頒發的CA,可以使用下面的命令:

openssl ca  -config root-ca.conf  -revoke certs/torevoke.pem -crl_reason unspecified

在revoke中指定要revoke的證書即可。

這裡要注意的是我們需要指定crl_reason,crl_reason可以是下面幾個值:

unspecified
keyCompromise
CACompromise
affiliationChanged
superseded
cessationOfOperation
certificateHold
removeFromCRL

使用OSCP

對於OSCP來說,需要一個OCSP responder來響應OCSP的請求。這個OCSP responder和CA本身並不是同一個,需要單獨建立。

首先,我們建立OCSP responder的key和證書請求CSR:

openssl req -new  -newkey rsa:2048  -keyout keys/root-ocsp.key -out root-ocsp.csr

當然輸入必須的引數之後,key和CSR就可以生成了。

接下來我可以使用root CA和root-ocsp.csr頒發OCSP證書,這裡我們需要用到組態檔中的ocsp_ext部分。

openssl ca  -config root-ca.conf  -in root-ocsp.csr  -out root-ocsp.crt -extensions ocsp_ext  -days 10

上面的命令為OCSP responder生成了一個有效期為10天的證書。

有了證書,我們可以方便的搭建一個原生的OCSP responder如下所示:

openssl ocsp  -port 9000 -index db/index  -rsigner root-ocsp.crt -rkey keys/root-ocsp.key  -CA root-ca.crt  -text
Enter pass phrase for keys/root-ocsp.key:
Waiting for OCSP client connections...

這樣我們就啟動了一個OCSP伺服器端。

另開一個視窗,執行下面的命令來請求OCSP:

 openssl ocsp -issuer root-ca.crt  -CAfile root-ca.crt  -cert root-ocsp.crt   -url http://127.0.0.1:9000

可以得到下面的結果:

Response verify OK
root-ocsp.crt: good
	This Update: May  1 08:09:31 2022 GMT

這就說明OCSP responder搭建成功了。

這裡啟動的是一個本地服務,在正式環境中可以考慮將其遷移到單獨的伺服器中。

總結

使用上面的命令,我們搭建了一個私有的CA服務,和對應的OCSP,openssl非常強大,基本上你可以用他來做任何事情。

更多內容請參考 http://www.flydean.com/45-openssl-private-ca/

最通俗的解讀,最深刻的乾貨,最簡潔的教學,眾多你不

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!