OpenSSL 建立私有 CA 三部曲:
使用 OpenSSL 建立私有 CA:1 根證書
使用 OpenSSL 建立私有 CA:2 中間證書
使用 OpenSSL 建立私有 CA:3 用戶證書html
本文將在前文《使用 OpenSSL 建立私有 CA:1 根證書》的基礎上介紹如何爲私有 CA 建立中間證書。
說明:本系列文章的演示環境爲 Ubuntu 18.04,OpenSSL 的版本爲 1.1.0g。linux
使用 CA 的根證書是能夠直接簽發用戶證書的,那麼爲何還還要建立中間證書呢?
大概有兩個緣由:git
先說安全性,經過簽發中間證書,再用中間證書籤發用戶證書的方式,能夠最大程度的減小更證書的使用頻率,甚至能夠離線保存根證書。若是發現中間證書被破壞,還能夠吊銷該中間證書並頒發新的中間證書。
再來講說中間證書頒發機構(CA),一箇中間證書頒發機構(CA)是一個實體,它具備根 CA 頒發的中間證書,而且能夠表明根 CA 頒發用戶證書,從而造成一條被信任的證書鏈。
這裏有必要介紹下證書產業的基本玩法:首先根證書的全部者(大的證書廠商)會和 OS 廠商合做,讓 OS 等環境默認信任本身的根證書。而後根證書的全部者會簽發中間證書賣給小一些的證書廠商。這些小的證書廠商再用中間證書建立最終證書賣給普通消費者。
舉個例子,像咱們經常使用的 Windows 操做系統默認就信任了不少廠商的根證書,好比 VeriSign 的證書,而且這些證書還會隨着 Windows 系統的更新而更新:web
上圖中,VeriSign 是根證書全部者,你安裝 windows 操做系統時,VeriSign 的根證書就被安裝到信任列表中了。Symantec Class 3 SHA256 Code Signing CA 則是 Symantec 公司從 VeriSign 公司購買的中間證書。GrapeCity inc. 則是 GrapeCity 公司從 Symantec 公司購買的最終證書用來對產品進行簽名。固然,有時候根證書廠商好比 VeriSign 等也會直接向最終用戶銷售證書。數據庫
爲了模擬中間證書頒發機構(CA),本文將使用前文中建立的根證書建立一個名稱爲 power 的中間證書。windows
建立文件配置文件 powerca/powerca.cnf,編輯其內容以下:瀏覽器
# OpenSSL root CA configuration file. # v1 [ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = /home/nick/projects/myca/powerca certs = $dir/certs crl_dir = $dir/crl new_certs_dir = $dir/newcerts database = $dir/db/index serial = $dir/db/serial RANDFILE = $dir/private/random # The root key and root certificate. private_key = $dir/private/powerca.key.pem certificate = $dir/certs/powerca.cert.pem # For certificate revocation lists. crlnumber = $dir/db/crlnumber crl = $dir/crl/powerca.crl.pem crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 name_opt = ca_default cert_opt = ca_default default_days = 3750 copy_extensions = copy preserve = no policy = policy_loose [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). # Optionally, specify some defaults. prompt = no input_password = 123456 default_bits = 2048 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 # Extension to add when the -x509 option is used. # make sure use x509_extensions, do not use req_extensions. x509_extensions = v3_ca # use the req_extensions not work. #req_extensions = v3_ca [ req_distinguished_name ] # See <https://en.wikipedia.org/wiki/Certificate_signing_request>. countryName = CN stateOrProvinceName = ShaanXi localityName = Xian organizationName = NickLi Ltd organizationalUnitName = NickLi Ltd CA commonName = NickLi Power CA emailAddress = ljfpower@163.com [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning
這個配置文件的內容和 rootca/rootca.cnf 有不少相同之處,下面是一些比較重要的不一樣之處:安全
[ CA_default ] dir = /home/nick/projects/myca/powerca private_key = $dir/private/powerca.key.pem certificate = $dir/certs/powerca.cert.pem crl = $dir/crl/powerca.crl.pem policy = policy_loose [ req_distinguished_name ] commonName = NickLi Power CA
CA_default 中的變化主要是告訴 OpenSSL 相關文件的路徑,而中間證書的 commonName 必須不一樣於根證書。bash
與 rootca 目錄相同,咱們須要在 powerca 目錄下建立以下的目錄和文件:dom
powerca/certs/ powerca/db/ powerca/private/ powerca/crl/ powerca/csr/ powerca/newcerts/ powerca/db/index powerca/db/serial powerca/db/crlnumber
其中的 powerca/private 目錄需一樣要 700 的權限,咱們使用下面的腳原本建立這些目錄和文件:
#!/bin/bash # create dir certs db private crl csr newcerts under powerca dir. if [ ! -d powerca/certs ]; then mkdir -p powerca/certs fi if [ ! -d powerca/db ]; then mkdir -p powerca/db touch powerca/db/index openssl rand -hex 16 > powerca/db/serial echo 1001 > powerca/db/crlnumber fi if [ ! -d powerca/private ]; then mkdir -p powerca/private chmod 700 powerca/private fi if [ ! -d powerca/crl ]; then mkdir -p powerca/crl fi if [ ! -d powerca/newcerts ]; then mkdir -p powerca/newcerts fi if [ ! -d powerca/csr ]; then mkdir -p powerca/csr fi
把上面的代碼保存到 myca/powerhelper.sh 文件中,而後 cd 到 myca 目錄下執行:
$ ./powerhelper.sh
此時當前目錄爲 myca,powerca 下的子目錄和文件都已經建立成功。
進入 powerca 目錄:
$ cd powerca
執行下面的命令重建私鑰:
$ openssl genrsa -aes256 -out powerca/private/powerca.key.pem 4096
這裏筆者設置的密碼爲:123456,記住這個密碼,後面還會用到。而後爲了確保安全,把祕鑰的權限設置爲 400:
$ chmod 400 private/powerca.key.pem
此時當前目錄爲 myca/powerca。
要建立中間證書,須要使用帶有 v3_intermediate_ca 擴展名的根 CA 來簽署中間 CSR,其中 v3_intermediate_ca 擴展的配置信息就在 powerca/powerca.cnf 中:
[ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign
如今直接建立 csr 就好了:
$ openssl req -new \ -config powerca.cnf \ -sha256 \ -key private/powerca.key.pem \ -out csr/powerca.csr.pem
下面的命令能夠檢查生成的 csr:
$ openssl req -text -noout -in csr/powerca.csr.pem
注意,csr 中包含了 CA 的基本信息,和公鑰信息。
下面是整個過程當中最爲關鍵的地方!經過 Root CA 的信息和用戶的 csr 爲用戶生成證書。
建立中間證書須要用到 rootca/rootca.cnf 中的配置信息,因此先進入 myca 目錄:
# 從 powerca 目錄回到 myca 目錄 $ cd .. $ openssl ca -config rootca/rootca.cnf \ -extensions v3_intermediate_ca \ -days 3650 -notext -md sha256 \ -in powerca/csr/powerca.csr.pem \ -out powerca/certs/powerca.cert.pem
在交互式的提示中輸入私鑰的密碼 123456,並贊成其它的確認提示,就完成了根證書的生成操做:
rootca/db/index 文件是 OpenSSL CA 工具存儲證書的數據庫,請不要手動修改這個文件(除非你清楚的知道本身在幹什麼)。此時它應該包含了根證書和中間證書的信息:
證書生成後咱們把它的權限修改成 444:
$ chmod 444 powerca/certs/powerca.cert.pem
經過下面的命令驗證中間證書:
$ openssl x509 -noout -text -in powerca/certs/powerca.cert.pem
在中間證書中,Subject 的 Common Name 爲 "NickLi Power CA",而 Issuer 的 Common Name 爲 "NickLi Root CA"。
還能夠經過下面的命令來檢查中間證書的狀態:
$ openssl verify -CAfile rootca/certs/rootca.cert.pem powerca/certs/powerca.cert.pem
當 web 瀏覽器等應用程序試圖驗證中間 CA 頒發的證書時,它還必須根據根證書驗證中間證書。這就須要構建完整的證書信任鏈供應用程序驗證。所謂的證書鏈,簡單的說就是把根證書和中間證書按照順序放置在同一個證書文件中。重點是:中間證書在上面,根證書在下面。好比爲咱們的中間證書建立證書鏈:
$ cat powerca/certs/powerca.cert.pem \ rootca/certs/rootca.cert.pem > powerca/certs/powerca-chain.cert.pem $ chmod 444 powerca/certs/powerca-chain.cert.pem
注意:在局域網環境中,咱們通常會把生成的這個證書鏈安裝到用戶的機器上。
pem 格式的證書、證書鏈文件適用的場景比較多,可是在 windows 系統中通常使用 p12 格式,因此咱們還須要建立一個 p12 格式的證書鏈:
$ openssl pkcs12 -export \ -name "powerca chain" \ -inkey powerca/private/powerca.key.pem \ -in powerca/certs/powerca.cert.pem \ -certfile powerca/certs/powerca-chain.cert.pem \ -out powerca/certs/powerca-chain.cert.p12
這個過程當中須要輸入私鑰 powerca/private/powerca.key.pem 的密碼(這裏是 123456),而且爲新證書設置的密碼。
如今咱們已經有了私有 CA 的根證書而且生成了中間證書和證書鏈,在接下來的《使用 OpenSSL 建立私有 CA:3 用戶證書》一文中咱們將詳細的介紹如何使用中間證書建立用戶證書,以及如何把證書部署到 web 站點和客戶端。
參考:
OpenSSL Certificate Authority
《openssl-cookbook》