2023年6月5日 星期一

Client Certificate 的 OCSP (Online Certificate Status Protocol) 設定

這篇是的
使用 OpenSSL 製做 Client Certificate 做客戶端 TLS 認證 - 配合 Nginx 和 Java 做示範
的 OCSP 設定補充。

如果要看 CRL 的設定可以看我的另一篇文章:

Client Certificate 的 CRL (Certificate Revocation List) 設定

OCSP 的全名是 Online Certificate Status Protocol,
跟 CRL 相同的地方是,它一樣可以用一個 ./db/index 來紀錄憑證的撤銷狀態。
跟 CRL 不同的地方是,它不是提供一個憑證撤銷清單,而是自行啟動一個伺服器,我們把它叫做 OCSP Responder,當想要對憑證狀態進行確認時,可以對 OCSP Responder 發起詢問的請求 (OCSP Request),OCSP Responder 再把憑證的狀態回傳回去 (OCSP Response)。

跟 CRL 比較起來,OCSP 有幾個優點:
  1. 不像 CRL 一次回傳多個憑證狀態,一次只回傳被詢問的憑證狀態,對於網路成本及詢問者的解析成本都比較低。
  2. 因為是由 OCSP Responder Server 即時回應,相較 CRL 可能一段時間才發出更新或才會被人詢問來說,能獲取比較即時的憑證狀態。
缺點也是有:
  1. OCSP Responder 的流量負擔可能比較大,可能可以用多台 Server 做 Revers Proxy 分流解決。
OCSP Responder 可以用任何技術實作,只要它能處理 OCSP Request 並回傳正確格式的 OCSP Response 即可,如何儲存憑證的撤銷狀態也可自行用任何方法實現,其實 CRL 也是一樣,只是上次我們就直接使用 OpenSSL 的 index 檔功能來幫助我們實現。

在這篇文中,我一樣會只使用 OpenSSL 來實現 OCSP Responder,OpenSSL 本身就可以開啟一個 OCSP Responder,並配合 OpenSSL index 檔來處理 OCSP Request。

---------------------------------------------------------------------------------------------
現在要來示範要做 Client Certificate 時,建立 OCSP Responder 和 Nginx 設定的方式。

Nginx 的設定非常簡單,接續這一篇文章的 Nginx 設定 使用 OpenSSL 製做 Client Certificate 做客戶端 TLS 認證 - 配合 Nginx 和 Java 做示範,只要再加上 ssl_ocsp ssl_ocsp_responder 設定即可。
server {
   ......
   ssl_client_certificate "ca.crt";
   ssl_verify_client optional;
   ssl_ocsp leaf; #值可以是 on, leaf, off,leaf 是指只對 client certificate 做 ocsp
   ssl_ocsp_responder http://127.0.0.1:9000; # 自行指定 OCSP Responder 的 url
   ......
}

為了之後管理方便,在這裡我先建了幾個資料夾和檔案 (./crlnumber 和 ./crl 資料夾就不用了):
  1. ./certs:存放憑證的地方。
  2. ./csr:存放 CSR 的地方。
  3. ./db/index:index 為我手動放置的一個空白檔案,作為一個紀錄憑證狀態的純文字檔,其實 CRL 可以不需要,主要給 OCSP 使用,但 CRL 也可從其中產生出 CRL 檔,也方便之後管理憑證狀態。
  4. ./keys:存放 Private Key 的地方。
  5. ./serial/serial:serial 為我手動放置的一個純文字檔案,其內容為一個單純的 serial number 序號,供憑證產生時的累加 Serial Key 使用,serial number 可視為對每一個 client certificate 的辨識唯一序號。
  6. ca.conf:供 openssl ca 指令用的配置檔,用以簡化指令參數長度及方便管理。
檔案內容例如可用以下指定 (自己用編輯器輸入也可以):
touch ./db/index
openssl rand -hex 16 > serial/serial
因為會用到
openssl ca 指令,為了方便我們先來建立一個 config 配置檔供 openssl ca 指令參考,
這樣 openssl ca 指令就可以少打一些參數。

ca.conf:
[default]
name                    = root-ca
default_ca              = ca_config

[ca_config]
database                = db/index
serial                  = serial/serial
crlnumber               = crlnumber/crlnumber
default_crl_days        = 1
certificate             = certs/ca.crt
private_key             = keys/ca.key
new_certs_dir           = certs
default_md              = sha256
policy                  = ca_policy
unique_subject          = no

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

[ocsp_ext]
basicConstraints        = critical,CA:false
extendedKeyUsage        = OCSPSigning
noCheck                 = yes
keyUsage                = critical,digitalSignature
subjectKeyIdentifier    = hash
接著各項指令如下,
#產生 CA private key
openssl genrsa -out ./keys/ca.key 4096

#產生 CA CSR
openssl req -new -key ./keys/ca.key -out ./csr/ca.csr

#產生 CA 憑證
openssl x509 -req -days 365 -in ./csr/ca.csr -signkey ./keys/ca.key -CAcreateserial -out ./certs/ca.crt

# OCSP Responder 也需要自己的憑證
#產生 OCSP Responder 的 private key
openssl genrsa -out ./keys/ocsp.key 4096

#產生 OCSP Responder 的 CSR
openssl req -new -key ./keys/ocsp.key -out ./csr/ocsp.csr

#產生 OCSP Responder Server 的 Certificate,這裡使用了 ocsp_ext 區塊
#不使用 config 檔裡的 ocsp_ext 區塊設定的話,之後向 OCSP Responder Server 驗證 Certificate 時會有 missing ocspsigning usage 錯誤訊息)
#此時 ./db/index 會被更新,可以看到有一筆 OCSP Certificate 的憑證資料被寫入
openssl ca -config ca.conf -in ./csr/ocsp.csr -out ./certs/ocsp.crt -extensions ocsp_ext -days 365

#啟動 OCSP Responder Server,這邊使用了 locahost 的 9000 port
#啟動成功後應該可以看到 console 顯示
#ocsp: waiting for OCSP client connections...
#的訊息
openssl ocsp -port 9000 -index ./db/index -rsigner ./certs/ocsp.crt -rkey ./keys/ocsp.key -CA ./certs/ca.crt -text

#產生 Client private key:
openssl genrsa -out ./keys/client.key 4096

#產生 Client CSR:
openssl req -new -key ./keys/client.key -out ./csr/client.csr

#產生 Client Certificate,
#此時 ./db/index 會被更新,可以看到有一筆 Client Certificate 的憑證資料被寫入
openssl ca -config ca.conf -in ./csr/client.csr -out ./certs/client.crt -days 365

#用 OpenSSL 對 OCSP Responder Server 發起 OCSP Request 進行憑證的驗證
#對 OCSP Certificate 做驗證
openssl ocsp -issuer ./certs/ca.crt -CAfile ./certs/ca.crt -cert ./certs/ocsp.crt -url http://127.0.0.1:9000
#對 Client Certificate 做驗證
openssl ocsp -issuer ./certs/ca.crt -CAfile ./certs/ca.crt -cert ./certs/client.crt -url http://127.0.0.1:9000
#如果驗證結果是合法 (Valid) 的話,應該會看到如下訊息:
Response verify OK
./certs/client.crt: good
        This Update: Jun
#被 Revoke 的憑證查詢結果會像這樣:
#(Reason 只會在 Revoke 時有加入 crl_reason 時才會出現,手動修改 ./db/index 內容也可以,就是在 Revoke date 欄位加上 Reason 並用逗號分隔)
Response verify OK
./certs/client.crt: revoked
        This Update: Jun  6 04:55:19 2023 GMT
		Reason: unspecified
        Revocation Time: Jun  6 04:53:37 2023 GMT

#撤銷 (Revoke) 一個 Certificate (可以看到跟 CRL 的 Revoke 指令相同,-crl_reason 參數可自選要不要加上)
openssl ca -config ca.conf -revoke ./certs/client.crt

#加進一個未撤銷 (Valid) 狀態的 Certificate 到 OCSP DB 中 (自己要先手動把 OCSP DB 中相同序號的 Certificate 紀錄刪掉),
#或是自己打開 OCSP DB 檔把 Certificate 的狀態從 R (Revoke 的意思) 改成 V (Valid 的意思) 也可以
openssl ca -valid ./certs/client.crt -config ca.conf

參考資料:

沒有留言 :

張貼留言