本文轉載自:https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html html
最近收到的幾封讀者郵件,都是詢問爲何在 Nginx 中沒法開啓 OCSP Stapling。具體現象是在 Nginx 中明明配置了 ssl_stapling on
,但經過 SSL Labs 等工具查看,OCSP stapling 這一項並無生效。本文就這個問題詳細探討下,若是你只關心結論,直接跳到最後一節便可。git
我以前在《TLS 握手優化詳解》這篇文章中介紹了 OCSP 是什麼,爲何要開啓 OCSP Stapling,這裏再簡單介紹下:api
OCSP(Online Certificate Status Protocol,在線證書狀態協議)是用來檢驗證書合法性的在線查詢服務,通常由證書所屬 CA 提供。某些客戶端會在 TLS 握手階段進一步協商時,實時查詢 OCSP 接口,並在得到結果前阻塞後續流程。OCSP 查詢本質是一次完整的 HTTP 請求 - 響應,這中間 DNS 查詢、創建 TCP、服務端處理等環節均可能耗費很長時間,致使最終創建 TLS 鏈接時間變得更長。瀏覽器
而 OCSP Stapling(OCSP 封套),是指服務端主動獲取 OCSP 查詢結果並隨着證書一塊兒發送給客戶端,從而讓客戶端跳過本身去驗證的過程,提升 TLS 握手效率。bash
經過前面提到的 SSL Labs 這個強大的在線服務,能夠輕鬆驗證指定網站是否開啓 OCSP Stapling。但這個網站功能太多,國內網站極可能要花十分鐘才能完成所有檢測項看到結果。服務器
使用 Wireshark 這個神器,設置好抓包條件和過濾器後,也能夠很方便地驗證某個網站是否開啓 OCSP Stapling,有興趣的同窗能夠本身試一下。session
本文介紹如何使用 openssl 這個命令行工具來完成一樣的任務。異步
多說一句,Mac 系統自帶的 openssl 版本過低了,建議經過 brew 裝上新版:ide
$ brew install openssl $ brew link openssl --force
若是使用其它系統,也請經過 openssl version
檢查一下 openssl 的版本,不要太舊了。工具
服務端啓用 OCSP Stapling 以後,客戶端還須要在創建 TLS 時,在 Client Hello 中啓用 status_request 這個 TLS 擴展,告訴服務端本身但願獲得 OCSP Response。目前主流瀏覽器都會帶上 status_request,而在 openssl 中須要指定 -status
參數。完整命令以下:
$ openssl s_client -connect imququ.com:443 -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"
若是你的服務器上部署了多個 HTTPS 站點,可能還須要加上 -servername
參數啓用 SNI:
$ openssl s_client -connect imququ.com:443 -servername imququ.com -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"
若是結果是下面這樣,說明 OCSP Stapling 已開啓:
OCSP response: OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response
而這樣顯然是未開啓:
OCSP response: no response sent
瞭解如何經過 openssl 驗證 OCSP Stapling 狀態後,咱們再來看看 OCSP Response 的完整內容,去掉前面命令中的 grep 就能夠看到。例如這是本站的:
$ openssl s_client -connect imququ.com:443 -status -tlsextdebug < /dev/null 2>&1OCSP response: ====================================== OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 87BAEBE8F7B12700EC9CD1A04EE0E123E57D809E Produced At: Mar 11 07:56:56 2016 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7C8E4E54532DB74C235073AAF1CDCF2C2423F86B Issuer Key Hash: F3B5560CC409B0B4CF1FAAF9DD2356F077E8A1F9 Serial Number: 5A26 Cert Status: good This Update: Mar 11 07:56:56 2016 GMT Next Update: Mar 18 07:56:56 2016 GMT Signature Algorithm: sha1WithRSAEncryption 8a:81:d6:a5:aa:8a:92:05:6f:39:97:f5:da:d0:bc:06:86:f2: ... ... Certificate: Data: Version: 3 (0x2) Serial Number: 8 (0x8) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G4 Validity Not Before: Jul 10 18:18:29 2015 GMT Not After : May 22 18:18:29 2016 GMT Subject: CN=RapidSSL SHA256 CA - G4 OCSP Responder Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:9d:e9:7b:75:81:1e:00:ab:b3:b4:cc:3f:a3:2d: ... ... Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Authority Key Identifier: keyid:F3:B5:56:0C:C4:09:B0:B4:CF:1F:AA:F9:DD:23:56:F0:77:E8:A1:F9 OCSP No Check: X509v3 Subject Key Identifier: 87:BA:EB:E8:F7:B1:27:00:EC:9C:D1:A0:4E:E0:E1:23:E5:7D:80:9E X509v3 Extended Key Usage: OCSP Signing X509v3 Basic Constraints: critical CA:FALSE X509v3 Key Usage: critical Digital Signature X509v3 Subject Alternative Name: DirName:/CN=TGV-C-26 Signature Algorithm: sha256WithRSAEncryption bb:ac:c3:3e:8b:20:be:a0:a7:4d:bb:e1:d1:c3:98:17:8e:58: ... ... -----BEGIN CERTIFICATE----- MIIDnTCCAoWgAwIBAgIBCDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJVUzEW ... ... bmgyvaosG4GykSUnasMqfbA= -----END CERTIFICATE----- ======================================
能夠看到 OCSP Response 由兩部分組成:OCSP Response Data 和 Certificate。OCSP Response Data 是本站證書的驗證信息;而 Certificate 則是用來驗證 OCSP Response Data。本例中的 Certificate 的 Common Name 是 RapidSSL SHA256 CA - G4 OCSP Responder,能夠看出它專屬於 RapidSSL 的 OCSP 服務。後面咱們會發現,並非每一家 CA 的 OCSP Response 都會提供 Certificate 信息。
上面這段 OCSP Response 信息是經過服務端 OCSP Stapling 獲取的。下面介紹如何經過 openssl 在本地獲取證書 OCSP Response。
首先須要準備好待驗證網站證書鏈上的全部證書。證書鏈通常由根證書、一個或多箇中間證書、站點證書組成。根證書內置在操做系統或瀏覽器內(Firefox),能夠直接導出,或者去各大 CA 官方下載;中間證書、站點證書在創建 TLS 鏈接時由服務端發送,能夠這樣獲取:
$ openssl s_client -connect imququ.com:443 -showcerts < /dev/null 2>&1CONNECTED(00000003) depth=2 C = US, O = GeoTrust Inc., OU = (c) 2008 GeoTrust Inc. - For authorized use only, CN = GeoTrust Primary Certification Authority - G3 verify return:1depth=1 C = US, O = GeoTrust Inc., CN = RapidSSL SHA256 CA - G4 verify return:1depth=0 CN = www.imququ.com verify return:1--- Certificate chain 0 s:/CN=www.imququ.com i:/C=US/O=GeoTrust Inc./CN=RapidSSL SHA256 CA - G4 -----BEGIN CERTIFICATE----- MIIFMDCCBBigAwIBAgICWiYwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx ... ... fBv5YysJ/pgFe75P9RVALMiPUPHvH2FGI47pxlvzs5+7Gt2p -----END CERTIFICATE----- 1 s:/C=US/O=GeoTrust Inc./CN=RapidSSL SHA256 CA - G4 i:/C=US/O=GeoTrust Inc./OU=(c) 2008 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G3 -----BEGIN CERTIFICATE----- MIIEpjCCA46gAwIBAgIQKByJKWYUQ4BCY1U6MkCuszANBgkqhkiG9w0BAQsFADCB ... ... nPvdJAq9WZFKQgM4EnEyiHagjny7Mu+IKhvUam9QuVJni6sw+h/94ySa -----END CERTIFICATE----- --- Server certificate subject=/CN=www.imququ.com issuer=/C=US/O=GeoTrust Inc./CN=RapidSSL SHA256 CA - G4 --- No client certificate CA names sent Peer signing digest: SHA512 Server Temp Key: ECDH, P-256, 256 bits --- SSL handshake has read 3460 bytes and written 434 bytes --- New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 Server public key is 4096 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 Session-ID: B6A0F49F6DAD0BD8AFB63F87D134FFCBC2B1487CD81440C26D165B5738A5C3EC Session-ID-ctx: Master-Key: 72871B14BC37B08F51F818285264169C512B865D13839C9B824175115F008801781FBAC64D01FC76376BCAB85E6B8F84 Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 86400 (seconds) TLS session ticket: 0000 - 56 f8 0d dd 0e ea 7d 0b-09 70 0b dd 52 da b7 a8 V.....}..p..R... ... ... ... ... 00a0 - c2 25 af a9 46 69 64 73-69 16 ea 64 94 c7 f4 a4 .%..Fidsi..d.... Start Time: 1457861201 Timeout : 300 (sec) Verify return code: 0 (ok) --- DONE
以上內容中 Certificate Chain 這一節,編號爲 0 的證書是站點證書;編號爲 1 的證書是中間證書。個人證書鏈一共是三級,服務端只須要發送兩個證書,對於四級證書鏈,服務端就須要發送三個證書了。總之,只有根證書無需發送。
將站點證書保存爲 site.pem;中間證書保存爲 intermediate.pem(若是有多箇中間證書,按照子證書在上的順序保存);再從系統中導出對應的根證書存爲 root.pem。這樣,證書鏈上的全部證書都搞定了。爲了確保無誤,建議再驗證一下每一個證書的 Common Name:
$ openssl x509 -in site.pem -noout -subject subject= /CN=www.imququ.com $ openssl x509 -in intermediate.pem -noout -subject subject= /C=US/O=GeoTrust Inc./CN=RapidSSL SHA256 CA - G4 $ openssl x509 -in root.pem -noout -subject subject= /C=US/O=GeoTrust Inc./OU=(c) 2008 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G3
接着,獲取站點證書的 OCSP 服務地址:
$ openssl x509 -in site.pem -noout -ocsp_uri http://gz.symcd.com
如今萬事具有,使用如下命令便可得到站點證書的 OCSP Response:
$ openssl ocsp -issuer intermediate.pem -cert site.pem -no_nonce -text -url http://gz.symcd.com OCSP Request Data: Version: 1 (0x0) Requestor List: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7C8E4E54532DB74C235073AAF1CDCF2C2423F86B Issuer Key Hash: F3B5560CC409B0B4CF1FAAF9DD2356F077E8A1F9 Serial Number: 5A26 OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 87BAEBE8F7B12700EC9CD1A04EE0E123E57D809E Produced At: Mar 11 07:56:56 2016 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7C8E4E54532DB74C235073AAF1CDCF2C2423F86B Issuer Key Hash: F3B5560CC409B0B4CF1FAAF9DD2356F077E8A1F9 Serial Number: 5A26 Cert Status: good This Update: Mar 11 07:56:56 2016 GMT Next Update: Mar 18 07:56:56 2016 GMT Signature Algorithm: sha1WithRSAEncryption 8a:81:d6:a5:aa:8a:92:05:6f:39:97:f5:da:d0:bc:06:86:f2: ... ... Certificate: Data: Version: 3 (0x2) Serial Number: 8 (0x8) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G4 Validity Not Before: Jul 10 18:18:29 2015 GMT Not After : May 22 18:18:29 2016 GMT Subject: CN=RapidSSL SHA256 CA - G4 OCSP Responder Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:9d:e9:7b:75:81:1e:00:ab:b3:b4:cc:3f:a3:2d: ... ... Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Authority Key Identifier: keyid:F3:B5:56:0C:C4:09:B0:B4:CF:1F:AA:F9:DD:23:56:F0:77:E8:A1:F9 OCSP No Check: X509v3 Subject Key Identifier: 87:BA:EB:E8:F7:B1:27:00:EC:9C:D1:A0:4E:E0:E1:23:E5:7D:80:9E X509v3 Extended Key Usage: OCSP Signing X509v3 Basic Constraints: critical CA:FALSE X509v3 Key Usage: critical Digital Signature X509v3 Subject Alternative Name: DirName:/CN=TGV-C-26 Signature Algorithm: sha256WithRSAEncryption ... ... -----BEGIN CERTIFICATE----- MIIDnTCCAoWgAwIBAgIBCDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJVUzEW ... ... bmgyvaosG4GykSUnasMqfbA= -----END CERTIFICATE----- Response Verify Failure140735166222416:error:27069065:OCSP routines:OCSP_basic_verify:certificate verify error:ocsp_vfy.c:138:Verify error:unable to get local issuer certificate site.pem: good This Update: Mar 11 07:56:56 2016 GMT Next Update: Mar 18 07:56:56 2016 GMT
能夠看到,本身獲取的 OCSP Response 和服務端發送的 OCSP Stapling 徹底一致,響應中的 Cert Status: good
表示證書合法。
可是,這段內容最後,多了這樣的奇怪信息:
Response Verify Failure 140735166222416:error:27069065:OCSP routines:OCSP_basic_verify:certificate verify error:ocsp_vfy.c:138:Verify error:unable to get local issuer certificate
實際上,這是由於咱們沒有告訴 openssl 應該信任哪些證書,openssl 沒法驗證 OCSP Response 內容而報的錯。這個錯誤能夠經過加上 -noverify
參數屏蔽,但更好的作法是經過 -CAfile
指定信任證書。
將根證書、所有中間證書按照子證書在上的順序,保存爲 chain.pem
。再次執行:
$ openssl ocsp -CAfile chain.pem -issuer intermediate.pem -cert site.pem -no_nonce -text -url http://gz.symcd.com
這下,最終的結果就是 Response verify OK 了。
Nginx 在實現 OCSP Stapling 這部分邏輯時,直接使用了 OpenSSL 庫(這也解釋了爲何 Nginx + BoringSSL 不支持 OCSP Stapling)。咱們再來看看 Nginx 中與 OCSP Stapling 有關的三個重要配置項:
ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /your/path/to/chained.pem;
ssl_stapling
的做用天然不用說,ssl_trusted_certificate
至關於前面命令中的 -CAfile
。還記得前面說過「若是不指定 -CAfile
就得加上 -noverify
」麼,換句話說,若是開啓了 Nginx 的 ssl_stapling_verify
,但沒有正確配置 ssl_trusted_certificate
,就會致使 OCSP Response 驗證失敗,OCSP Stapling 天然不會生效。
昨天給我寫信的那位同窗就是栽在這裏。實際上,檢查 Nginx 的 error_log,應該有相似這樣的錯誤:
[error] 5594#0: OCSP_basic_verify() failed (SSL: error:27069065:OCSP routines:OCSP_basic_verify:certificate verify error:Verify error:unable to get local issuer certificate) while requesting certificate status, responder: gz.symcd.com
能夠看到,這個錯誤確實是 OpenSSL 庫報的。
看到這裏,有些同窗可能會說:不對,我明明開啓了 ssl_stapling_verify
,也沒有指定 ssl_trusted_certificate
,爲何個人 OCSP Stapling 功能也是正常的呢?
昨天那位同窗的郵件中也問到這個奇怪的問題:
我 Nginx 目前的 OCSP stapling 配置爲:
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 223.5.5.5 valid=300s;
resolver_timeout 5s;
有個奇怪的問題 :
我在使用 AlphaSSL 證書的域名測試 OCSP stapling 顯示 NO,可是用配置了 COMODO ECC 證書的域名 OCSP stapling 就爲 Yes。兩個域名的 Nginx 配置徹底相同。
看來這個問題遠遠沒這麼簡單,難道還跟證書有關?我找了一個一樣使用 COMODO 證書的站點,使用前面講過的方法得到了它的 OCSP Response:
$ openssl ocsp -CAfile root.pem -issuer intermediate.pem -cert site.pem -no_nonce -text -url http://ocsp.comodoca.com OCSP Request Data: Version: 1 (0x0) Requestor List: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7AE13EE8A0C42A2CB428CBE7A605461940E2A1E9 Issuer Key Hash: 90AF6A3A945A0BD890EA125673DF43B43A28DAE7 Serial Number: 15F3C026B44BEEF870A7A496640BC484 OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 90AF6A3A945A0BD890EA125673DF43B43A28DAE7 Produced At: Mar 12 23:59:22 2016 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7AE13EE8A0C42A2CB428CBE7A605461940E2A1E9 Issuer Key Hash: 90AF6A3A945A0BD890EA125673DF43B43A28DAE7 Serial Number: 15F3C026B44BEEF870A7A496640BC484 Cert Status: good This Update: Mar 12 23:59:22 2016 GMT Next Update: Mar 16 23:59:22 2016 GMT Signature Algorithm: sha256WithRSAEncryption 29:a8:b4:a3:60:98:d9:c3:4f:56:4b:72:6c:9a:9e:7f:51:2d: ... ... Response Verify Failure140735166222416:error:27069076:OCSP routines:OCSP_basic_verify:signer certificate not found:ocsp_vfy.c:92: site.pem: good This Update: Mar 12 23:59:22 2016 GMT Next Update: Mar 16 23:59:22 2016 GMT
此次測試全部步驟跟以前同樣,證書狀態正常,也指定了 -CAfile
,但 OCSP Response 驗證仍是失敗:
Response Verify Failure 140735166222416:error:27069076:OCSP routines:OCSP_basic_verify:signer certificate not found:ocsp_vfy.c:92:
從錯誤信息中能夠得知,COMODO 的 OCSP Response 沒有提供 Certificate 信息,致使沒法驗證其內容。進一步測試發現,對於這種狀況,Nginx 直接忽略了ssl_stapling_verify
參數,不管是否配置,都不執行 verify 操做。
通過測試,Let's Encrypt 的 OCSP 服務也沒有返回 Certificate,因此使用 Let's Encrypt 證書,開啓 OCSP Stapling 也無需配置 ssl_trusted_certificate
。
順便說一下,獲取 Let's Encrypt 證書的 OCSP Response 必定要指定 Host,就像這樣:
openssl ocsp -CAfile chain.pem -issuer intermediate.pem -cert site.pem -no_nonce -text -url http://ocsp.int-x1.letsencrypt.org/ -header "HOST" "ocsp.int-x1.letsencrypt.org"
在 Nginx 中配置 ssl_stapling on
並 reload 後,Nginx 並不會立刻獲取 OCSP Response,它要等第一個請求過來,再發起異步 OCSP 請求,因此剛開始幾個響應,極可能不帶 OCSP Stapling。另外,有時候因爲 OCSP 域名沒法解析,或者服務器沒法訪問形成 OCSP Response 獲取失敗,也會致使 OCSP Stapling 沒法生效。這是首先須要排查的地方,通常在 Nginx 的 error_log 中會有這樣的錯誤:
[error] 5225#0: xxx.com could not be resolved (110: Operation timed out) while requesting certificate status, responder: xxx.com
若是 OCSP Response 包含了 Certificate 信息,而且 Nginx 配置了 ssl_stapling_verify on
,那麼須要確保正確配置了 ssl_trusted_certificate
參數,這個參數應該指向一個包含根證書、中間證書的文件(順序是子證書在上、父證書在下),不然 OCSP Stapling 沒法生效。這時候 Nginx 的 error_log 中會出現相似這樣的錯誤:
[error] 4832#0: OCSP_basic_verify() failed (SSL: error:27069065:OCSP routines:OCSP_basic_verify:certificate verify error:Verify error:unable to get local issuer certificate) while requesting certificate status, responder: xxx.com
若是證書 OCSP Response 沒有包含 Certificate 信息,例如 COMODO、Let's Encrypt 家的部分證書,那麼 ssl_stapling_verify
和 ssl_trusted_certificate
兩個配置能夠忽略,徹底不影響開啓 OCSP Stapling。
.