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

时间:2017-12-01 02:25:17

标签: node.js openssl certificate x509certificate

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

$ 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保留在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)

不确定该怎么做。

Here他们说:

  

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'

更新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)

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

2 个答案:

答案 0 :(得分:5)

(此答案摘自[{1}} X509_verify_cert,openssl-1.0.2m)

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

时此过程停止
  1. 在受信任的商店中找不到发行人。
  2. 遇到自签名证书。
  3. 遇到最大验证深度。
  4. 此时我们有一个可能过早结束的链(如果我们找不到发行人,或者我们超过了验证深度)。

    然后,OpenSSL扫描链上的每个可信证书,查找指定可信证书目的的SSLv3扩展。如果可信证书具有用于验证操作的“目的”的正确“信任”属性(或具有verify属性),则该链是可信的。 (原谅信任属性上的手动波,代码的那部分难以阅读。)

    所以让我们测试一下。首先,让我们重新考虑OP的错误案例:

    anyExtendedKeyUsage

    产量

    #
    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 的{​​{1}}选项来确保我们在中间CA上有一个可接受的信任属性(称之为-addtrust;我们将使用它签署openssl x509。):

    IntermediateCAWithTrust

    这会产生

    AnotherUserCert
    嘿,看!我们刚刚通过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 ),我们的CA证书

    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
    

    我认为OpenSSL会视为一般“可以为任何目的进行验证”扩展。新via openssl x509 -in ca-crt.pem -noout -text没有 X509v3 Basic Constraints: CA:TRUE ,而是

    IntermediateCAWithTrust

    有关X509v3 Basic Constraints选项中的详细信息以及可添加的信任属性类型,请参阅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(在Trusted Uses: Any Extended Key Usage No Rejected Uses. 中)。这似乎是一个很好的教程(并且它明确地将中间CA生成为CA):https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html

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

答案 1 :(得分:-1)

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;
    }
}