问题描述
我有一个简单的链设置程序,在这种情况下可以成功验证:
I have a simple chain setup and can successfully verify in this case:
$ openssl version
OpenSSL 1.0.2m 2 Nov 2017
$ openssl verify -CAfile chain.pem cert.pem
cert.pem: OK
但是在这些情况下我得到了错误:
However I get errors in these cases:
$ openssl verify -CAfile ca-cert.pem cert.pem
cert.pem: C = US...
error 2 at 1 depth lookup:unable to get issuer certificate
尤其是无法获得颁发者证书.
也可以在这里获取
$ openssl verify chain.pem
chain.pem: C = US...
error 20 at 0 depth lookup:unable to get local issuer certificate
$ openssl verify cert.pem
cert.pem: C...
error 20 at 0 depth lookup:unable to get local issuer certificate
最后,当我将密钥传递给HTTPS服务器时,我在Node.js中得到它:
Finally, I get it in Node.js when I pass the keys to an HTTPS server:
events.js:193
throw er; // Unhandled 'error' event
^
Error: unable to get local issuer certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1036:34)
at emitNone (events.js:115:13)
at TLSSocket.emit (events.js:218:7)
at TLSSocket._finishInit (_tls_wrap.js:637:8)
我尝试通过{ key, cert, ca }
传递它,但仍然是相同的错误.
I tried passing it with { key, cert, ca }
, but still same error.
想知道如何进行调试或如何使HTTPS服务器运行.
Wondering how to go about debugging this or what the fix is to get an HTTPS server running.
如果使用pfx
文件,则会得到以下信息:
If I use a pfx
file I get the following:
events.js:193
throw er; // Unhandled 'error' event
^
Error: self signed certificate in certificate chain
at TLSSocket.onConnectSecure (_tls_wrap.js:1036:34)
at emitNone (events.js:115:13)
at TLSSocket.emit (events.js:218:7)
at TLSSocket._finishInit (_tls_wrap.js:637:8)
如果我仅将cert.pem保留在cert文件中,并将ca
属性设置为ca-cert.pem,它将给出:
If I leave only the cert.pem in the cert file, and make the ca
attribute be the ca-cert.pem, it gives:
Error: unable to verify the first certificate
at TLSSocket.<anonymous> (_tls_wrap.js:1108:38)
at emitNone (events.js:105:13)
at TLSSocket.emit (events.js:207:7)
at TLSSocket._finishInit (_tls_wrap.js:638:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:468:38)
不确定该怎么做.
此处,他们说:
不确定这是什么意思.
- https://wiki.zimbra.com/wiki/Fix_depth_lookup:unable_to_get_issuer_certificate
更新
更多帮助:
- https://www.openssl.org/docs/faq.html#USER6
- https://www.openssl.org/docs/faq.html#USER6
但是仍然没有太大帮助.
But still doesn't help very much.
看起来Node.js使用的是1.0.2l而不是1.0.2m,但这似乎没什么大碍.
Looks like Node.js is using a 1.0.2l instead of 1.0.2m but doesn't seem like a big deal.
$ node -pe process.versions | grep openssl
openssl: '1.0.2l'
更新2
很奇怪,当我从Node.js发出请求时得到了这个消息:
Weird, I get this when I make a request from Node.js:
Uncaught Error: unable to verify the first certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1036:34)
at TLSSocket._finishInit (_tls_wrap.js:637:8)
但是,当我使用浏览器时,没有看到请谨慎操作"页面,并且可以在Node.js中成功记录请求.也许有所帮助.请帮忙:D
But when I go to the browser, I don't see the "Proceed with caution" page, and can successfully log a request in Node.js. Maybe that helps somewhat. Please help :D
推荐答案
(此答案是从X509_verify_cert
在crypto/x509/x509_vfy.c:204
的openssl-1.0.2m中提取的)
(This answer extracted from X509_verify_cert
at crypto/x509/x509_vfy.c:204
, in openssl-1.0.2m)
OpenSSL verify
应用程序通过以下方式验证证书:它以目标证书开始构建证书链,并跟踪颁发者链,首先搜索与目标证书一起提供的所有不受信任的证书.在找不到不受信任的颁发者证书后,OpenSSL切换到受信任的证书存储,并继续构建链.该过程在以下时间停止
The OpenSSL verify
application verifies a certificate in the following way: It builds the certificate chain starting with the target certificate, and tracing the issuer chain, searching any untrusted certificates supplied along with the target cert first. Upon failing to find an untrusted issuer cert, OpenSSL switches to the trusted certificate store and continues building the chain. This process stops when
- 在受信任的商店中找不到发行者.
- 遇到自签名证书.
- 遇到最大验证深度.
这时,我们有一条链可能会过早终止(如果找不到发行人,或者超出了验证深度).
At this point we have a chain that may end prematurely (if we failed to find an issuer, or if we exceeded the verify depth).
然后,OpenSSL扫描链上的每个受信任证书,以查找指定受信任证书用途的SSLv3扩展.如果受信任的证书具有用于验证操作的目的"的正确信任"属性(或具有anyExtendedKeyUsage
属性),则该链是受信任的. (绕过信任属性的浪潮,那部分代码很难阅读.)
OpenSSL then scans over each trusted certificate on the chain looking for SSLv3 extensions that specify the purpose of the trusted certificate. If the trusted certificate has the right "trust" attributes for the "purpose" of the verification operation (or has the anyExtendedKeyUsage
attribute) the chain is trusted. (Forgive the hand-wave on trust attributes, that part of the code was difficult to read.)
所以让我们测试一下.首先,让我们再现一下OP的错误情况:
So lets test it out. First, let's repro the OP's error cases:
#
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
收益
[... 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
现在,让我们使用openssl x509
的-addtrust
选项来确保我们在中间CA上具有可接受的信任属性之一(将其称为IntermediateCAWithTrust
;我们将使用它来签署AnotherUserCert
. ):
Now, lets use the -addtrust
option of openssl x509
to make sure we have one of the acceptable trust attributes on the intermediate CA (call this one IntermediateCAWithTrust
; we'll use it to sign 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.造成这种差异的关键在于,链中的任何一个受信任证书都具有用于验证操作的适当信任属性.
Hey look! we just successfully verified AnotherUserCert via the IntermediateCAWithTrust, even though we didn't supply the whole chain. The key to this difference is that any one of the trusted certificates in the chain had an appropriate trust attribute for the verify operation.
再仔细一点(via openssl x509 -in ca-crt.pem -noout -text
),我们的CA证书已经
Looking a little closer (via openssl x509 -in ca-crt.pem -noout -text
), our CA certificate has
X509v3 Basic Constraints:
CA:TRUE
我可以想象OpenSSL将
视为一般的可以出于任何目的进行验证"扩展.新的IntermediateCAWithTrust
没有X509v3 Basic Constraints
,但是有
which I would imagine OpenSSL treats as a general "may verify for any purpose" extension. The new IntermediateCAWithTrust
does not have X509v3 Basic Constraints
, but instead has
Trusted Uses:
Any Extended Key Usage
No Rejected Uses.
有关-addtrust
选项中的更多信息以及可以添加的信任属性的类型,请参见 https://www.openssl.org/docs/manmaster/man1/x509.html#TRUST_SETTINGS
For more info in the -addtrust
option, and the types of trust attributes that can be added, see https://www.openssl.org/docs/manmaster/man1/x509.html#TRUST_SETTINGS
该页面底部附近是上述讨论的简要摘要:
Near the bottom of that page is a concise summary of the preceding discussion:
如果缺少basicConstraints扩展名,则证书为 被认为是可能的CA"的其他扩展名会被检查 根据证书的预期用途.发出警告 在这种情况下,因为该证书实际上不应被视为 CA:但是可以允许CA来处理某些损坏的CA 软件.
If the basicConstraints extension is absent then the certificate is considered to be a "possible CA" other extensions are checked according to the intended use of the certificate. A warning is given in this case because the certificate should really not be regarded as a CA: however it is allowed to be a CA to work around some broken software.
因此,简而言之,请确保您的中间CA是正确的CA(在其X509v3 Basic Constraints
中).这似乎是一个很好的教程(它明确地将中间CA生成为CA): https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html
So, in short, make sure your intermediate CAs are properly CAs (in their X509v3 Basic Constraints
). This seems an excellent tutorial (and it explicitly generates the intermediate CA as a CA): https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html
作为备份计划,您可以始终提供整个链,也可以使用-addtrust
hack来制作中间CA.
As a backup plan, you can always supply the whole chain, or you can make your intermediate CAs with the -addtrust
hack.
这篇关于OpenSSL错误-无法获取本地发行者证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!