(此答案摘自X509_verify_cert
at crypto/x509/x509_vfy.c:204
,在 openssl-1.0.2m 中)
OpenSSLverify
应用程序按以下方式验证证书:它从目标证书开始构建证书链,并跟踪颁发者链,首先搜索与目标证书一起提供的任何不受信任的证书。在找不到不受信任的颁发者证书时,OpenSSL 会切换到受信任的证书存储并继续构建链。该过程停止时
- 在可信存储中找不到发行者。
- 遇到自签名证书。
- 遇到最大验证深度。
此时,我们的链可能会提前结束(如果我们未能找到发行者,或者如果我们超出了验证深度)。
然后,OpenSSL 扫描链上的每个受信任证书,查找指定受信任证书用途的 SSLv3 扩展。如果可信证书具有用于验证操作“目的”的正确“信任”属性(或者具有anyExtendedKeyUsage
属性)该链是可信的。 (请原谅对信任属性的挥手,这部分代码很难阅读。)
那么我们来测试一下。首先,让我们重现OP的错误案例:
#
echo "Making Root CA..."
openssl req -newkey rsa:4096 -nodes -keyout ca-key.pem -sha384 -x509 -days 365 -out ca-crt.pem -subj /C=XX/ST=YY/O=RootCA
echo "Making Intermediate CA..."
openssl req -newkey rsa:3072 -nodes -keyout int-key.pem -new -sha384 -out int-csr.pem -subj /C=XX/ST=YY/O=IntermediateCA
openssl x509 -req -days 360 -in int-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out int-crt.pem
echo "Making User Cert..."
openssl req -newkey rsa:2048 -nodes -keyout usr-key.pem -new -sha256 -out usr-csr.pem -subj /C=XX/ST=YY/O=LockCmpXchg8b
openssl x509 -req -days 360 -in usr-csr.pem -CA int-crt.pem -CAkey int-key.pem -CAcreateserial -out usr-crt.pem
echo ""
echo "Making Chain..."
cat ca-crt.pem int-crt.pem > chain.pem
echo ""
echo "Verfying UserCert via RootCA..."
openssl verify -CAfile ca-crt.pem usr-crt.pem
echo ""
echo "Verfying UserCert via IntermediateCA..."
openssl verify -CAfile int-crt.pem usr-crt.pem
echo ""
echo "Verfying UserCert via chain..."
openssl verify -CAfile chain.pem usr-crt.pem
yields
[... Skipping OpenSSL KeyGen / CertGen verbosity ...]
Making Chain...
Verfying UserCert via RootCA...
usr-crt.pem: C = XX, ST = YY, O = LockCmpXchg8b
error 20 at 0 depth lookup:unable to get local issuer certificate
Verfying UserCert via IntermediateCA...
usr-crt.pem: C = XX, ST = YY, O = IntermediateCA
error 2 at 1 depth lookup:unable to get issuer certificate
Verfying UserCert via chain...
usr-crt.pem: OK
现在,让我们使用-addtrust
的选项openssl x509
确保我们在中间 CA 上拥有可接受的信任属性之一(将此称为IntermediateCAWithTrust
;我们将用它来签名AnotherUserCert
.):
echo ""
echo "Alternate Intermedate CA (using -addtrust anyExtendedKeyUsage)"
echo ""
echo "Making IntermediateCAWithTrust..."
openssl req -newkey rsa:3072 -nodes -keyout int-key2.pem -new -sha384 -out int-csr2.pem -subj /C=XX/ST=YY/O=IntermediateCAWithTrust
openssl x509 -req -days 360 -in int-csr2.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out int-crt2.pem -addtrust anyExtendedKeyUsage
echo "Making AnotherUser Cert..."
openssl req -newkey rsa:2048 -nodes -keyout usr-key2.pem -new -sha256 -out usr-csr2.pem -subj /C=XX/ST=YY/O=LockCmpXchg8b_2
openssl x509 -req -days 360 -in usr-csr2.pem -CA int-crt2.pem -CAkey int-key2.pem -CAcreateserial -out usr-crt2.pem
echo ""
echo "Verfying AnotherUserCert via IntermediateCAWithTrust..."
openssl verify -CAfile int-crt2.pem usr-crt2.pem
这产生
Alternate Intermedate CA (using -addtrust anyExtendedKeyUsage)
Making IntermediateCAWithTrust...
[... Snip more OpenSSL generation output ...]
Making AnotherUser Cert...
[... Snip more OpenSSL generation output ...]
Verfying AnotherUserCert via IntermediateCAWithTrust...
usr-crt2.pem: OK
你看!我们刚刚通过 IntermediateCAWithTrust 成功验证了 AnotherUserCert,即使我们没有提供整个链。这种差异的关键在于链中的任何一个受信任的证书都具有适当的信任属性用于验证操作。
靠近一点看(via openssl x509 -in ca-crt.pem -noout -text
),我们的CA证书有
X509v3 Basic Constraints:
CA:TRUE
我认为 OpenSSL 将其视为一般的“可以出于任何目的进行验证”扩展。新的IntermediateCAWithTrust
不具有X509v3 Basic Constraints
,而是有
Trusted Uses:
Any Extended Key Usage
No Rejected Uses.
欲了解更多信息,请参阅-addtrust
选项以及可以添加的信任属性类型,请参见https://www.openssl.org/docs/manmaster/man1/x509.html#TRUST_SETTINGS https://www.openssl.org/docs/manmaster/man1/x509.html#TRUST_SETTINGS
该页面底部附近是前面讨论的简明摘要:
basicConstraints 扩展 CA 标志用于确定是否
该证书可以用作 CA。如果 CA 标志为真,那么它是
CA,如果 CA 标志为 false,则它不是 CA。所有 CA 都应该有
CA 标志设置为 true。
如果 basicConstraints 扩展不存在,则证书为
被认为是“可能的 CA”,检查其他扩展名
根据证书的预期用途。发出警告
在这种情况下,因为证书实际上不应该被视为
CA:但是允许使用 CA 来解决一些损坏的问题
软件。
因此,简而言之,请确保您的中间 CA 是正确的 CA(在其X509v3 Basic Constraints
)。这似乎是一个很棒的教程(它显式生成中间 CA 作为 CA):https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html
作为备份计划,您始终可以提供整个链,或者您可以使用-addtrust
hack.