OpenSSL 错误 - 无法获取本地颁发者证书
OpenSSL error - unable to get local issuer certificate
我有一个简单的链设置,在这种情况下可以成功验证:
$ openssl version
OpenSSL 1.0.2m 2 Nov 2017
$ openssl verify -CAfile chain.pem cert.pem
cert.pem: OK
但是在这些情况下我会出错:
$ 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 中得到了它:
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 }
传递它,但仍然是同样的错误。
想知道如何进行调试或获取 HTTPS 服务器的修复方法 运行。
如果我使用 pfx
文件,我会得到以下信息:
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,并使 ca
属性成为 ca-cert.pem,它会给出:
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)
不知道该怎么做。
他们说:
OpenSSL is unable to find a local certificate for the issuer (or the issuer of the first certificate in the chain received from the web server during the TLS handshake) with which to verify the signature(s).
不确定那是什么意思。
This error means the certificate path or chain is broken and you are missing certificate files.
-
https://wiki.zimbra.com/wiki/Fix_depth_lookup:unable_to_get_issuer_certificate
更新
稍微多一点帮助:
This problem is usually indicated by log messages saying something like "unable to get local issuer certificate" or "self signed certificate". When a certificate is verified its root CA must be "trusted" by OpenSSL this typically means that the CA certificate must be placed in a directory or file and the relevant program configured to read it. The OpenSSL program 'verify' behaves in a similar way and issues similar error messages: check the verify(1) program manual page for more information.
但仍然没有太大帮助。
看起来 Node.js 使用的是 1.0.2l 而不是 1.0.2m,但似乎没什么大不了的。
$ node -pe process.versions | grep openssl
openssl: '1.0.2l'
更新 2
很奇怪,当我从 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)
但是当我去浏览器时,我没有看到 "Proceed with caution" 页面,并且可以在 Node.js 中成功记录请求。也许这有点帮助。请帮忙:D
(此答案摘自 X509_verify_cert
at crypto/x509/x509_vfy.c:204
,在 openssl-1.0.2m 中)
OpenSSL verify
应用程序通过以下方式验证证书:它从目标证书开始构建证书链,并跟踪颁发者链,首先搜索与目标证书一起提供的任何不受信任的证书。在找不到不受信任的颁发者证书时,OpenSSL 切换到受信任的证书存储并继续构建链。此过程在
时停止
- 在受信任的商店中找不到发行者。
- 遇到自签名证书。
- 遇到最大验证深度。
此时我们有一条链可能会提前结束(如果我们未能找到发行者,或者如果我们超过了验证深度)。
OpenSSL 然后扫描链上的每个可信证书,寻找指定可信证书用途的 SSLv3 扩展。如果受信任的证书对于验证操作的 "purpose" 具有正确的 "trust" 属性(或具有 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
产量
[... 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
.):
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 会将其视为一般 "may verify for any purpose" 扩展。新的 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
该页底部附近是对前面讨论的简要总结:
The basicConstraints extension CA flag is used to determine whether
the certificate can be used as a CA. If the CA flag is true then it is
a CA, if the CA flag is false then it is not a CA. All CAs should have
the CA flag set to true.
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
作为备用计划,您始终可以提供整个链,或者您可以使用 -addtrust
hack 创建中间 CA。
https://letsencrypt.org/ 真的好用而且免费。此外,运行 节点在本地 HTTP 端口上没有 SSL,并使用 NGINX 作为 HTTPS 代理。
sudo apt-get install certbot nginx
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl on;
ssl_certificate /etc/letsencrypt/live/host.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/host.com/privkey.pem;
access_log /var/log/nginx/host.access.log;
error_log /var/log/nginx/host.error.log;
server_name _;
gzip on;
gzip_proxied any;
gzip_types text/css text/javascript text/xml text/plain application/javascript application/x-javascript application/json;
location / {
include /etc/nginx/proxy_params;
proxy_pass http://localhost:8080;
proxy_read_timeout 90s;
proxy_redirect http://localhost:8080 https://www.host.com;
}
}
我有一个简单的链设置,在这种情况下可以成功验证:
$ openssl version
OpenSSL 1.0.2m 2 Nov 2017
$ openssl verify -CAfile chain.pem cert.pem
cert.pem: OK
但是在这些情况下我会出错:
$ 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 中得到了它:
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 }
传递它,但仍然是同样的错误。
想知道如何进行调试或获取 HTTPS 服务器的修复方法 运行。
如果我使用 pfx
文件,我会得到以下信息:
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,并使 ca
属性成为 ca-cert.pem,它会给出:
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)
不知道该怎么做。
OpenSSL is unable to find a local certificate for the issuer (or the issuer of the first certificate in the chain received from the web server during the TLS handshake) with which to verify the signature(s).
不确定那是什么意思。
This error means the certificate path or chain is broken and you are missing certificate files.
- https://wiki.zimbra.com/wiki/Fix_depth_lookup:unable_to_get_issuer_certificate
更新
稍微多一点帮助:
This problem is usually indicated by log messages saying something like "unable to get local issuer certificate" or "self signed certificate". When a certificate is verified its root CA must be "trusted" by OpenSSL this typically means that the CA certificate must be placed in a directory or file and the relevant program configured to read it. The OpenSSL program 'verify' behaves in a similar way and issues similar error messages: check the verify(1) program manual page for more information.
但仍然没有太大帮助。
看起来 Node.js 使用的是 1.0.2l 而不是 1.0.2m,但似乎没什么大不了的。
$ node -pe process.versions | grep openssl
openssl: '1.0.2l'
更新 2
很奇怪,当我从 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)
但是当我去浏览器时,我没有看到 "Proceed with caution" 页面,并且可以在 Node.js 中成功记录请求。也许这有点帮助。请帮忙:D
(此答案摘自 X509_verify_cert
at crypto/x509/x509_vfy.c:204
,在 openssl-1.0.2m 中)
OpenSSL verify
应用程序通过以下方式验证证书:它从目标证书开始构建证书链,并跟踪颁发者链,首先搜索与目标证书一起提供的任何不受信任的证书。在找不到不受信任的颁发者证书时,OpenSSL 切换到受信任的证书存储并继续构建链。此过程在
- 在受信任的商店中找不到发行者。
- 遇到自签名证书。
- 遇到最大验证深度。
此时我们有一条链可能会提前结束(如果我们未能找到发行者,或者如果我们超过了验证深度)。
OpenSSL 然后扫描链上的每个可信证书,寻找指定可信证书用途的 SSLv3 扩展。如果受信任的证书对于验证操作的 "purpose" 具有正确的 "trust" 属性(或具有 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
产量
[... 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
.):
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 会将其视为一般 "may verify for any purpose" 扩展。新的 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
该页底部附近是对前面讨论的简要总结:
The basicConstraints extension CA flag is used to determine whether the certificate can be used as a CA. If the CA flag is true then it is a CA, if the CA flag is false then it is not a CA. All CAs should have the CA flag set to true.
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
作为备用计划,您始终可以提供整个链,或者您可以使用 -addtrust
hack 创建中间 CA。
https://letsencrypt.org/ 真的好用而且免费。此外,运行 节点在本地 HTTP 端口上没有 SSL,并使用 NGINX 作为 HTTPS 代理。
sudo apt-get install certbot nginx
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl on;
ssl_certificate /etc/letsencrypt/live/host.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/host.com/privkey.pem;
access_log /var/log/nginx/host.access.log;
error_log /var/log/nginx/host.error.log;
server_name _;
gzip on;
gzip_proxied any;
gzip_types text/css text/javascript text/xml text/plain application/javascript application/x-javascript application/json;
location / {
include /etc/nginx/proxy_params;
proxy_pass http://localhost:8080;
proxy_read_timeout 90s;
proxy_redirect http://localhost:8080 https://www.host.com;
}
}