神刀安全网

从无法开启 OCSP Stapling 说起

最近收到的几封读者邮件,都是询问为什么在 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_verifyssl_trusted_certificate 两个配置可以忽略,完全不影响开启 OCSP Stapling。

好了,本文先写到这里。本站近期开始接受捐赠,如果你认为本站文章对你有帮助,欢迎捐赠本站。详情请点击这里 »

本文链接: 参与评论

EOF

发表于 2016-03-13 21:06:57 ,并被添加「OCSP、 HTTPNginx 、Certificate」标签。

本站所有文章均为本人原创,如果你认为我的文章对你有帮助,欢迎捐赠本站。详情请点这里 »

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 从无法开启 OCSP Stapling 说起

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮