从“openssl s_client”命令的输出中提取证书

3

我希望能够获取http站点证书链的所有证书。使用openssl连接到http站点并将输出存储到文件out.txt中:

openssl s_client -connect www.openssl.org:443 -showcerts > out.txt

out.txt 的内容如下所示。它包含两个证书:

...
 0 s:CN = www.openssl.org
   i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
-----BEGIN CERTIFICATE-----
MIIFVTCCBD2gAwIBAgISAwk9QUiwVmoQAtcCLKybaK7yMA0GCSqGSIb3DQEBCwUA
...
mQBom1EISBOiNyu5koR6iRZcXsn6x/4kwA==
-----END CERTIFICATE-----
 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
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
...
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----
---
...

现在我想将每个证书存储在以.cer 结尾的文件中。 对于上面的示例,应创建文件 Let's Encrypt Authority X3.cerwww.openssl.org.cer
使用命令openssl x509时,我只能存储包含在out.txt中的第一个证书。
cat out.txt | openssl x509 > www.openssl.org.cer

但我希望存储在 out.txt 中的所有 证书,而不仅仅是第一个。

这可通过 opensslawk 实现吗?

1个回答

5

可以使用awk来完成这个任务。我将逐步呈现我的解决方案。

步骤1:提取"BEGAIN CERTIFICATE"和"END CERTIFICATE"之间的所有内容

只将"BEGAIN CERTIFICATE"和"END CERTIFICATE"之间的行写入输出:

awk '
/BEGIN CERTIFICATE/,/END CERTIFICATE/ {
print $0
}
' out.txt

步骤二:提取包含CN的行

选择包含CN的行(例如 0 s:CN = www.openssl.org)

awk '
/^ [0-9]+ s:.*CN = / {
print $0
}
' out.txt

这将产生输出:
 0 s:CN = www.openssl.org
 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

步骤三:提取CN字段的内容

awk '
BEGIN {
# change field separator, so that $2 returns everything after "CN = "
FS="CN = "
}
# selects line which contains CN (e.g.  0 s:CN = www.openssl.org)
/^ [0-9]+ s:.*CN = / {
# use CN (e.g. www.openssl.org) as filename
print $2
}
' out.txt

这将产生输出结果:
www.openssl.org
Let's Encrypt Authority X3

步骤四:完整解决方案

这将创建文件Let's Encrypt Authority X3.cerwww.openssl.org.cer

awk '
BEGIN {
# change field separator, so that $2 returns everything after "CN = "
FS="CN = "
}
# selects line which contains CN (e.g.  0 s:CN = www.openssl.org)
/^ [0-9]+ s:.*CN = / {
# use CN (e.g. www.openssl.org) as filename
filename=$2".cer"
}
# write all lines between "BEGIN CERTIFICATE" and "END CERTIFICATE" to filename
/BEGIN CERTIFICATE/,/END CERTIFICATE/ {
print $0 > filename
}
' out.txt

AWK 文档: https://www.gnu.org/software/gawk/manual/html_node/index.html


这几乎是完美的。不过有一个问题,如果 CN = 不是最后一个呢?在我的情况下,$2 匹配 Zscaler Intermediate Root CA (zscalertwo.net), emailAddress = support@zscaler.com 而不是 **Zscaler Intermediate Root CA (zscalertwo.net)**。 - mark
我用split($2,cn,","); gsub(/"/, "", cn[1]); filename=cn[1]".crt"替换了filename=$2".cer"。不确定这是否是awk中惯用的方法。 - mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接