如何在 Linux 中从证书链中提取根 CA 和从属 CA?

如何在 Linux 中从证书链中提取根 CA 和从属 CA?

我有一个终端实体/服务器证书,其中包含中间证书和根证书。当我cat在最终实体证书上时,我只看到一个BEGINEND标签。它是唯一的最终实体证书。

有什么方法可以查看中间证书和根证书内容。我只需要BEGIN和标签的内容END

在 Windows 中,我可以从“证书路径”看到完整的证书链。以下是 Stack Exchange 证书的示例。

在此输入图像描述

从那里我可以执行查看证书并导出它们。我可以在 Windows 中对根目录和中间目录执行此操作。我正在Linux中寻找同样的方法。

在此输入图像描述

答案1

从网站上,您可以执行以下操作:

openssl s_client -showcerts -verify 5 -connect stackexchange.com:443 < /dev/null

这将显示证书链和服务器提供的所有证书。

现在,如果我将这两个证书保存到文件中,我可以使用openssl verify

$ openssl verify -show_chain -untrusted dc-sha2.crt se.crt 
se.crt: OK
Chain:
depth=0: C = US, ST = NY, L = New York, O = "Stack Exchange, Inc.", CN = *.stackexchange.com (untrusted)
depth=1: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 High Assurance Server CA (untrusted)
depth=2: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA

-untrusted选项用于提供中间证书;se.crt是要验证的证书。深度=2的结果来自系统信任的CA存储。

如果您没有中间证书,则无法执行验证。这就是 X.509 的工作原理。

根据证书的不同,它可能包含从中获取中间体的 URI。例如,openssl x509 -in se.crt -noout -text包含:

        Authority Information Access: 
            OCSP - URI:http://ocsp.digicert.com
            CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2HighAssuranceServerCA.crt

该“CA Issuers”URI 指向中间证书(采用 DER 格式,因此您需要使用openssl x509 -inform der -in DigiCertSHA2HighAssuranceServerCA.crt -out DigiCertSHA2HighAssuranceServerCA.pem它来转换它以供 OpenSSL 进一步使用)。

如果运行,openssl x509 -in /tmp/DigiCertSHA2HighAssuranceServerCA.pem -noout -issuer_hash您会得到244b5494,您可以在系统根 CA 存储中查找它/etc/ssl/certs/244b5494.0(只需附加.0到名称)。

我认为没有一个好的、简单的 OpenSSL 命令可以为您完成所有这些工作。

答案2

tl;dr - 一个 liner bash 魔法可以转储链中的所有证书

openssl s_client -showcerts -verify 5 -connect wikipedia.org:443 < /dev/null |
   awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN CERTIFICATE/){a++}; out="cert"a".pem"; print >out}'
for cert in *.pem; do 
        newname=$(openssl x509 -noout -subject -in $cert | sed -nE 's/.*CN ?= ?(.*)/\1/; s/[ ,.*]/_/g; s/__/_/g; s/_-_/-/; s/^_//g;p' | tr '[:upper:]' '[:lower:]').pem
        echo "${newname}"; mv "${cert}" "${newname}" 
done

分2步解释

要将链中的所有证书转储到当前目录,如下所示cert${chain_number}.pem

openssl s_client -showcerts -verify 5 -connect your_host:443 < /dev/null |
 awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN CERTIFICATE/){a++}; out="cert"a".pem"; print >out}' 

将它们重命名为通用名称的奖励曲目:

for cert in *.pem; do 
   newname=$(openssl x509 -noout -subject -in $cert | sed -nE 's/.*CN ?= ?(.*)/\1/; s/[ ,.*]/_/g; s/__/_/g; s/_-_/-/; s/^_//g;p' | tr '[:upper:]' '[:lower:]').pem
   mv $cert $newname 
done

答案3

我发现使用选项-verify 5openssl 会深入显示所有证书,甚至不包含在您的证书部署中。

如果您确实想了解您的证书提供了哪个链,您应该运行:

openssl s_client -showcerts -partial_chain -connect YOUR_ENDPOINT:443 < /dev/null |less

答案4

当我使用 Lets Encrypt 免费通配符证书时,上述方法对我不起作用。

更具体地说:
我有一个 Kubernetes 集群 + 入口控制器,它使用 *.mydomain.dev 的 Lets Encrypt 免费通配符证书进行配置,它托管以下 2 个域名:

  • grafana.mydomain.dev
  • prometheus.mydomain.dev

我必须在每个站点后面添加 -servername 标志:https://community.letsencrypt.org/t/where-can-i-download-the-trusted-root-ca-certificates-for-lets-encrypt/33241/2

export DOMAIN=grafana.mydomain.dev
openssl s_client -showcerts -verify 5 -connect $DOMAIN:443 -servername $DOMAIN < /dev/null 2> /dev/null | awk '/BEGIN/,/END/{ if(/BEGIN/){a++}; print}'

我还调整了链,因此它为我提供了标准输出的完整证书+中间+根并隐藏stderr噪音。

实际上...在测试时我发现这并没有给我 CA... openssl s_client -showcerts -verify 5 -connect letsencrypt.org:443 < /dev/null 2> /dev/null | awk '/BEGIN/,/END/{ if(/BEGIN/){a++}; print}'

curl https://letsencrypt.org/certs/isrgrootx1.pem 给出不同的值(当测试某些东西时,这是有效的值。)

相关内容