從無法開啟 OCSP Stapling 說起

qqqab 8年前發布 | 21K 次閱讀 OpenSSL 加密解密 Nginx Web服務器

最近收到的幾封讀者郵件,都是詢問為什么在 Nginx 中無法開啟 OCSP Stapling。具體現象是在 Nginx 中明明配置了 ssl_stapling on ,但通過 SSL Labs 等工具查看,OCSP stapling 這一項并沒有生效。本文就這個問題詳細探討下,如果你只關心結論,直接跳到最后一節即可。

我之前在《TLS 握手優化詳解》這篇文章中介紹了 OCSP 是什么,為什么要開啟 OCSP Stapling,這里再簡單介紹下:

OCSP(Online Certificate Status Protocol,在線證書狀態協議)是用來檢驗證書合法性的在線查詢服務,一般由證書所屬 CA 提供。某些客戶端會在 TLS 握手階段進一步協商時,實時查詢 OCSP 接口,并在獲得結果前阻塞后續流程。OCSP 查詢本質是一次完整的 HTTP 請求 - 響應,這中間 DNS 查詢、建立 TCP、服務端處理等環節都可能耗費很長時間,導致最終建立 TLS 連接時間變得更長。

而 OCSP Stapling(OCSP 封套),是指服務端主動獲取 OCSP 查詢結果并隨著證書一起發送給客戶端,從而讓客戶端跳過自己去驗證的過程,提高 TLS 握手效率。

驗證 OCSP Stapling 狀態

通過前面提到的 SSLLabs 這個強大的在線服務,可以輕松驗證指定網站是否開啟 OCSP Stapling。但這個網站功能太多,國內網站很可能要花十分鐘才能完成全部檢測項看到結果。

使用 Wireshark 這個神器,設置好抓包條件和過濾器后,也可以很方便地驗證某個網站是否開啟 OCSP Stapling,有興趣的同學可以自己試一下。

本文介紹如何使用 openssl 這個命令行工具來完成同樣的任務。

多說一句,Mac 系統自帶的 openssl 版本太低了,建議通過 brew 裝上新版:

$ brew install openssl
$ brew link openssl --force

如果使用其它系統,也請通過 openssl version 檢查一下 openssl 的版本,不要太舊了。

服務端啟用 OCSP Stapling 之后,客戶端還需要在建立 TLS 時,在 Client Hello 中啟用 status_request 這個 TLS 擴展,告訴服務端自己希望得到 OCSP Reponse。目前主流瀏覽器都會帶上 status_request,而在 openssl 中需要指定 -status 參數。完整命令如下:

$ openssl s_client -connect imququ.com:443 -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

獲取證書 OCSP Response

了解如何通過 openssl 驗證 OCSP Stapling 狀態后,我們再來看看 OCSP Response 的完整內容,去掉前面命令中的 grep 就可以看到。例如這是本站的:

$ openssl s_client -connect imququ.com:443 -status -tlsextdebug < /dev/null 2>&1

OCSP 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>&1

CONNECTED(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:1
depth=1 C = US, O = GeoTrust Inc., CN = RapidSSL SHA256 CA - G4
verify return:1
depth=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 Failure
140735166222416: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 Reponse 內容而報的錯。這個錯誤可以通過加上 -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 Failure
140735166222416: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"

啟用 OCSP Stapling 的條件

在 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。

好了,本文先寫到這里。本站近期開始接受捐贈,如果你認為本站文章對你有幫助,歡迎捐贈本站。詳情請點擊這里 ?

本文鏈接: https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html參與評論

-- EOF --

發表于 2016-03-13 21:06:57 ,并被添加「OCSP、 HTTPNginx 、Certificate」標簽。

本站所有文章均為本人原創,如果你認為我的文章對你有幫助,歡迎捐贈本站。詳情請點這里 ?

專題「Web 服務器」的其他文章?

 

來自: https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html

 

 本文由用戶 qqqab 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!