OpenSSL错误 - 无法获得本地颁发者证书

Lan*_*ard 9 openssl certificate x509certificate node.js

我有一个简单的链设置,可以在这种情况下成功验证:

$ openssl version
OpenSSL 1.0.2m  2 Nov 2017
$ openssl verify -CAfile chain.pem cert.pem
cert.pem: OK
Run Code Online (Sandbox Code Playgroud)

但是我在这些情况下遇到错误:

$ openssl verify -CAfile ca-cert.pem cert.pem
cert.pem: C = US...
error 2 at 1 depth lookup:unable to get issuer certificate
Run Code Online (Sandbox Code Playgroud)

特别是无法获得颁发者证书.

也来这里:

$ 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
Run Code Online (Sandbox Code Playgroud)

最后,当我将密钥传递给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)
Run Code Online (Sandbox Code Playgroud)

我尝试传递它{ 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)
Run Code Online (Sandbox Code Playgroud)

如果我只将cert.pem保留在cert文件中,并使该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)
Run Code Online (Sandbox Code Playgroud)

不知道该怎么办.

他们在这里说:

OpenSSL无法为发布者(或在TLS握手期间从Web服务器接收的链中的第一个证书的颁发者)查找用于验证签名的本地证书.

不确定那是什么意思.

此错误表示证书路径或链断开,您缺少证书文件.

- https://wiki.zimbra.com/wiki/Fix_depth_lookup:unable_to_get_issuer_certificate

更新

稍微多一点帮助:

此问题通常由日志消息指示,例如"无法获取本地颁发者证书"或"自签名证书".验证证书时,其根CA必须由OpenSSL"信任",这通常意味着CA证书必须放在目录或文件中,并且相关程序配置为读取它.OpenSSL程序"verify"以类似的方式运行并发出类似的错误消息:有关详细信息,请查看verify(1)程序手册页.

但仍然没有多大帮助.

看起来Node.js使用1.0.2l而不是1.0.2m,但似乎没什么大不了的.

$ node -pe process.versions | grep openssl
  openssl: '1.0.2l'
Run Code Online (Sandbox Code Playgroud)

更新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)
Run Code Online (Sandbox Code Playgroud)

但是当我进入浏览器时,我没有看到"继续谨慎"页面,并且可以在Node.js中成功记录请求.也许这有点帮助.请帮忙:D

loc*_*g8b 6

(此答案摘自X509_verify_certat crypto/x509/x509_vfy.c:204,openssl-1.0.2m)

OpenSSL verify应用程序通过以下方式验证证书:它构建从目标证书开始的证书链,并跟踪颁发者链,首先搜索与目标证书一起提供的任何不受信任的证书.未能找到不受信任的颁发者证书时,OpenSSL将切换到受信任的证书存储区并继续构建链.此过程在何时停止

  1. 在受信任的商店中找不到发行者.
  2. 遇到自签名证书.
  3. 遇到最大验证深度.

在这一点上,我们有一个可能过早结束的链(如果我们找不到发行人,或者我们超过了验证深度).

然后,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
Run Code Online (Sandbox Code Playgroud)

产量

[... 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
Run Code Online (Sandbox Code Playgroud)

现在,让我们使用-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
Run Code Online (Sandbox Code Playgroud)

这产生了

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
Run Code Online (Sandbox Code Playgroud)

你看!我们刚刚通过IntermediateCAWithTrust成功验证了AnotherUserCert,即使我们没有提供整个链.这种差异的关键在于中的任何一个可信证书都具有适用于验证操作的信任属性.

仔细观察(via openssl x509 -in ca-crt.pem -noout -text),我们的CA证书有

        X509v3 Basic Constraints:
            CA:TRUE
Run Code Online (Sandbox Code Playgroud)

我认为OpenSSL将视为一般"可以为任何目的进行验证"扩展.新的IntermediateCAWithTrust没有X509v3 Basic Constraints,但相反

Trusted Uses:
  Any Extended Key Usage
No Rejected Uses.
Run Code Online (Sandbox Code Playgroud)

有关-addtrust选项中的更多信息以及可添加的信任属性类型,请参阅https://www.openssl.org/docs/manmaster/man1/x509.html#TRUST_SETTINGS

该页面底部附近是前面讨论的简明摘要:

basicConstraints扩展CA标志用于确定证书是否可用作CA. 如果CA标志为真,则它是CA,如果CA标志为假,则它不是CA. 所有CA都应将CA标志设置为true.

如果不存在basicConstraints扩展,则证书被认为是"可能的CA",根据证书的预期用途检查其他扩展.在这种情况下会给出警告,因为证书确实不应被视为CA:但是允许CA作为CA解决某些损坏的软件.

因此,简而言之,请确保您的中间CA是正确的CA(在其中X509v3 Basic Constraints).这似乎是一个很好的教程(它明确地将中间CA生成为CA):https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html

作为备份计划,您始终可以提供整个链,或者您可以使用-addtrusthack 制作中间CA.

  • 感谢您的精彩回答!然而,当我运行第一个脚本时,奇怪的是,通过链的验证对我不起作用。我检查了证书,结果发现根证书是正确的 X509 v3 证书,但由于某种原因,中间证书是 X509 v1 非 CA 证书。我想知道为什么这对您有用以及我该怎么做才能为中间 CA 获得适当的证书。 (2认同)