有没有一种编程方式可以检查SAN SSL证书的替代名称(Subject Alternative Names)?
例如,使用以下命令可以获取许多信息,但不包括所有SAN:
openssl s_client -connect www.website.example:443
有没有一种编程方式可以检查SAN SSL证书的替代名称(Subject Alternative Names)?
例如,使用以下命令可以获取许多信息,但不包括所有SAN:
openssl s_client -connect www.website.example:443
要获取证书的主题备用名称(SAN),请使用以下命令:
openssl s_client -connect website.example:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep DNS:
首先,该命令连接到我们需要的站点(website.example
,端口443用于SSL):
openssl s_client -connect website.example:443
然后将其导入到以下命令中(使用 |
):
openssl x509 -noout -text
此命令将证书文件作为输入并输出所有有趣的细节。 -noout
标志可防止它输出(base64编码的)证书文件本身,因为我们不需要它。 -text
标志告诉它以文本形式输出证书详细信息。
通常会有大量输出(签名、发行者、扩展等)我们不关心,因此将其导入到一个简单的grep中:
grep DNS:
由于SAN条目以 DNS:
开始,因此这只返回包含该行的行,剥离了所有其他信息,使我们获得所需的信息。
您可能会注意到,该命令没有干净地退出;openssl s_client
实际上充当客户端并保持连接打开,等待输入。 如果您想要立即退出它(例如在shell脚本中解析输出),只需将echo
导入其中:
echo | openssl s_client -connect website.example:443 | openssl x509 -noout -text | grep DNS:
为此,您不需要使用openssl s_client
命令。只需在openssl x509
命令上添加-in MyCertificate.crt
,然后再次通过grep管道筛选,例如:
openssl x509 -noout -text -in MyCertificate.crt | grep DNS:
echo | openssl s_client -servername www.website.com -connect sameserver.website.com:443 | openssl x509 -noout -text | grep DNS
- B. Shea也可以使用捆绑的 OpenSSL 功能:
openssl s_client -connect website.example:443 </dev/null | openssl x509 -noout -ext subjectAltName
x509
-ext
参数至少需要 OpenSSL 1.1.1p 版本才能使用。请注意,某些网站需要在 s_client
请求中提供 SNI,通过 -servername
参数,例如:openssl s_client -connect website.example:443 -servername website.example </dev/null | openssl x509 -noout -ext subjectAltName
- user310346true | openssl s_client -connect example.com:443 2>/dev/null \
| openssl x509 -noout -text \
| perl -l -0777 -ne '@names=/\bDNS:([^\s,]+)/g; print join("\n", sort @names);'
这将输出:
example.com
example.edu
example.net
example.org
www.example.com
www.example.edu
www.example.net
www.example.org
所以你可以将其引导到 while read name; do echo "do stuff with $name"; done
等等。
或者对于一行上的逗号分隔列表,用 join(",",
替换 join("\n",
。
(perl 的 -0777
开关使其一次性读取整个输入而不是逐行读取)
SSL_get_peer_certificate
)、从内存中的d2i_X509
或从文件系统中的PEM_read_bio_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);
}
就像有人只会得到一行一个的SAN列表:
openssl x509 -noout -text -in "${CERT_FILE}" | grep -Po 'DNS:\K[^,]+'
最好的祝福,