我试图在nginx中启用客户端证书身份验证,其中证书已由中间CA签名.使用由自签名根CA签名的证书时,我能够正常工作; 但是,当签名CA是中间CA时,这不起作用.
我的简单服务器部分如下所示:
server { listen 443; server_name _; ssl on; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_timeout 5m; ssl_protocols SSLv2 SSLv3 TLSv1; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; ssl_client_certificate ca.pem; ssl_verify_client on; ssl_verify_depth 1; location / { root html; index index.html index.htm; } }
对于ca.pem的内容,我尝试过只使用中间CA并连接中间CA证书和根CA证书,例如:
cp intermediate.crt ca.pem cat root.crt >> ca.pem
我还验证了在使用相同的CA链时,从openssl的角度来看证书是有效的:
openssl verify -CAfile /etc/nginx/ca.pem certs/client.crt certs/client.crt: OK
我已经尝试将ssl_verify_depth显式设置为1(如上所述)然后甚至为0(不确定该数字的确切含义),但仍然会得到相同的错误.
我在中间CA的所有变体中得到的错误是"400 Bad Request",更具体地说是"SSL证书错误"(不确定这意味着什么).
也许nginx只是不支持中间证书的证书链?任何帮助非常感谢!
编辑:我也有这个"问题",解决方案和解释是在文本的底部.
似乎nginx不支持中间证书.我的证书是自己创建的:(RootCA是自签名的,IntrermediateCA1是由RootCA签名的,等等)
RootCA -> IntermediateCA1 -> Client1 RootCA -> IntermediateCA2 -> Client2
我想在nginx"IntermediateCA1"中使用,只允许访问"Client1"证书的所有者.
当我使用IntermediateCA1和RootCA设置"ssl_client_certificate"文件并设置"ssl_verify_depth 2"(或更多)时,客户端可以使用证书Client1和Client2(仅应该是Client1)登录到站点.同样的结果是当我只使用RootCA放入"ssl_client_certificate"文件时- 两个客户端都可以登录.
当我只使用IntermediateCA1放入"ssl_client_certificate"文件,并设置"ssl_verify_depth 1"(或"2"或更多 - 无论如何)时,登录是不可能的,我得到错误400.在调试模式下,我看到日志:
verify:0, error:20, depth:1, subject:"/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=RootCA/emailAddress=cert@asdf.com" verify:0, error:27, depth:1, subject:"/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=RootCA/emailAddress=cert@asdf.com" verify:1, error:27, depth:0, subject:"/C=PL/CN=Client1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com" (..) client SSL certificate verify error: (27:certificate not trusted) while reading client request headers, (..)
我觉得这是一个错误.在Ubuntu上测试,nginx 1.1.19和1.2.7-1~dotdeb.1,openssl 1.0.1.我看到nginx 1.3有更多关于使用客户端证书的选项,但我们没有看到解决这个问题的方法.
目前,分离客户端1和2的唯一方法是创建两个自签名的RootCAs,但这只是解决方法.
编辑1: 我在这里报告了这个问题:http://trac.nginx.org/nginx/ticket/301
编辑2" *好的,这不是错误,它是功能;)*
我在这里得到回复:http ://trac.nginx.org/nginx/ticket/301 它正在运行,你必须只检查你的ssl_client_i_dn是什么(.你可以使用证书主题,或者你想要的东西,而不是发行者http://wiki.nginx.org/HttpSslModule#Built-in_variables
这是证书验证的工作原理:证书必须经过验证,最多可以验证到受信任的根.如果无法将链构建到受信任的根(非中间),则验证失败.如果您信任root,则将成功验证由其直接或间接签署的所有证书.
如果要将客户端证书限制为仅直接颁发的证书,则可以使用限制验证深度,但它更多的是关于DoS预防,显然它不能用于将verificate限制为仅限于中间1(而不是中间2).
你想要的是一些基于验证结果的授权层 - 即你可能想检查客户的证书发行者是否为中间1.如果发行人的DN与允许的DN不匹配,最简单的解决方案是拒绝请求,例如像这样(完全未经测试):
[由我编辑,它在我的配置中正常工作]
server { listen 443 ssl; ssl_certificate ... ssl_certificate_key ... ssl_client_certificate /path/to/ca.crt; ssl_verify_client on; ssl_verify_depth 2; if ($ssl_client_i_dn != "/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com") { return 403; } }
你试过增加ssl_verify_depth
指令吗?文件说:
(it) sets a verification depth in the client certificates chain.
但你的验证深度是1.你说:
我已经尝试将ssl_verify_depth显式设置为1(如上所述)然后甚至为0(不确定该数字的确切含义),但仍然会得到相同的错误.
所以,试试2或3 ..
PS:
在我发现提到这个问题的任何地方,它被告知将中间CA证书与您的服务器证书结合起来.到了一个文件(正如@ vikas-nalwar所建议你做的那样)按照验证顺序(但我不确定订单是否重要)并粗略地说是设置ssl_verify_depth
为捆绑中的证书数量.