无法“openssl 验证”letsencrypt 证书
Unable to `openssl verify' letsencrypt certificate
我使用 Certbot 容器通过 Letsencrypt 生成证书:
$ mkdir /home/$USER/letsencrypt
$ docker run -it --rm -p 80:80 -p 443:443 -v /home/$USER/letsencrypt:/etc/letsencrypt certbot/certbot certonly --standalone --email user@example.com --agree-tos -d example.com
我导航到生成的证书:
$ cd /home/$USER/letsencrypt/live/example.com
我可以验证 chain.pem
:
$ openssl verify chain.pem
chain.pem: OK
而且我可以看到 chain.pem
中的内容:
$ openssl x509 -noout -in chain.pem -subject -issuer
subject=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
issuer=O = Digital Signature Trust Co., CN = DST Root CA X3
我无法验证cert.pem
(大概是因为它需要链):
$ openssl verify cert.pem
CN = example.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error cert.pem: verification failed
但我也无法验证 fullchain.pem
:
$ openssl verify fullchain.pem
CN = example.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error fullchain.pem: verification failed
证书似乎在浏览器中有效,但在 curl
(和 Android http 客户端,这是真正的问题)中失败:
$ curl https://example.com
curl: (60) SSL certificate problem: unable to get local issuer certificate
我仔细检查过 fullchain.pem
是 cert.pem
和 chain.pem
的串联。
所以:我不明白为什么fullchain.pem
不验证?
与直觉相反,我终于 openssl verify
通过将根证书添加到链中来工作。感觉 Letsencrypt CA 应该已经可用了,所以我不认为这是正确的做法(欢迎发表评论)。
步骤是:
- Chrome 开发人员工具 > 安全选项卡 > 查看证书 > 详细信息选项卡 > Select 根证书 ("Builtin Object Token:DST Root CA X3")
- 点击导出,导出为 Base64-Encoded ASCII,单一证书(我将其命名为
ca.pem
)
将根连接到链:
$ ca.pem fullchain.pem > cachain.pem
然后验证:
$ openssl verify cachain.pem
cachain.pem: OK
这感觉"wrong"所以我想了解一下这是不是误报。
我从 man verify
中了解到这一点,阅读了 untrusted
的描述。事实证明 untrusted
实际上是您指定证书信任链的方式(当您这样说时似乎违反直觉)。
因此,您需要验证 Letsencrypt 证书的命令是:
openssl verify -untrusted chain.pem cert.pem
其中 cert.pem
是您的证书,chain.pem
是 LE 中间证书。没有必要为此使用 fullchain.pem
。
我为同样的问题苦苦挣扎了 3 天。但该错误是由于我的 Apache 配置中的配置错误造成的。
我通过 openssl 命令发现 s_client -connect advertentiekracht.nl:443 返回:
Certificate chain
0 s:/CN=advertentiekracht.nl
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
包括"Unable to get local issuer certificate"
命令:[root@srv ssl]# openssl x509 -noout -in /etc/letsencrypt/live/advertentiekracht.nl/chain.pem -subject -issuer
显示丢失的链:
subject= /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
issuer= /O=Digital Signature Trust Co./CN=DST Root CA X3
我当然不熟悉openssl和证书。肯定有很多原因导致“无法获得本地颁发者证书。但在你像我一样开始挖掘之前,请检查你的 http 服务器配置。对我来说就是 Apache。我在定义 SSL 证书 hocus pocus 的地方有拼写错误。httpd 标记下面的错误行
SSLCertificateFile /etc/letsencrypt/live/advertentiekracht.nl/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/advertentiekracht.nl/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
注意第一行 SSLCertificateFile 应该是 SSLCertificateChainFile,我错过了对 cert.pem 和 chain.pem 的引用。下面几行解决了我的问题:
SSLCertificateChainFile /etc/letsencrypt/live/advertentiekracht.nl/fullchain.pem
SSLCertificateFile /etc/letsencrypt/live/advertentiekracht.nl/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/advertentiekracht.nl/chain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/advertentiekracht.nl/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
结果,一个完整的链:
Certificate chain
0 s:/CN=advertentiekracht.nl
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
问题是 certbot 颁发的全链中的最后一个证书是由过期的根证书颁发的证书(json 中的输出以说明链中的每个证书)截至 2021 年 9 月 30 日( https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/)
[
{
"subject": {
"commonName": "..."
},
"issuer": {
"countryName": "US",
"organizationName": "Let's Encrypt",
"commonName": "R3"
},
"version": 3,
...
},
"OCSP": [
"http://r3.o.lencr.org"
],
"caIssuers": [
"http://r3.i.lencr.org/"
]
},
{
"subject": {
"countryName": "US",
"organizationName": "Let's Encrypt",
"commonName": "R3"
},
"issuer": {
"countryName": "US",
"organizationName": "Internet Security Research Group",
"commonName": "ISRG Root X1"
},
"version": 3,
"serialNumber": "912B084ACF0C18A753F6D62E25A75F5A",
"notBefore": "Sep 4 00:00:00 2020 GMT",
"notAfter": "Sep 15 16:00:00 2025 GMT",
"caIssuers": [
"http://x1.i.lencr.org/"
],
"crlDistributionPoints": [
"http://x1.c.lencr.org/"
]
},
{
"subject": {
"countryName": "US",
"organizationName": "Internet Security Research Group",
"commonName": "ISRG Root X1"
},
"issuer": {
"organizationName": "Digital Signature Trust Co.",
"commonName": "DST Root CA X3"
},
"version": 3,
"serialNumber": "4001772137D4E942B8EE76AA3C640AB7",
"notBefore": "Jan 20 19:14:03 2021 GMT",
"notAfter": "Sep 30 18:14:03 2024 GMT",
"caIssuers": [
"http://apps.identrust.com/roots/dstrootcax3.p7c"
],
"crlDistributionPoints": [
"http://crl.identrust.com/DSTROOTCAX3CRL.crl"
]
}
]
请注意,链中的最后一项是由 DST Root CA X3 颁发的,如果您获取 http://apps.identrust.com/roots/dstrootcax3.p7c,您会看到它是新近过期的 DST Root CA X3 证书。
所以你得到
$ openssl verify -CAfile fullchain.pem fullchain.pem
server.pem: O = Digital Signature Trust Co., CN = DST Root CA X3
error 10 at 1 depth lookup:certificate has expired
O = Digital Signature Trust Co., CN = DST Root CA X3
error 10 at 3 depth lookup:certificate has expired
OK
但是如果您从 fullchain.pem 中删除最后一个证书并将输出放入 chain.pem
$ openssl verify -CAfile chain.pem fullchain.pem
server.pem: OK
(注意验证只检查 fullchain.pem 中的第一个证书)
对于最新版本的 openssl,您可以使用 -partial_chain
或 -trusted_first
,但这些在 MacOS 上安装的 openssl 上不可用。
我这里有几个pem处理工具:https://gitlab.com/Blockdaemon/pem2json
我使用 Certbot 容器通过 Letsencrypt 生成证书:
$ mkdir /home/$USER/letsencrypt
$ docker run -it --rm -p 80:80 -p 443:443 -v /home/$USER/letsencrypt:/etc/letsencrypt certbot/certbot certonly --standalone --email user@example.com --agree-tos -d example.com
我导航到生成的证书:
$ cd /home/$USER/letsencrypt/live/example.com
我可以验证 chain.pem
:
$ openssl verify chain.pem
chain.pem: OK
而且我可以看到 chain.pem
中的内容:
$ openssl x509 -noout -in chain.pem -subject -issuer
subject=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
issuer=O = Digital Signature Trust Co., CN = DST Root CA X3
我无法验证cert.pem
(大概是因为它需要链):
$ openssl verify cert.pem
CN = example.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error cert.pem: verification failed
但我也无法验证 fullchain.pem
:
$ openssl verify fullchain.pem
CN = example.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error fullchain.pem: verification failed
证书似乎在浏览器中有效,但在 curl
(和 Android http 客户端,这是真正的问题)中失败:
$ curl https://example.com
curl: (60) SSL certificate problem: unable to get local issuer certificate
我仔细检查过 fullchain.pem
是 cert.pem
和 chain.pem
的串联。
所以:我不明白为什么fullchain.pem
不验证?
与直觉相反,我终于 openssl verify
通过将根证书添加到链中来工作。感觉 Letsencrypt CA 应该已经可用了,所以我不认为这是正确的做法(欢迎发表评论)。
步骤是:
- Chrome 开发人员工具 > 安全选项卡 > 查看证书 > 详细信息选项卡 > Select 根证书 ("Builtin Object Token:DST Root CA X3")
- 点击导出,导出为 Base64-Encoded ASCII,单一证书(我将其命名为
ca.pem
)
将根连接到链:
$ ca.pem fullchain.pem > cachain.pem
然后验证:
$ openssl verify cachain.pem
cachain.pem: OK
这感觉"wrong"所以我想了解一下这是不是误报。
我从 man verify
中了解到这一点,阅读了 untrusted
的描述。事实证明 untrusted
实际上是您指定证书信任链的方式(当您这样说时似乎违反直觉)。
因此,您需要验证 Letsencrypt 证书的命令是:
openssl verify -untrusted chain.pem cert.pem
其中 cert.pem
是您的证书,chain.pem
是 LE 中间证书。没有必要为此使用 fullchain.pem
。
我为同样的问题苦苦挣扎了 3 天。但该错误是由于我的 Apache 配置中的配置错误造成的。
我通过 openssl 命令发现 s_client -connect advertentiekracht.nl:443 返回:
Certificate chain
0 s:/CN=advertentiekracht.nl
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
包括"Unable to get local issuer certificate"
命令:[root@srv ssl]# openssl x509 -noout -in /etc/letsencrypt/live/advertentiekracht.nl/chain.pem -subject -issuer 显示丢失的链:
subject= /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
issuer= /O=Digital Signature Trust Co./CN=DST Root CA X3
我当然不熟悉openssl和证书。肯定有很多原因导致“无法获得本地颁发者证书。但在你像我一样开始挖掘之前,请检查你的 http 服务器配置。对我来说就是 Apache。我在定义 SSL 证书 hocus pocus 的地方有拼写错误。httpd 标记下面的错误行
SSLCertificateFile /etc/letsencrypt/live/advertentiekracht.nl/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/advertentiekracht.nl/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
注意第一行 SSLCertificateFile 应该是 SSLCertificateChainFile,我错过了对 cert.pem 和 chain.pem 的引用。下面几行解决了我的问题:
SSLCertificateChainFile /etc/letsencrypt/live/advertentiekracht.nl/fullchain.pem
SSLCertificateFile /etc/letsencrypt/live/advertentiekracht.nl/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/advertentiekracht.nl/chain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/advertentiekracht.nl/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
结果,一个完整的链:
Certificate chain
0 s:/CN=advertentiekracht.nl
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
问题是 certbot 颁发的全链中的最后一个证书是由过期的根证书颁发的证书(json 中的输出以说明链中的每个证书)截至 2021 年 9 月 30 日( https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/)
[
{
"subject": {
"commonName": "..."
},
"issuer": {
"countryName": "US",
"organizationName": "Let's Encrypt",
"commonName": "R3"
},
"version": 3,
...
},
"OCSP": [
"http://r3.o.lencr.org"
],
"caIssuers": [
"http://r3.i.lencr.org/"
]
},
{
"subject": {
"countryName": "US",
"organizationName": "Let's Encrypt",
"commonName": "R3"
},
"issuer": {
"countryName": "US",
"organizationName": "Internet Security Research Group",
"commonName": "ISRG Root X1"
},
"version": 3,
"serialNumber": "912B084ACF0C18A753F6D62E25A75F5A",
"notBefore": "Sep 4 00:00:00 2020 GMT",
"notAfter": "Sep 15 16:00:00 2025 GMT",
"caIssuers": [
"http://x1.i.lencr.org/"
],
"crlDistributionPoints": [
"http://x1.c.lencr.org/"
]
},
{
"subject": {
"countryName": "US",
"organizationName": "Internet Security Research Group",
"commonName": "ISRG Root X1"
},
"issuer": {
"organizationName": "Digital Signature Trust Co.",
"commonName": "DST Root CA X3"
},
"version": 3,
"serialNumber": "4001772137D4E942B8EE76AA3C640AB7",
"notBefore": "Jan 20 19:14:03 2021 GMT",
"notAfter": "Sep 30 18:14:03 2024 GMT",
"caIssuers": [
"http://apps.identrust.com/roots/dstrootcax3.p7c"
],
"crlDistributionPoints": [
"http://crl.identrust.com/DSTROOTCAX3CRL.crl"
]
}
]
请注意,链中的最后一项是由 DST Root CA X3 颁发的,如果您获取 http://apps.identrust.com/roots/dstrootcax3.p7c,您会看到它是新近过期的 DST Root CA X3 证书。
所以你得到
$ openssl verify -CAfile fullchain.pem fullchain.pem
server.pem: O = Digital Signature Trust Co., CN = DST Root CA X3
error 10 at 1 depth lookup:certificate has expired
O = Digital Signature Trust Co., CN = DST Root CA X3
error 10 at 3 depth lookup:certificate has expired
OK
但是如果您从 fullchain.pem 中删除最后一个证书并将输出放入 chain.pem
$ openssl verify -CAfile chain.pem fullchain.pem
server.pem: OK
(注意验证只检查 fullchain.pem 中的第一个证书)
对于最新版本的 openssl,您可以使用 -partial_chain
或 -trusted_first
,但这些在 MacOS 上安装的 openssl 上不可用。
我这里有几个pem处理工具:https://gitlab.com/Blockdaemon/pem2json