Ssl 如何显示证书的主题替代名称?
我找到的最接近的答案是使用“grep” 有没有更好的办法?我只喜欢命令行Ssl 如何显示证书的主题替代名称?,ssl,openssl,certificate,ssl-certificate,x509certificate,sed,bash,shell,Ssl,Openssl,Certificate,Ssl Certificate,X509certificate,Sed,Bash,Shell,我找到的最接近的答案是使用“grep” 有没有更好的办法?我只喜欢命令行 谢谢。请注意,您可以通过添加以下选项将-text的输出限制为仅输出扩展名: -certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux i、 e: 但是,您仍然需要应用一些文本解析逻辑,以仅获取主题备选名称 如果这还不够,我认为您需要编写一个小程序,使用ope
谢谢。请注意,您可以通过添加以下选项将
-text
的输出限制为仅输出扩展名:
-certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux
i、 e:
但是,您仍然需要应用一些文本解析逻辑,以仅获取主题备选名称
如果这还不够,我认为您需要编写一个小程序,使用openssl库提取您要查找的特定字段。下面是一些示例程序,演示如何解析证书,包括提取扩展字段,如主题备选名称
:
请注意,如果按照编程路线进行,则不必使用openssl和C。。。您可以选择您喜欢的语言和
ASN.1
解析器库,并使用它。例如,在Java中,您可以使用,以及许多其他工具。您可以使用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/'
获取证书数据
使用gnutls
和certtool
$gnutls cli example.com-p 443--打印证书
使用openssl
取自
$openssl s|u client-connect example.com:443
提取证书数据
| grep-C3-idns
适用于一个简单的情况,如果您手工查看这些数据,肯定可以很好地工作。然而,证书数据是分层的,而不是面向行的(因此灰色化将是混乱的,尤其是对于ca链)
我不知道有任何x509命令行工具可以进行键值提取,我使用的大多数系统都在box上或附近有python,因此这里有一种使用python的方法,x509接口由提供。使用cryptography
有点冗长,我不愿意将其压缩成一行代码,但使用此脚本,您可以从传递给stdin的证书中提取dns名称
#/usr/bin/env蟒蛇3
导入系统
导入cryptography.x509
导入加密。hazmat。后端
导入加密.hazmat.primitives
默认\u指纹\u哈希=cryptography.hazmat.primitives.hashes.SHA256
def_x509_san_dns_名称(证书):
“”“返回包含san dns名称的字符串列表
"""
crt_san_data=certificate.extensions.get_extension_for_oid(
cryptography.x509.oid.extensionId.SUBJECT\u可选\u名称
)
dns_name=crt_san_data.value.get_values_for_type(
cryptography.x509.DNSName
)
返回dns\u名称
def\u查找\u证书\u pem(流):
“产生大量pem证书
"""
证书\u pem=[]
开始证书=错误
对于流中的行:
如果行==b'----结束证书------\n':
开始证书=错误
证书附录(第行)
产生b“”。加入(证书\u pem)
证书\u pem=[]
如果行==b'----开始证书------\n':
begin\u certificate=True
如果是begin\U证书:
证书附录(第行)
定义转储标准证书存储系统():
“”“打印面向行的证书指纹和san dns名称
"""
对于查找证书中的证书(sys.stdin.buffer):
证书=cryptography.x509.load\u pem\u x509\u证书(
pem证书,
cryptography.hazmat.backends.default_backend()
)
证书\指纹=证书。指纹(
默认\u指纹\u哈希(),
)
证书\u指纹\u str=':'。加入(
“{:02x}”。证书中i的格式(i)
)
尝试:
对于_x509_san_dns_名称(证书)中的dns_名称:
sys.stdout.write('{}{}\n'.格式(证书\u指纹\u str,dns\u名称))
除了cryptography.x509.extensions.ExtensionNotFound之外:
sys.stderr.write({}证书没有扩展名SubjectAlternativeName\n'。格式(证书\u指纹\u str))
def main():
_dump_stdincert_san_dnsnames()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
####范例
$true | openssl s|U客户端-连接本地主机:8443 | openssl x509-noout-text | grep DNS:
深度=2 C=US,ST=NC,L=SomeCity,O=SomeCompany Security,OU=SomeOU,CN=SomeCN
验证错误:num=19:证书链中的自签名证书
完成
DNS:localhost,DNS:127.0.0.1,DNS:servername1.somedom.com,DNS:servername2.somedom.local
如何显示证书的主题替代名称
X509证书中可能有多个SAN。以下内容来自位于的OpenSSL wiki。它在名字上循环并打印出来
您可以从TLS连接的SSL\u get\u peer\u certificate
、内存的d2i\u X509
或文件系统的PEM\u read\u bio\u X509
等函数中获取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);
}
void print\u san\u name(常量字符*标签,X509*常量证书)
{
int成功=0;
通用名称*名称=空;
无符号字符*utf8=NULL;
做
{
如果(!cert)中断;/*失败*/
name=X509\u get\u ext\u d2i(证书,NID\u主题\u alt\u名称,0,0);
如果(!name)中断;
int i=0,count=sk\u GENERAL\u NAME\u num(名称);
如果(!count)中断;/*失败*/
对于(i=0;i类型)
{
int len1=0,len2=-1;
len1=ASN1\u字符串到\u UTF8(&UTF8,条目->d.dNSName);
如果(utf8){
len2=(int)strlen((const char*)utf8);
}
if(len1!=len2){
fprintf(strerr,“Strlen和ASN1_字符串大小不匹配(嵌入null?)%d vs
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/'
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);
}
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
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; }'
openssl x509 -in /path/to/x509/cert -noout -text|grep -oP '(?<=DNS:|IP Address:)[^,]+'|sort -uV
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
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}'
android.clients.google.com
android.com
developer.android.google.cn
g.co
goo.gl
...
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>
openssl x509 -noout -ext subjectAltName -in cert.pem
➤ 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
➤