我发现最接近的答案是使用“grep”。
> openssl x509 -text -noout -in cert.pem | grep DNS
有更好的方法吗?我只喜欢命令行。
感谢。
答案 0 :(得分:31)
请注意,您可以通过添加以下选项将-text
的输出限制为仅扩展名:
-certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux
即:
openssl x509 -text -noout -in cert.pem \
-certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux
但是,您仍然需要应用一些文本解析逻辑才能获得Subject Alternative Name
。
如果这还不够,我认为您需要编写一个使用openssl库来提取您正在寻找的特定字段的小程序。以下是一些示例程序,用于说明如何解析证书,包括提取Subject Alternative Name
等扩展字段:
https://zakird.com/2013/10/13/certificate-parsing-with-openssl
请注意,如果您继续编程路线,则不必使用openssl和C ...您可以选择自己喜欢的语言和ASN.1
解析器库,然后使用它。例如,在Java中,您可以使用http://jac-asn1.sourceforge.net/和许多其他人。
答案 1 :(得分:19)
取自https://stackoverflow.com/a/13128918/1695680
$ true | openssl s_client -connect example.com:443 | openssl x509 -noout -text | grep DNS:
$ true | openssl s_client -connect localhost:8443 | openssl x509 -noout -text | grep DNS:
depth=2 C = US, ST = NC, L = SomeCity, O = SomeCompany Security, OU = SomeOU, CN = SomeCN
verify error:num=19:self signed certificate in certificate chain
DONE
DNS:localhost, DNS:127.0.0.1, DNS:servername1.somedom.com, DNS:servername2.somedom.local
答案 2 :(得分:10)
sed -ne '
s/^\( *\)Subject:/\1/p;
/X509v3 Subject Alternative Name/{
N;
s/^.*\n//;
:a;
s/^\( *\)\(.*\), /\1\2\n\1/;
ta;
p;
q;
}' < <(openssl x509 -in cert.pem -noout -text)
可写:
sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }' < <(
openssl x509 -in cert.pem -noout -text )
可以渲染类似:
CN=www.example.com
DNS:il0001.sample.com
DNS:example.com
DNS:demodomain.com
DNS:testsite.com
DNS:www.il0001.sample.com
DNS:www.il0001.sample.com.vsite.il0001.sample.com
DNS:www.example.com
DNS:www.example.com.vsite.il0001.sample.com
DNS:www.demodomain.com
DNS:www.demodomain.com.vsite.il0001.sample.com
DNS:www.testsite.com
DNS:www.testsite.com.vsite.il0001.sample.com
sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }' < <(
openssl x509 -noout -text -in <(
openssl s_client -ign_eof 2>/dev/null <<<$'HEAD / HTTP/1.0\r\n\r' \
-connect google.com:443 ) )
可能输出:
C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com
DNS:*.google.com
DNS:*.android.com
DNS:*.appengine.google.com
DNS:*.cloud.google.com
DNS:*.gcp.gvt2.com
DNS:*.google-analytics.com
DNS:*.google.ca
DNS:*.google.cl
DNS:*.google.co.in
DNS:*.google.co.jp
DNS:*.google.co.uk
DNS:*.google.com.ar
DNS:*.google.com.au
DNS:*.google.com.br
DNS:*.google.com.co
DNS:*.google.com.mx
DNS:*.google.com.tr
DNS:*.google.com.vn
DNS:*.google.de
DNS:*.google.es
DNS:*.google.fr
DNS:*.google.hu
DNS:*.google.it
DNS:*.google.nl
DNS:*.google.pl
DNS:*.google.pt
DNS:*.googleadapis.com
DNS:*.googleapis.cn
DNS:*.googlecommerce.com
DNS:*.googlevideo.com
DNS:*.gstatic.cn
DNS:*.gstatic.com
DNS:*.gvt1.com
DNS:*.gvt2.com
DNS:*.metric.gstatic.com
DNS:*.urchin.com
DNS:*.url.google.com
DNS:*.youtube-nocookie.com
DNS:*.youtube.com
DNS:*.youtubeeducation.com
DNS:*.ytimg.com
DNS:android.clients.google.com
DNS:android.com
DNS:developer.android.google.cn
DNS:g.co
DNS:goo.gl
DNS:google-analytics.com
DNS:google.com
DNS:googlecommerce.com
DNS:urchin.com
DNS:www.goo.gl
DNS:youtu.be
DNS:youtube.com
DNS:youtubeeducation.com
由于< <(...)
是 bashism ,必须编写相同的命令:
openssl x509 -in cert.pem -noout -text | sed -ne '
s/^\( *\)Subject:/\1/p;
/X509v3 Subject Alternative Name/{
N;
s/^.*\n//;
:a;
s/^\( *\)\(.*\), /\1\2\n\1/;
ta;
p;
q;
}'
和
printf 'HEAD / HTTP/1.0\r\n\r\n' |
openssl s_client -ign_eof 2>/dev/null -connect google.com:443 |
openssl x509 -noout -text |
sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }'
答案 3 :(得分:4)
使用grep
的非常简单的解决方案openssl x509 -in /path/to/x509/cert -noout -text|grep -oP '(?<=DNS:|IP Address:)[^,]+'|sort -uV
对于Google证书,此输出:
android.clients.google.com
android.com
developer.android.google.cn
g.co
goo.gl
google.com
googlecommerce.com
google-analytics.com
hin.com
urchin.com
www.goo.gl
youtu.be
youtube.com
youtubeeducation.com
*.android.com
*.appengine.google.com
*.cloud.google.com
*.gcp.gvt2.com
*.googleadapis.com
*.googleapis.cn
*.googlecommerce.com
*.googlevideo.com
*.google.ca
*.google.cl
*.google.com
*.google.com.ar
*.google.com.au
*.google.com.br
*.google.com.co
*.google.com.mx
*.google.com.tr
*.google.com.vn
*.google.co.in
*.google.co.jp
*.google.co.uk
*.google.de
*.google.es
*.google.fr
*.google.hu
*.google.it
*.google.nl
*.google.pl
*.google.pt
*.gstatic.cn
*.gstatic.com
*.gvt1.com
*.gvt2.com
*.metric.gstatic.com
*.urchin.com
*.url.google.com
*.youtubeeducation.com
*.youtube.com
*.ytimg.com
*.google-analytics.com
*.youtube-nocookie.com
答案 4 :(得分:1)
您可以使用awk
更接近SAN,将上述选项引入awk
语句:
openssl x509 -in mycertfile.crt -text -noout \
-certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_subject,no_issuer,no_pubkey,no_sigdump,no_aux \
| awk '/X509v3 Subject Alternative Name/','/X509v3 Basic Constraints/'
答案 5 :(得分:1)
较新版本的openssl具有“ -ext”选项,该选项仅允许您打印subjectAltName记录。在Debian 9.9上使用'OpenSSL 1.1.1b'
openssl x509 -noout -ext subjectAltName -in cert.pem
尽管您仍然需要解析输出。
中进行的答案 6 :(得分:0)
如何显示证书的主题备用名称?
X509证书中可能有多个SAN。以下内容来自SSL/TLS Client的OpenSSL wiki。它遍历名称并打印出来。
您从TLS连接X509*
中获取SSL_get_peer_certificate
,从内存中获取d2i_X509
,或从文件系统获得PEM_read_bio_X509
。
void print_san_name(const char* label, X509* const cert)
{
int success = 0;
GENERAL_NAMES* names = NULL;
unsigned char* utf8 = NULL;
do
{
if(!cert) break; /* failed */
names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
if(!names) break;
int i = 0, count = sk_GENERAL_NAME_num(names);
if(!count) break; /* failed */
for( i = 0; i < count; ++i )
{
GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
if(!entry) continue;
if(GEN_DNS == entry->type)
{
int len1 = 0, len2 = -1;
len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
if(utf8) {
len2 = (int)strlen((const char*)utf8);
}
if(len1 != len2) {
fprintf(stderr, " Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
}
/* If there's a problem with string lengths, then */
/* we skip the candidate and move on to the next. */
/* Another policy would be to fails since it probably */
/* indicates the client is under attack. */
if(utf8 && len1 && len2 && (len1 == len2)) {
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
}
if(utf8) {
OPENSSL_free(utf8), utf8 = NULL;
}
}
else
{
fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
}
}
} while (0);
if(names)
GENERAL_NAMES_free(names);
if(utf8)
OPENSSL_free(utf8);
if(!success)
fprintf(stdout, " %s: <not available>\n", label);
}
答案 7 :(得分:0)
基于awk的改进解决方案(提示:@RandomW):
openssl x509 -in certfile -text -noout \
-certopt no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux \
| awk '/X509v3 Subject Alternative Name:/ {san=1;next}
san && /^ *X509v3/ {exit}
san { sub(/DNS:/,"",$1);print $1}'
这将打印出一个列表,这里也可以找到grep
和sed
解决方案。不同之处在于,可以更严格地控制找到信息的位置。如果输出格式发生更改,此版本将更强大,并且可以更好地处理更改。仅打印“主题备用名称”和下一个“ X509v3”部分之间的文本,并去除前面的所有可选“ DNS:”文本。
android.clients.google.com
android.com
developer.android.google.cn
g.co
goo.gl
...
答案 8 :(得分:0)
添加python替代品。 前提条件是您必须具有一个带有“ DNS:”记录的字符串。
获取证书详细信息(子进程,OpenSSL模块等) dnsstring包含“ openssl”输出的“ DNS:”行。 如何从文本输出中获取DNS名称字符串的示例 的证书。
for idx, line in enumerate(certoutput.split()):
if ' X509v3 Authority Key Identifier:' in line:
dnsstring = certoutput.split()[idx + 1]
# Get a list
[x.replace('DNS:', '').replace(',', '') for x in dnsstring]
# Format to a comma separated string
', '.join([x.replace('DNS:', '').replace(',', '') for x in dnsstring])
一个命令行示例:
true | \
openssl s_client -showcerts -connect google.com:443 2>/dev/null | \
openssl x509 -noout -text 2>/dev/null | grep " DNS:" | \
python -c"import sys; print ', '.join([x.replace('DNS:', '').replace(',', '') for x in sys.stdin.readlines()[0].split()])"
输出:
*.google.com, *.android.com, <etc>
答案 9 :(得分:0)
也许这足够了:
openssl x509 -in cert.pem -noout -text -certopt ca_default,no_sigdump
答案 10 :(得分:0)
这是我们可以通过awk
执行此操作的方法。
'/Subject: C=/{printf $NF"\n"}
匹配具有模式/Subject: C=
的任何行,而{printf $NF"\n"}
仅用换行符打印最后一个字段。
/DNS:/{x=gsub(/ *DNS:/, ""); printf "SANS=" $0"\n"}
将行与模式DNS:
匹配。 gsub
用于在每个fqdn之前替换不需要的DNS:
。 printf "SANS="$0"\n"
用换行符打印整行。
➤ echo | openssl s_client -connect google.com:443 2>&1 | openssl x509 -noout -text | awk '/Subject: C=/{printf $NF"\n"} /DNS:/{x=gsub(/ *DNS:/, ""); printf "SANS=" $0"\n"}'
CN=*.google.com
SANS=*.google.com,*.android.com,*.appengine.google.com,*.cloud.google.com,*.crowdsource.google.com,*.g.co,*.gcp.gvt2.com,*.gcpcdn.gvt1.com,*.ggpht.cn,*.gkecnapps.cn,*.google-analytics.com,*.google.ca,*.google.cl,*.google.co.in,*.google.co.jp,*.google.co.uk,*.google.com.ar,*.google.com.au,*.google.com.br,*.google.com.co,*.google.com.mx,*.google.com.tr,*.google.com.vn,*.google.de,*.google.es,*.google.fr,*.google.hu,*.google.it,*.google.nl,*.google.pl,*.google.pt,*.googleadapis.com,*.googleapis.cn,*.googlecnapps.cn,*.googlecommerce.com,*.googlevideo.com,*.gstatic.cn,*.gstatic.com,*.gstaticcnapps.cn,*.gvt1.com,*.gvt2.com,*.metric.gstatic.com,*.urchin.com,*.url.google.com,*.wear.gkecnapps.cn,*.youtube-nocookie.com,*.youtube.com,*.youtubeeducation.com,*.youtubekids.com,*.yt.be,*.ytimg.com,android.clients.google.com,android.com,developer.android.google.cn,developers.android.google.cn,g.co,ggpht.cn,gkecnapps.cn,goo.gl,google-analytics.com,google.com,googlecnapps.cn,googlecommerce.com,source.android.google.cn,urchin.com,www.goo.gl,youtu.be,youtube.com,youtubeeducation.com,youtubekids.com,yt.be
➤