【问题标题】:How to check two sided secured https connection using OpenSSL / Curl如何使用 OpenSSL / Curl 检查两侧安全的 https 连接
【发布时间】:2019-07-22 05:27:38
【问题描述】:

之前好像有人问过这个问题:
OpenSSL Verify return code: 20 (unable to get local issuer certificate)
但是不同的是它是关于本地颁发者证书的。此外,答案不适用于 Windows 计算机。

问题描述
在 Windows 计算机上,我有一个尝试联系安全服务器的程序。安全性在于双方的证书。

问题:我联系​​不上它,所以我试图找出证书是否正确安装

搜索,a.o.这里关于堆栈溢出,表明找到问题的好方法是为此使用 OpenSsl,即使我正在运行 Windows 计算机。

作为检查连接的所有证书是否正确安装的示例,建议我检查与 google.com 的连接:

openssl.exe s_client -connect google.com:443

(我的浏览器连接到这个服务器没有问题)

响应的第一行是

CONNECTED(00000184)
depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3
verify error:num=20:unable to get local issuer certificate
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com
   i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
 1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
   i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
---
Server certificate
-----BEGIN CERTIFICATE-----
...

再往下两次同样的错误:

Verification error: unable to get local issuer certificate
Verify return code: 20 (unable to get local issuer certificate)

唉,OpenSSL documentation about s_client 没有提供关于这些错误的非常丰富的信息。

那是什么意思?我是否缺少一些与 google.com 通信的证书,或者我为此使用了不正确的程序?

当然 google.com 只是一个例子。我选择了这个,所以我可以检查报告的问题是因为证书问题,还是因为我使用的命令。

对于我尝试联系的实际服务器,我拥有正确的证书(直到根目录)作为 .CER 文件。根证书在 winstore 中。

【问题讨论】:

  • "unable to get local issuer certificate" 表示你收到了一个远程证书,你(程序)提取了证书的颁发者部分并试图找到与这个颁发者相关的证书,但没有能够找到一个,因为它不在使用的信任库中。我不知道 Windows 上的 openssl 使用哪个信任库(操作系统之一或它自己的)。如果您收到自签名证书,则会出现错误,因为由自己签名的证书显然不是由已知 CA 签名的(因此需要将证书添加到适当的信任库中)
  • 谢谢帕特里克,您的评论为我指明了正确的方向。我会在回复中写下我的发现,并提及您的帮助

标签: windows ssl openssl authorization ssl-certificate


【解决方案1】:

Patrick Mevzek 向我指出了正确的答案(感谢 Patrick!)。因为需要进行一些调查,所以我决定把它写下来作为一个完整的答案。

我在 Windows Server 2012 中工作。较新的版本可能会类似地工作。测试证书和我使用的通信:

文件:

所以我是服务器的客户。有一个双向安全认证:通过非常安全的方法,我们有以下文件:

  • 可以信任的根证书:Root.Pem
  • 由根证书颁发的一系列不受信任的证书:A.PemB.PemC.Pem
  • 私钥文件MyPrivate.keyC.Pem颁发的可信证书,以确保我的身份:MyCertificate.pem

如果需要,将证书文件转换为 PEM 格式

如果证书不是 PEM 格式,我们需要先转换它们。要检查它们是否在 PEM 中,请在文本编辑器中打开它们。 PEM 文件如下所示:

-----BEGIN CERTIFICATE-----
MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
...
-----END CERTIFICATE-----

如果不是,我们可以使用openSSL来转换文件:

openssl.exe x509 -inform DER -in myCertificate.cer -out myCertificate.Pem
  • inform:输入文件的格式:DER / NET / PEM(好吧,如果已经是 PEM 就不必转换了)
  • in/out:输入文件,输出文件

验证证书链

为了提高安全性,我分别验证了每个证书。一步完成也可能是安全的。

  • 检查根证书的有效性。例如,通过使用已发布的指纹检查指纹。
  • 检查不受信任证书的有效性

(1) A.pem 是 Root.Pem 发布的吗?

openssl.exe verify -show_chain -CAfile root.pem A.pem

参数-CAfile 包含受信任的证书。最后一个文件是包含要验证的证书的文件。

回复应该类似于:

A.pem: OK
Chain:
depth=0: C = NL, ..., CN = <some text describing certificate A> (untrusted)
depth=1: C = NL, ..., CN = <some text describing the trusted root certificate>

(2) B.Pem 是否由受信任的 A.Pem 发行?

现在A.pem 可以信任,我们可以检查B.Pem。为此,我们提到中间证书 A.Pem 不可信,正如 this answer 中所建议的那样

openssl.exe verify -show_chain -CAfile root.pem -untrusted A.pem B.pem

回复:

B.pem: OK
Chain:
depth=0: C = NL, ..., CN = <some text describing certificate B> (untrusted)
depth=1: C = NL, ..., CN = <some text describing certificate A> (untrusted)
depth=2: C = NL, ..., CN = <some text describing the trusted root certificate>

(3) 我们可以信任证书链的其余部分吗?

所以现在 B 可以信任了。要继续检查链,请将不受信任的 CA 文件连接到一个 untrusted.pem 文件中。不要添加 MyCertificate.Pem

-----BEGIN CERTIFICATE-----
MIIGNjCCBB6gAwIBA...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
jCCBB6gAwIBA34F..
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
dZBo31cAYsByRL...
-----END CERTIFICATE-----

还有命令:

openssl.exe verify -show_chain -CAfile root.pem -untrusted untrusted.pem myCertificate.pem

回复:

MyCertificate.pem: OK
Chain:
depth=0: C = NL, ..., CN = <some text describing MyCertificate> (untrusted)
depth=1: C = NL, ..., CN = <some text describing certificate C> (untrusted)
depth=2: C = NL, ..., CN = <some text describing certificate B> (untrusted)
depth=3: C = NL, ..., CN = <some text describing certificate A> (untrusted)
depth=4: C = NL, ..., CN = <some text describing the trusted root certificate>

我想也许所有这些中间步骤都不是检查有效性所必需的。

检查连接

现在证书链是可信的,我们可以使用 OpenSsl 来检查连接。

  • 将除MyCertificate.pem 之外的所有证书连接到一个文件AllTrusted.pem、使用文本编辑器或命令Copy Root.Pem + A.Pem + B.Pem ... Trusted.Pem

命令:

openssl.exe s_client CAfile Trusted.Pem -connect google.nl:443

用正确的地址和端口替换google.nl:443

回复,类似于:

CONNECTED(00000124)
depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3
verify error:num=20:unable to get local issuer certificate
---
Certificate chain
0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=google.com
  i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
  i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIhWDCCIECgAwIBAgIQaEMB4EOx3++GhdWADJfgEjANBgkqhkiG9w0BAQsFADBU
...
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=Mountain View/O=Google LLC/CN=google.com
issuer=/C=US/O=Google Trust Services/CN=Google Internet Authority G3

服务器发送了一个证书来标识自己。客户端应使用此证书及其受信任的 CA 链来检查服务器的身份。

要继续通信,我们需要一个 PEM 文件,其中包含提到的颁发者及其颁发者,直到根。使用上述过程获取完整的证书链,并将所有证书按正确顺序添加到文件trusted.pem。如果您将收到的证书复制粘贴到 PEM 文件(文本),您应该能够验证收到的证书,就像我验证 MyCertificate.Pem 如上所述。

安装接收证书的 CA 证书后,我的 openssl s_client 命令回复:

...
SSL handshake has read 8945 by
Verification: OK
---
New, TLSv1.2, Cipher is ...
Server public key is 2048 bit

Start Time: 1551779993
Timeout   : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no

所以识别服务器的证书链被接受了。

向服务器识别我

下一步将检查我是否可以使用MyCertficate.pem 在服务器上识别自己。

这是我第一次需要我的私钥文件。我们将为此使用 curl:

命令:

curl.exe -v --cacert trusted.pem --cert MyCertificate.pem --key MyPrivate.key https://...
  • -v:详细
  • --cacert: 受信任的 CA 链连接到根的文本文件,使用 openssl verify 进行验证
  • --Cert:我用来识别自己的证书
  • --Key:此证书的私钥

回复:

...
* successfully set certificate verify locations:
*   CAfile: trustall.pem
...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):

* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):

* TLSv1.2 (IN), TLS handshake, Finished (20):
...
* Server certificate:
*  subject: C=NL; ...
*  start date: Apr 19 12:10:31 2016 GMT
*  expire date: Apr 19 12:10:31 2019 GMT
...
*  issuer: C=NL; O= <description of certificate issuer; should be in trusted.pem>
*  SSL certificate verify ok.
> GET /exchange/ciot HTTP/1.1
> Host: ....
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request

我们所看到的:

  • TrustAll.Pem 包含受信任的证书
  • (Out) Client Hello - (In) Server Hello: 显然我们在说话
  • 服务器发送证书并请求一个
  • 客户端发送其证书以识别自己
  • 显示收到的证书,服务器用它来标识自己。发行人应位于trusted.pem
  • 收到的证书已验证并接受。可以开始数据传输
  • 因为我没有发送任何数据,所以回复是400 Bad Request

所以这足以知道客户端和服务器都使用受信任的证书并且可以进行通信

【讨论】:

    猜你喜欢
    • 2013-02-13
    • 2015-12-06
    • 1970-01-01
    • 2020-06-14
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    • 2012-09-20
    相关资源
    最近更新 更多