CRL 概述與用途
憑證吊銷清單(Certificate Revocation List,CRL)是公開金鑰基礎建設(PKI)中用於管理已失效憑證的重要機制。當憑證在有效期限內因各種原因(如私鑰外洩、持有者離職、憑證資訊變更等)需要提前作廢時,憑證授權中心(CA)會將該憑證的序號加入 CRL 中。
CRL 的主要用途包括:
- 安全性維護:確保已被吊銷的憑證不再被信任
- 合規性要求:符合各類安全標準對憑證管理的規範
- 風險控管:及時處理憑證洩露或誤發的情況
- 身份驗證:在驗證憑證時檢查其是否已被吊銷
CRL vs OCSP 比較
除了 CRL 之外,線上憑證狀態協定(OCSP)是另一種常見的憑證狀態檢查機制。以下是兩者的比較:
| 特性 | CRL | OCSP |
|---|
| 運作方式 | 下載完整清單 | 即時查詢單一憑證 |
| 頻寬消耗 | 較高(需下載整份清單) | 較低(僅查詢特定憑證) |
| 即時性 | 較差(依發布週期) | 較佳(即時查詢) |
| 離線支援 | 支援(可快取) | 不支援 |
| 隱私性 | 較佳(不洩露查詢行為) | 較差(CA 可追蹤查詢) |
| 實作複雜度 | 較簡單 | 較複雜 |
CRL 結構與欄位
CRL 採用 X.509 標準格式,主要包含以下欄位:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| CRL 結構
├── tbsCertList(待簽名的憑證清單)
│ ├── version(版本,v2 為 1)
│ ├── signature(簽章演算法)
│ ├── issuer(發行者名稱)
│ ├── thisUpdate(本次更新時間)
│ ├── nextUpdate(下次更新時間)
│ ├── revokedCertificates(已吊銷憑證清單)
│ │ ├── userCertificate(憑證序號)
│ │ ├── revocationDate(吊銷日期)
│ │ └── crlEntryExtensions(擴充欄位)
│ └── crlExtensions(CRL 擴充欄位)
├── signatureAlgorithm(簽章演算法)
└── signatureValue(簽章值)
|
常見的吊銷原因代碼(CRL Reason Code):
| 代碼 | 名稱 | 說明 |
|---|
| 0 | unspecified | 未指定原因 |
| 1 | keyCompromise | 私鑰洩露 |
| 2 | cACompromise | CA 私鑰洩露 |
| 3 | affiliationChanged | 隸屬關係變更 |
| 4 | superseded | 憑證被取代 |
| 5 | cessationOfOperation | 停止運作 |
| 6 | certificateHold | 憑證暫停(可恢復) |
| 9 | privilegeWithdrawn | 權限撤銷 |
| 10 | aACompromise | 屬性授權中心洩露 |
使用 OpenSSL 建立 CRL
準備 CA 環境
首先,建立 CA 所需的目錄結構和設定檔:
1
2
3
4
5
6
| # 建立目錄結構
mkdir -p ~/ca/{certs,crl,newcerts,private}
chmod 700 ~/ca/private
touch ~/ca/index.txt
echo 1000 > ~/ca/serial
echo 1000 > ~/ca/crlnumber
|
建立 OpenSSL 設定檔 ~/ca/openssl.cnf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| [ ca ]
default_ca = CA_default
[ CA_default ]
dir = /home/user/ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
crlnumber = $dir/crlnumber
private_key = $dir/private/ca.key
certificate = $dir/certs/ca.crt
crl = $dir/crl/ca.crl
default_md = sha256
default_days = 365
default_crl_days = 30
policy = policy_loose
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ crl_ext ]
authorityKeyIdentifier = keyid:always
|
建立 CA 憑證
1
2
3
4
5
6
7
8
9
10
| # 產生 CA 私鑰
openssl genrsa -aes256 -out ~/ca/private/ca.key 4096
# 產生 CA 憑證
openssl req -config ~/ca/openssl.cnf \
-key ~/ca/private/ca.key \
-new -x509 -days 3650 -sha256 \
-extensions v3_ca \
-out ~/ca/certs/ca.crt \
-subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=Example CA"
|
產生初始 CRL
1
2
3
4
5
6
| # 產生空的 CRL
openssl ca -config ~/ca/openssl.cnf \
-gencrl -out ~/ca/crl/ca.crl
# 檢視 CRL 內容
openssl crl -in ~/ca/crl/ca.crl -text -noout
|
吊銷憑證流程
簽發測試憑證
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 產生伺服器私鑰
openssl genrsa -out ~/ca/private/server.key 2048
# 產生憑證簽署請求(CSR)
openssl req -new -key ~/ca/private/server.key \
-out ~/ca/certs/server.csr \
-subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=www.example.com"
# CA 簽發憑證
openssl ca -config ~/ca/openssl.cnf \
-days 365 -notext -md sha256 \
-in ~/ca/certs/server.csr \
-out ~/ca/certs/server.crt
|
吊銷憑證
1
2
3
4
5
6
7
8
9
10
11
| # 吊銷憑證(指定原因為私鑰洩露)
openssl ca -config ~/ca/openssl.cnf \
-revoke ~/ca/certs/server.crt \
-crl_reason keyCompromise
# 重新產生 CRL
openssl ca -config ~/ca/openssl.cnf \
-gencrl -out ~/ca/crl/ca.crl
# 驗證憑證已被加入 CRL
openssl crl -in ~/ca/crl/ca.crl -text -noout | grep -A 2 "Serial Number"
|
CRL 分發點設定
CRL 分發點(CRL Distribution Point,CDP)用於告知用戶端從何處取得 CRL。在憑證中加入 CDP 擴充欄位:
1
2
3
4
5
6
7
| # 在 openssl.cnf 中加入以下設定
[ server_cert ]
crlDistributionPoints = URI:http://crl.example.com/ca.crl
[ crl_info ]
URI.0 = http://crl.example.com/ca.crl
URI.1 = ldap://ldap.example.com/cn=CA,dc=example,dc=com?certificateRevocationList
|
簽發憑證時套用設定:
1
2
3
4
5
| openssl ca -config ~/ca/openssl.cnf \
-extensions server_cert \
-days 365 -notext -md sha256 \
-in ~/ca/certs/server.csr \
-out ~/ca/certs/server.crt
|
驗證 CRL
檢視 CRL 資訊
1
2
3
4
5
6
7
8
9
10
11
| # 檢視 CRL 詳細內容
openssl crl -in ~/ca/crl/ca.crl -text -noout
# 檢視 CRL 發行者
openssl crl -in ~/ca/crl/ca.crl -issuer -noout
# 檢視 CRL 有效期間
openssl crl -in ~/ca/crl/ca.crl -lastupdate -nextupdate -noout
# 轉換 CRL 格式(DER 轉 PEM)
openssl crl -in ca.crl -inform DER -out ca.pem -outform PEM
|
使用 CRL 驗證憑證
1
2
3
4
5
6
7
8
| # 合併 CA 憑證與 CRL
cat ~/ca/certs/ca.crt ~/ca/crl/ca.crl > ~/ca/certs/ca-bundle.pem
# 驗證憑證狀態
openssl verify -crl_check -CAfile ~/ca/certs/ca-bundle.pem ~/ca/certs/server.crt
# 驗證憑證鏈(包含中繼 CA)
openssl verify -crl_check_all -CAfile ~/ca/certs/ca-bundle.pem ~/ca/certs/server.crt
|
Delta CRL
Delta CRL 是一種增量式 CRL,只包含自上次完整 CRL 發布後新增的吊銷憑證。這可以大幅減少頻寬消耗。
1
2
3
4
5
6
| # 產生 Delta CRL
openssl ca -config ~/ca/openssl.cnf \
-gencrl -crlexts crl_ext \
-crl_lastupdate 20240401000000Z \
-crl_nextupdate 20240408000000Z \
-out ~/ca/crl/delta.crl
|
Delta CRL 的設定需要在 openssl.cnf 中加入:
1
2
3
4
5
6
7
8
| [ crl_ext ]
authorityKeyIdentifier = keyid:always
issuingDistributionPoint = critical, @idp_section
deltaCRLIndicator = critical, 1000
[ idp_section ]
fullname = URI:http://crl.example.com/ca.crl
onlyuser = TRUE
|
CRL 的限制與挑戰
主要限制
- 延遲問題:CRL 有發布週期,在下次更新前無法反映最新的吊銷狀態
- 檔案大小:隨著吊銷憑證增加,CRL 檔案會持續增長
- 頻寬消耗:用戶端需要定期下載完整 CRL
- 可用性依賴:CRL 分發點若無法存取,可能導致驗證失敗
最佳實踐
- 設定合理的 CRL 更新週期(通常 1-7 天)
- 部署多個 CRL 分發點以提高可用性
- 考慮搭配 OCSP 使用以提供即時驗證
- 實施 CRL 快取機制以減少頻寬消耗
- 定期監控 CRL 大小和發布狀態
自動化 CRL 更新腳本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| #!/bin/bash
# crl-update.sh - 自動更新 CRL 腳本
CA_DIR="/home/user/ca"
CRL_FILE="${CA_DIR}/crl/ca.crl"
WEB_DIR="/var/www/html/crl"
# 產生新的 CRL
openssl ca -config ${CA_DIR}/openssl.cnf -gencrl -out ${CRL_FILE}
# 複製到 Web 伺服器目錄
cp ${CRL_FILE} ${WEB_DIR}/
# 設定正確權限
chmod 644 ${WEB_DIR}/ca.crl
# 記錄更新時間
echo "CRL updated at $(date)" >> ${CA_DIR}/crl/update.log
|
可搭配 cron 排程自動執行:
1
2
| # 每天凌晨 2 點更新 CRL
0 2 * * * /home/user/ca/scripts/crl-update.sh
|
參考資料