&引用;openssl验证";为坏证书链提供OK

&引用;openssl验证";为坏证书链提供OK,openssl,certificate,verification,Openssl,Certificate,Verification,有一个自签名根CA证书rootcert.pem,具有以下V3扩展: X509v3 extensions: X509v3 Key Usage: Certificate Sign X509v3 Basic Constraints: CA:TRUE X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digit

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

X509v3 extensions:
    X509v3 Key Usage: 
       Certificate Sign
    X509v3 Basic Constraints: 
       CA:TRUE
X509v3 extensions:
    X509v3 Basic Constraints: 
        CA:FALSE
    X509v3 Key Usage: 
        Digital Signature, Non Repudiation, Key Encipherment
rootcert.pem的CA标志设置为true&其密钥使用允许证书签名。rootcert.pem使用以下V3扩展名签署证书foocert.pem:

X509v3 extensions:
    X509v3 Key Usage: 
       Certificate Sign
    X509v3 Basic Constraints: 
       CA:TRUE
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验证。验证成功:

$ openssl verify  -CAfile rootcert.pem roguechain.pem 
roguechain.pem: OK
$ openssl verify -x509_strict -CAfile rootcert.pem badchain.pem 
badchain.pem: OK
使用x509_strict进行验证,但仍然成功:

$ openssl verify  -CAfile rootcert.pem roguechain.pem 
roguechain.pem: OK
$ openssl verify -x509_strict -CAfile rootcert.pem badchain.pem 
badchain.pem: OK
假设系统只信任根CA证书。对等方给出了它的证书链,其中一个中间证书不应该是CA(CA设置为false&key usage不允许证书签名),但openssl仍然标记该链是好的


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

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

看起来openssl verify只进行证书链验证,不检查任何标志(即使设置了正确的用途)。但是,当您实际进行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只关注它在roguecert.pem文件中找到的第一个内容,即foocert.pem的有效内容。(要向自己证明这一点,请将args交换到cat。)要验证证书链,请使用以下方法提供链中不受信任的证书:

   -untrusted file
       A file of untrusted certificates. The file should contain multiple 
       certificates in PEM format concatenated together.
(编辑:刚刚注意到我的答案是克里斯·莱斯纳的一个更长更详细的版本,我会投票支持他,但我这里还没有代表:>)

我想你还是走错了方向。我认为实际的问题是“验证”并没有以这种方式验证单个文件中的链

“验证”的最后一个参数列为
[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.
您可以传递多个文件,但每个文件都将作为单个叶证书进行验证,独立于其他文件。它不是绝对明确的,但它意味着(我可以告诉您,事实上是这样的;详细信息请参见下面的代码位置)将从每个文件中读取一个证书。如果您向它提供一个包含多个连接在一起的证书的文件,它实际上只会验证文件中的第一个证书作为叶证书,而完全忽略其他证书

因此,在您的示例中,您实际做的是将
foocert.pem
验证为叶证书,因为它是
roguechain.pem
中的第一个证书
foocert.pem
作为叶证书有效,即使使用
专用sslserver
<代码>man x509部分
证书扩展
记录了“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验证-CAfile rootcert.pem-untrusted foocert.pem-purpose sslserver roguecert.pem

使用您在初始问题中给出的文件名。基本上,将根CA证书设置为
-CAfile
-CApath
-trusted
,将中间CA证书设置为
-untrusted
,并将叶证书作为最终参数进行验证,这是一种合理的简化

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

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

如果要按照代码进行确认,则每个叶证书文件都由
apps/apps.c
中的
load\u cert()
加载。该函数的返回值为
X509
<代码>X509对象是单个证书。与同一文件中的
load_certs()
相比,该文件返回
STACK_OF(X509)
-这是OpenSSL通常用于原始证书链的内容。

我尝试了命令“OpenSSL验证-purpose sslserver”&它仍然给出了OK。问题是roguecert.pem是一个有效的服务器证书(密钥用法:数字签名,密钥加密),但它是由一个不是CA的中间证书签署的。openssl验证仍然信任该链。好吧,完全复制了这个东西,现在我和你一样感到羞愧。不过我做了一些调查。看起来openssl verify根本没有检查这些标志(尽管文档说有)。但当您实际使用ssl/tls流时,它会检查标志。将用技术输出更新我的答案。
badchain.pem
来自哪里?这可能是openssl中的一个缺陷,在1.1.0版中得到了修复:尽管在GitHub问题中,看起来他们使用的是
openssl s_客户端
,但是@paulus在下面说他使用的是
openssl s_客户端
,并且没有看到问题。所以我不知道发生了什么。这似乎是正确的答案。然而,我遇到了更多的问题。如果对证书进行签名,则keyCertSign扩展必须处于启用状态。在这种情况下,RFC(请参阅)要求指定basicConstraint扩展,并且必须将其标记为critical。我使用keyCertSign-on生成的链,但CA:true没有基本约束,除非我指定-x509\u-strict,否则会给出OK。我用这两个约束生成了一个链,但一个非关键的basicConstraint仍然响应OK,即使是-x509_strict。事实上,我会在一分钟后进行进一步测试,因为我的openssl版本从2018年3月起为1.0.2o,看起来在这方面有一些变化。