【问题标题】:"openssl verify" gives OK for bad certificate chain“openssl verify”对坏证书链给出 OK
【发布时间】:2014-06-11 19:38:37
【问题描述】:

有一个自签名的根 CA 证书 rootcert.pem,具有以下 V3 扩展:

X509v3 extensions:
    X509v3 Key Usage: 
       Certificate Sign
    X509v3 Basic Constraints: 
       CA:TRUE

rootcert.pem 的 CA 标志设置为 true,并且其密钥使用允许证书签名。 rootcert.pem 使用以下 V3 扩展对证书 foocert.pem 进行签名:

X509v3 extensions:
    X509v3 Basic Constraints: 
        CA:FALSE
    X509v3 Key Usage: 
        Digital Signature, Non Repudiation, Key Encipherment

foocert.pem 的 CA 标志设置为 false,并且其密钥使用不允许证书签名。但是可以说,foocert.pem 签署了 rougecert.pem。

形成foocert & roguecert的证书链:

cat foocert.pem roguecert.pem > roguechain.pem

使用 openssl verify 进行验证。验证成功:

$ openssl verify  -CAfile rootcert.pem roguechain.pem 
roguechain.pem: OK

使用 x509_strict 验证,仍然成功:

$ openssl verify -x509_strict -CAfile rootcert.pem badchain.pem 
badchain.pem: OK

假设系统只信任根 CA 证书。对等方提供其证书链,其中一个中间证书不应该是 CA(CA 设置为 false 并且密钥使用不允许证书签名),openssl 仍然标记该链是好的吗?

如何让 openssl 不信任这样的链?

【问题讨论】:

  • badchain.pem 来自哪里?是不是又应该是rougechain.pem?
  • 这可能是 openssl 中的一个错误,已在 1.1.0 版中修复:github.com/openssl/openssl/issues/5236 虽然在那个 GitHub 问题中看起来他们正在使用openssl s_client,但在@paulus 下面说他正在使用 openssl s_client 并且 没有 看到问题。所以我不知道发生了什么。

标签: openssl certificate verification


【解决方案1】:

(编辑:刚刚注意到我的答案是 Chris Lesner 的更长更详细的版本,我会投票给他,但我还没有代表在这里:>)

我认为你在这里仍然走错了路。我认为实际的问题是“验证”不会以这种方式验证单个文件中的链。

“验证”的最后一个参数被列为 [certificates] 并记录如下:

   certificates
       One or more certificates to verify. If no certificates are given, verify will attempt to read a
       certificate from standard input. Certificates must be in PEM format.

您可以传递多个文件 - 但每个文件都将作为单个叶证书进行验证,独立于其他文件。它不是绝对明确的,但它暗示(我可以告诉你,事实就是如此;有关详细信息,请参阅下面的代码位置)将从每个文件中读取 one 证书。如果你给它一个包含多个连接在一起的证书的文件,它实际上只会将文件中的 first 证书验证为叶证书,而完全忽略其他证书。

因此,在您的示例中,您实际所做的是将foocert.pem 验证为叶证书,因为它是您的roguechain.pem 中的第一个证书。 foocert.pem 作为叶证书有效,即使是 -purpose sslserver。 man x509 部分 CERTIFICATE EXTENSIONS 记录了“SSL 服务器”用途的条件:

   SSL Server
       The extended key usage extension must be absent or include the "web server authentication" and/or one
       of the SGC OIDs.  keyUsage must be absent or it must have the digitalSignature, the keyEncipherment set
       or both bits set.  Netscape certificate type must be absent or have the SSL server bit set.

您可以看到您的foocert.pem 没有扩展密钥用法,也不是Netscape 类型的证书;它确实有密钥用法,同时设置了数字签名和密钥加密位。因此,它通过了测试。

要进行您真正想做的检查,您必须这样做:

openssl verify -CAfile rootcert.pem -untrusted foocert.pem -purpose sslserver roguecert.pem

使用您在最初问题中提供的文件名。基本上,将根 CA 证书提供为 -CAfile、-CApath 或 -trusted,将中间 CA 证书提供为 -untrusted,并将叶证书作为最终参数进行验证是一个合理的简化(s)。

请注意,作为-untrusted 传递的文件可以包含连接在一起的多个证书:

   -untrusted file
       A file of untrusted certificates. The file should contain multiple certificates in PEM format
       concatenated together.

如果您想按照代码确认这一点,每个叶子证书文件由load_cert() 加载到apps/apps.c。该函数的返回是X509; X509 对象是单个证书。与同一文件中的 load_certs() 进行比较,后者返回 STACK_OF(X509) - 这是 OpenSSL 通常用于原始证书链的内容。

【讨论】:

  • 这似乎是正确的答案。但是,我遇到了更多问题。如果签署证书,keyCertSign 扩展必须打开。在这种情况下,RFC(请参阅tools.ietf.org/html/rfc5280#section-4.2.1.9)要求指定 basicConstraint 扩展,并且必须将其标记为关键。除非我指定 -x509_strict,否则我使用 keyCertSign 生成但没有 CA:true 的 basicConstraint 的链给出 OK。即使使用 -x509_strict,我生成的带有两个约束但非关键 basicConstraint 的链仍然响应 OK。
  • 其实一分钟后我会进一步测试,因为我的openssl版本从2018年3月开始是1.0.2o,看起来这方面发生了一些变化。
【解决方案2】:

我怀疑 openssl 只查看它在 roguecert.pem 文件中找到的第一件事,这是 foocert.pem 的有效内容。 (为了向自己证明,将 args 换成 cat。)要验证证书链,请提供链中不受信任的证书,使用:

   -untrusted file
       A file of untrusted certificates. The file should contain multiple 
       certificates in PEM format concatenated together.

【讨论】:

    【解决方案3】:

    原来的答案被证明是错误的,所以这里是另一个:)

    看起来 openssl verify 只进行证书链验证,它不检查 any 标志(即使设置了正确的用途)。但是,当您实际进行 ssl/tls 连接时,该库会检查标志:

    $ openssl s_client -verify 100 -CAfile cacert.pem -connect servername:443
    verify depth is 100
    CONNECTED(00000003)
    depth=1 /CN=middle
    verify error:num=24:invalid CA certificate
    verify return:1
    depth=1 /CN=middle
    verify error:num=26:unsupported certificate purpose
    verify return:1
    depth=2 /CN=root
    verify return:1
    depth=1 /CN=middle
    verify return:1
    depth=0 /CN=leaf
    verify return:1
    ---
    Certificate chain
    0 s:/CN=leaf
      i:/CN=middle
    1 s:/CN=middle
      i:/CN=root
    ---
    ...
    SSL-Session:
        Protocol  : TLSv1
        ...
        Verify return code: 26 (unsupported certificate purpose)
    

    【讨论】:

    • 我尝试了命令“openssl verify - purpose sslserver”,它仍然可以。问题是 roguecert.pem 是一个有效的服务器证书(密钥用法:数字签名,密钥加密),但它由不是 CA 的中间证书签名。 openssl 验证仍然信任该链。
    • 好的,完全复制了这件事,现在我和你一样感到羞耻。虽然做了一些调查。看起来 openssl verify 根本不检查这些标志(尽管文档说确实如此)。但是当您实际使用 ssl/tls 流时,它会检查标志。将用技术输出更新我的答案。
    猜你喜欢
    • 2018-01-25
    • 1970-01-01
    • 2021-05-12
    • 2018-08-29
    • 2018-02-27
    • 2020-06-26
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多