Nginx 怎么使用不被信任的 CA 验证客户端证书? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xudzhang
V2EX    NGINX

Nginx 怎么使用不被信任的 CA 验证客户端证书?

  •  
  •   xudzhang 2018-08-01 09:59:01 +08:00 6739 次点击
    这是一个创建于 2631 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下面的配置里,ca.crt 是一个 untrusted 的 CA,当用 ca.crt 来验证客户端的证书时,Nginx 的 error log 里提示 unable to verify the first certificate,错误码是 21。但其实我用 openssl 命令行用 ca.crt 校验客户端证书是 OK 的。哪位高人指点下怎么解决?

    server { listen 443 ssl; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; server_name www.example.com; ssl_certificate server.crt; ssl_certificate_key server.key; ssl_verify_client on; ssl_client_certificate ca.crt; } 
    26 条回复    2018-08-02 13:39:01 +08:00
    virusdefender
        1
    virusdefender  
       2018-08-01 10:05:55 +08:00
    client_certificate 不需要是可信 ca,你的可能是其他错误导致的,比如客户端证书导出的不太对?
    xudzhang
        2
    xudzhang  
    OP
       2018-08-01 10:08:44 +08:00
    @virusdefender Nginx 的官方文档这样说的:"ssl_client_certificate specifies a file with trusted CA certificates in the PEM format used to verify",这个的意思是不是说我的 ca.crt 必须是 trusted ?
    virusdefender
        3
    virusdefender  
       2018-08-01 10:15:06 +08:00   1
    @xudzhang #2 我一直是用的自签名的 ca,然后导出的客户端证书啊,正常用,稍等我看下导出证书的脚本。
    virusdefender
        4
    virusdefender  
       2018-08-01 10:27:25 +08:00
    你用的是什么版本的 nginx 啊,我看新版好像行为不太一样了

    ssl_verify_client on | off | optional | optional_no_ca;

    The optional_no_ca parameter (1.3.8, 1.2.5) requests the client certificate but does not require it to be signed by a trusted CA certificate. This is intended for the use in cases when a service that is external to nginx performs the actual certificate verification. The contents of the certificate is accessible through the $ssl_client_cert variable.
    owt5008137
        5
    owt5008137  
       2018-08-01 10:29:34 +08:00 via Android   1
    @virusdefender 我以前也自己签,写了个写脚本改 openssl.cnf 文件里的配置就成。
    https://github.com/owent-utils/bash-shell/tree/master/Others/x509_ssl_cert

    但是现在有 let's encrypt
    xudzhang
        6
    xudzhang  
    OP
       2018-08-01 10:32:01 +08:00
    @virusdefender 这个 optional_no_ca 我昨天试了一下,好像不管用,看官方文档的意思,这个选项启用的时候会请求客户端证书但是不要求客户端证书是 trusted 的,但我这个情况其实是我自己的 ca.crt 是 untrusted,现在我就是没找到路子怎么让 Nginx 或者说让我的 Linux server 信任我的这个 ca.crt ,不知道我这么理解对不对?
    xudzhang
        7
    xudzhang  
    OP
       2018-08-01 10:32:45 +08:00
    @owt5008137 大佬,我的 openssl 好像是用 yum install 安装的,能不能指教一下你说的这个 cnf 配置在哪里?我找了一下没找到~
    Zakun
        8
    Zakun  
       2018-08-01 10:35:39 +08:00
    virusdefender
        9
    virusdefender  
       2018-08-01 10:35:40 +08:00
    不过我试了下,我的 nginx version: nginx/1.13.9 还是可以工作的

    ```
    openssl genrsa -out ca.key 4096
    openssl req -new -x509 -nodes -sha256 -subj "$subj/CN=Test Root CA" -days 3650 -key ca.key -out ca.crt

    openssl genrsa -out client.key 4096
    openssl req -new -key client.key -out client.csr -subj "/CN=Cert Test"
    openssl x509 -req -days 3650 -extfile <(printf "keyUsage=digitalSignature") -in client.csr -CA client_ca.crt -CAkey client_ca.key -set_serial 1234 -out client.crt
    openssl pkcs12 -export -in client.crt -inkey client.key -name "Admin Cert" -out client.p12 -password pass:123456
    ```

    ```
    ssl_client_certificate /ssl/client_ca.crt;
    ssl_verify_client on;
    ```
    SirLostWhite
        10
    SirLostWhite  
       2018-08-01 10:35:50 +08:00
    可以 certbot 自动配置 letsencrypt 证书
    全自动的
    xudzhang
        11
    xudzhang  
    OP
       2018-08-01 10:39:07 +08:00
    @Zakun 这个字段之前试过,我加了 ssl_trusted_certificate ca.crt 的配置,并没什么用啊……
    xudzhang
        12
    xudzhang  
    OP
       2018-08-01 10:41:39 +08:00
    @virusdefender 理解一下,在你这个例子里,你用 ca 签发了 client_ca,那为什么你的 ssl_client_certificate 里配的是 client_ca.crt 而不是 ca.crt ?
    msg7086
        13
    msg7086  
       2018-08-01 10:50:06 +08:00
    ca -> client_ca -> client
    如果用 ca.crt 的话,就是 2 层验证,也就是 ssl_verify_depth 2; 。
    Hardrain
        14
    Hardrain  
       2018-08-01 10:53:10 +08:00   1
    用于 SSL 双向认证的 CA 证书不需要也不应该是一个商业 CA。
    Hardrain
        15
    Hardrain  
       2018-08-01 11:09:26 +08:00   1
    ssl_client_certificate file;
    ssl_verify_client on | off | optional | optional_no_ca;
    ssl_verify_depth number;

    你只需要关注以上三行
    其中第三行的解释

    (用于客户端验证的,下同)根 CA ------第 0 层
    |
    |_____中间 CA(a)-------第 1 层
    | |
    | |________用户 A 的证书----第 2 层
    | |________用户 B 的证书----第 2 层
    |_____用户 C 的证书----第 1 层

    如果你把 depth 设为 1,只有 C 的证书会被信任;如果设成 2,所有三个用户的证书都被信任。
    如果设成 0,则需要将根 CA 换成(唯一的)被信任的用户证书,且只有这个用户被信任。

    一般地,如果证书的拓扑结构不是很复杂(压根没有中间 CA),设为 1 即可。
    Hardrain
        16
    Hardrain  
       2018-08-01 11:10:23 +08:00
    xudzhang
        17
    xudzhang  
    OP
       2018-08-01 11:17:52 +08:00
    @Hardrain 感谢!根据你画的图,其实我的情况是这样的,我的 ca.crt 是第 0 层,然后 client 那边的证书都是 ca.crt 签发的,那其实理论上我只要把 ssl_verify_depth 设置成 1 应该就能 work。但实际上,Nginx 的 error log 里提示 client SSL certificate verify error: (7:certificate signature failure),相关的 verify 的 log 如下,大佬能不能帮忙看看什么情况?

    2018/08/01 02:52:56 [debug] 6024#0: *9450 verify:1, error:0, depth:1, subject:"/C=CN/ST=Fujian/L=Xiamen/O=Yealink Network Technology Co.,Ltd./OU=yealink.com/CN=Yealink Equipment Issuing CA/[email protected]", issuer:"/C=CN/ST=Fujian/L=Xiamen/O=Yealink Network Technology Co.,Ltd./OU=yealink.com/CN=Yealink Equipment Issuing CA/[email protected]"

    2018/08/01 02:52:56 [debug] 6024#0: *9450 verify:0, error:7, depth:0, subject:"/C=CN/ST=Fujian/L=Xiamen/O=Yealink Network Technology Co.,Ltd./OU=Yealink Equipment/CN=$mac/[email protected]", issuer:"/C=CN/ST=Fujian/L=Xiamen/O=Yealink Network Technology Co.,Ltd./OU=yealink.com/CN=Yealink Equipment Issuing CA/[email protected]"

    2018/08/01 02:52:56 [debug] 6024#0: *9450 verify:1, error:7, depth:0, subject:"/C=CN/ST=Fujian/L=Xiamen/O=Yealink Network Technology Co.,Ltd./OU=Yealink Equipment/CN=$mac/[email protected]", issuer:"/C=CN/ST=Fujian/L=Xiamen/O=Yealink Network Technology Co.,Ltd./OU=yealink.com/CN=Yealink Equipment Issuing CA/[email protected]"
    virusdefender
        18
    virusdefender  
       2018-08-01 11:53:19 +08:00
    我开始文件有手动重命名的,重发一下

    openssl genrsa -out ca.key 4096
    openssl req -new -x509 -nodes -sha256 -subj "$subj/CN=Test Root CA" -days 3650 -key ca.key -out ca.crt

    openssl genrsa -out client.key 4096
    openssl req -new -key client.key -out client.csr -subj "/CN=Cert Test"
    openssl x509 -req -days 3650 -extfile <(printf "keyUsage=digitalSignature") -in client.csr -CA ca.crt -CAkey ca.key -set_serial 1234 -out client.crt
    openssl pkcs12 -export -in client.crt -inkey client.key -name "Admin Cert" -out client.p12 -password pass:123456


    ssl_client_certificate /ssl/ca.crt;
    ssl_verify_client on;

    其实不存在 client_ca.crt 的
    msg7086
        19
    msg7086  
       2018-08-01 13:24:50 +08:00
    yum 安装的 openssl ?
    certificate signature failure ?

    我先猜个:sha256 你的 openssl 太老了不支持。
    你是啥版本的 openssl ?啥版本的发行版?啥版本的 nginx ?
    xudzhang
        20
    xudzhang  
    OP
       2018-08-01 13:58:31 +08:00
    @msg7086 Openssl 版本是 1.0.2k-fips,Nginx 版本是 1.13.8 ……
    msg7086
        21
    msg7086  
       2018-08-01 16:38:34 +08:00
    @xudzhang 你看看 Nginx 编译用的是哪个 OpenSSL,是系统自带的还是静态链接了别的版本?
    Hardrain
        22
    Hardrain  
       2018-08-01 21:46:36 +08:00
    @xudzhang 很抱歉,我恐怕很难透过这些信息提供帮助

    我检索了 nginx+{错误信息中的数字*}(其余的信息似乎都是 x.509 证书的一些字段),但无法找到任何有帮助的结果。
    客户端有什么错误出现?
    你可以尝试从客户端 /服务器抓一下包吗?

    *:debug 6024|9450|error:7 等
    Hardrain
        23
    Hardrain  
       2018-08-01 21:53:16 +08:00   1
    @xudzhang
    检索 openssl 和 error 7 得到一结果,或有帮助:
    https://serverfault.com/questions/653144/openssl-verify-error-7-at-1-depth-lookupcertificate-signature-failure
    从这篇问答来看似乎是用户证书签名问题。

    使用`openssl x509 -in {path_to_client_cert} -noout -text`看一下客户端证书所用签名算法。
    另外,用`openssl verify -CAfile {path_to_client_verify_ca} {path_to_client_cert}`测试下签发的证书有无问题。
    xudzhang
        24
    xudzhang  
    OP
       2018-08-02 10:26:18 +08:00
    @Hardrain 找到 root cause 了,是 openssl 版本的问题,client 使用的签名算法在高版本中的 openssl 已经废弃……
    xierch
        25
    xierch  
       2018-08-02 12:09:03 +08:00
    > ssl_client_certificate specifies a file with trusted CA certificates in the PEM format used to verify.

    他其实是说,你需要指定一个证书作为 trusted CA …
    然后这个 trusted CA 用 ssl_client_certificate 来指定…
    owt5008137
        26
    owt5008137  
       2018-08-02 13:39:01 +08:00 via Android
    @xudzhang 我贴的地址里有两个文件。一个是执行脚本的.sh 另一个就是 openssl.cnf
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     919 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 20:53 PVG 04:53 LAX 13:53 JFK 16:53
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86