CA 證書單位
任何人都可以自己建立一個 CA 證書單位,並且用你所建立的 Root CA Key 去幫別人簽名,發給他人的證書基本上就會基於你的 Root CA Key 簽名得到背書,並關聯起來。
每個人的電腦系統都會安裝一些預設的 Root CA 證書,讓某些服務都可以使用,而瀏覽器本身也會自帶安裝一些 Root CA 的證書,讓民眾使用瀏覽器時可以信任某些單位的 CA,以 Chrome 為例,Chrome 有一個管理 CA 的計畫叫做 Chrome Root Program Policy (https://www.chromium.org/Home/chromium-security/root-ca-policy/),要申請加入要經過審查以及可能無法很快的就被加入 (根據網站說明是有可能一季一次)。
CA 證書單位常見的結構
- Root CA 跟憑證
- Private Key - CA 憑證的 Private Key,要用於幫別人簽名用,須保存好
- Public Key - 對外展示的 Public Key (.CRT / .PEM)
- CRL 吊銷證書列表 - 列出吊銷的 Public Key
- OCSP 吊銷證書服務 (Port: 9080) - 驗證 Public Key 是否被吊銷
- Intermediate CA (二級 CA 憑證)
- Private Key
- Public Key
- CRL 吊銷證書列表
- OCSP 吊銷證書服務 (Port: 9081)
- 子憑證
- Private Key (產生 CSR 的時候一併產生的)
- Public Key (CSR 被 Intermediate CA Private Key 簽名過後的 Public Key / .crt / .pem)
- 子憑證
- Private Key (產生 CSR 的時候一併產生的)
- Public Key (CSR 被 Root CA Private Key 簽名過後的 Public Key / .crt / .pem)
CRL 吊銷列表是一個檔案、OCSP Server 也是用於紀錄吊銷的憑證,這兩者基本上,瀏覽器訪問的時候不會特別去檢查 CRL 和 OCSP,CRL 只會不定期 (甚至需要自行去下載) 更新到電腦裡面,瀏覽器才會知道有哪些證書是吊銷過的。
在購買網域時,有時候會看到 EV SSL Extended Validation (EV),這個加註的功能是來自證書單位認定,他們會對證書做延伸驗證,就是用於檢查這個證書有沒有過期,延伸驗證基本上就是對 OCSP Server 發起請求去檢查有效性。*一般狀況是不會有人對 OCSP 發起驗證,除非做 Extended Validation (EV) 之類的
*大多 EV 收費高,是根據發出的證書數量決定每個月的價格
OpenSSL CA Config 詳細說明
需要先建立一個: openssl-rootca.conf
[default]
name = ca # 自訂命名
domain_suffix = example.com # 需要填寫 Domain 名稱
aia_url = http://$name.$domain_suffix/root-ca.crt # 有用到變數
crl_url = http://crl.$domain_suffix/$name.crl
ocsp_url = http://ocsp.$domain_suffix:9080
name_opt = utf8,esc_ctrl,multiline,lname,align
default_ca = ca_default # 參照下方 ca_default 設定
[ca_dn]
countryName = "國家代碼兩碼"
organizationName = "組織名稱"
commonName = "example.com"
[ca_default]
home = ./rootca
database = $home/db/index
serial = $home/db/serial
crlnumber = $home/db/crlnumber
certificate = $home/$name.crt # 預設證書的位置
private_key = $home/private/private.key # CSR Private Key 儲存位置
RANDFILE = $home/private/random
new_certs_dir = $home/certs
unique_subject = no
copy_extensions = copy
default_days = 3650 # 10 年 CA Root
default_crl_days = 3650 # 10 年 CRL 效期
default_md = sha256
policy = policy_c_o_match # 參照下方 policy_c_o_match 設定
[policy_c_o_match]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied # 設定支援 common name
emailAddress = optional
[req]
default_bits = 4096
encrypt_key = yes
default_md = sha256
utf8 = yes
string_mask = utf8only
prompt = no
distinguished_name = ca_dn # 請參考上面的 ca_dn 設定
req_extensions = ca_ext
[root_ca_ext]
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign,cRLSign # RFC 3280: "The nonRepudiation bit is asserted when the subject public key is used to verify digital signatures used to provide a non-repudiation service which protects against the signing entity falsely denying some action, excluding certificate or CRL signing. In the case of later conflict, a reliable third party may determine the authenticity of the signed data."
subjectKeyIdentifier = hash
[sub_ca_ext] # 二級 CA 設定
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:true,pathlen:0 # pathlen:0 規定這個簽發下去的證書二級 CA 無法再簽發新的 CA
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth,serverAuth
keyUsage = critical,keyCertSign,cRLSign,digitalSignature # v3_intermediate_ca
nameConstraints = @name_constraints # 參照下方 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 = examples.com # 設定簽發出來可使用的 domain name 或 IP
permitted;DNS.1 = localhost
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_ext]
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
extendedKeyUsage = OCSPSigning
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
[server_ext] # 給 server 用的證書簽名的設定
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false # 簽發出來的證書不是 CA
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth,serverAuth # 簽發出來的證書可以開 server, 當 client 證書拿去驗證
keyUsage = critical,digitalSignature,keyEncipherment
subjectKeyIdentifier = hash
[client_ext] # 給一般 client 用的證書簽名的設定
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false # 簽發出來的證書不是 CA
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth # 簽發出來的證書不可以開 server,只能當 client 證書用,除非加上 serverAuth
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
OpenSSL CA 生成憑證
- certs (由 CA 簽名出的證書 Public Key Certificate / .crt)
- db (目錄)
- index (文件)
- serial (文件)
- crlnumber (文件)
- private (目錄)
mkdir -p ./rootca/certs ./rootca/db ./rootca/private
openssl rand -hex 16 > ./rootca/db/serial
echo 1001 > ./rootca/db/crlnumber
openssl req -new -config openssl-rootca.conf -out RootCAPublicKey.csr -keyout ./rootca/private/private.key
3. 自行簽作為起始方 (Private Key 會讀取 openssl-rootca.conf 裡面的 ./rootca/private/private.key 位置
openssl ca -selfsign -config openssl-rootca.conf -in RootCAPublicKey.csr -out RootCA.crt -extensions root_ca_ext
現在 CA 憑證已經完成簽發,RootCA 就是 CA 憑證本身 (也是完成簽名的 PublicKey)。
建立 CRL 吊銷憑證證書設定
吊銷證書是附屬在 CA 憑證環節中重要的部分,他記錄了哪一些發出去的證書已經吊銷了。
openssl ca -gencrl -config openssl-rootca.conf -out ./rootca/ca.crl
現在已經完成產生基本的 crl 文件,裡面沒有任何被吊銷的證書。
CRL 吊銷證書
要吊銷證書,請執行指令
openssl ca -config openssl-rootca.conf -revoke ./rootca/certs/xxxx.crt -crl_reason keyCompromise
-crl_reason 這個可以使用其他種,原因有:
- keyCompromise
- CACompromise
- affiliationChanged
- superseded
- cessationOfOperation
- certificateHold
- removeFromCRL
每次吊銷完證書,需要重新執行一次 gencrl (參考上一小節)。
把所有發過的證書全部吊銷掉的腳本
for entry in "$(pwd)/rootca/certs/*"
do
openssl ca -config openssl-rootca.conf -revoke $entry -crl_reason keyCompromise -passin pass:[你的 CA 上鎖密碼]
done
openssl ca -gencrl -config openssl-rootca.conf -out ./rootca/ca.crl
驗證證書有效性
openssl verify -extended_crl -verbose -CAfile ./crl-bundle -crl_check ./certificate
建立 OSCP 吊銷憑證證書 Server 設定
OCSP 吊銷證書是啟動一個 Server 服務,然後供服務連入查詢,OpenSSL 內建就可以開啟這樣的 OCSP Server。 不過一定要注意 OSCP Server 連入不能是 https。
1. 先簽發一個 OCSP 用的 CSR 待簽名證書
openssl req -new -newkey rsa:2048 -subj "/C=TW/O=Org/CN=example.com" -keyout ./rootca/private/ocsp-private.key -out ./rootca/ocsp.csr
2. 用 CA 去發
openssl ca -config openssl-rootca.conf -in ./rootca/ocsp.csr -out ./rootca/ocsp.crt -extensions ocsp_ext -days 3650
3. 打開 OCSP Server
openssl ocsp -port 9080 -index ./rootca/db/index -rsigner ./rootca/ocsp.crt -rkey ./rootca/private/ocsp-private.key -CA ./rootca/ca.crt -text -ignore_err
4. 測試驗證 OCSP
openssl ocsp -issuer ./rootca/ca.crt -CAfile ./rootca/ca.crt -cert ./rootca/ocsp.crt -url http://127.0.0.1:9080
作為 CA 去簽發憑證給最終端使用者
1. 先設定一個 openssl-server.conf 給這個證書定義一些內容
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = TW
ST = Asia
L = Taiwan
O = Example
OU = Example
emailAddress = [email protected]
CN = localhost
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = my.example.com # 自己新增一些適用的證書範圍,也可以是 IP
DNS.2 = localhost
2. 簽發一個自用的 CSR 待簽名證書
openssl req -new -config openssl-server.conf -out ./my.csr -keyout ./my-private.key
3. 拿去 CA 簽發一個證書下來
openssl ca -config openssl-rootca.conf -in my.csr -out my.crt -extensions server_ext
如此一來就會產生一個被 CA 簽名過的證書了。
建立二級 CA
建立二級 CA 一樣會需要先定義一個 openssl-intermediate-ca.conf
目錄可學 root ca 一樣建立一樣的結構,目錄叫: ./intermediate-ca
1. 設定 openssl-intermediate-ca.conf:
[default]
name = intermediate-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:9081
default_ca = ca_default
name_opt = utf8,esc_ctrl,multiline,lname,align
[ca_dn]
countryName = "TW"
organizationName = "Org Name"
commonName = "Intermediate CA"
[ca_default]
home = ./intermediate-ca
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 = copy
default_days = 365
default_crl_days = 30
default_md = sha256
policy = policy_c_o_match
[policy_c_o_match]
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_dn
req_extensions = ca_ext
[ca_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
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 = xx.example.com
permitted;DNS.1 = localhost
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_ext]
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
extendedKeyUsage = OCSPSigning
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
[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,serverAuth
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
2. 產生一個待簽名 CSR (config 用的是 openssl-intermediate-ca.conf)
openssl req -new -config openssl-intermediate-ca.conf -out intermediate-ca.csr -keyout ./intermediate-ca/private/private.key
3. 用 Root CA 簽發 Intermediate CA
openssl ca -config openssl-rootca.conf -in ./intermediate-ca/intermediate-ca.csr -out ./intermediate-ca/intermediate-ca.crt -extensions sub_ca_ext
其他部分 - CA 單位驗證擁有權
通常作為 CA 要幫其他人去簽發證書,都會先去驗證他人對於他的 domain 擁有權,才能幫他們背書,這就是普遍發憑證的時候會要求去 DNS 加 txt 紀錄或是用 email 驗證的原因。
開 Server 測試
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(ctx *gin.Context) {
ctx.String(200, "ok")
})
r.RunTLS("0.0.0.0:443", "my.crt", "my-private.key")
}
接著,應該要先去點擊 ca.crt 兩下,讓電腦去信任他,並且把所有信任選項都打勾,開啟 Server 之後,透過瀏覽器去看,就會得到綠色的 https 了。 (前提是要手動電腦自己去點那個憑證然後信任)
沒有留言:
張貼留言