我找到的最接近的答案是使用“grep”。
> openssl x509 -text -noout -in cert.pem | grep DNS
有没有更好的方法可以做到这一点?我只喜欢命令行。
谢谢。
请注意,您可以通过添加以下选项将 -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
但是,您仍然需要应用一些文本分析逻辑来仅获取主题备用名称
。
如果这还不够,我认为您需要编写一个小程序,该程序使用 openssl 库来提取您正在寻找的特定字段。下面是一些示例程序,演示如何解析证书,包括提取扩展字段,如主题备用名称
:
https://zakird.com/2013/10/13/certificate-parsing-with-openssl
请注意,如果您采用编程路线,则不必使用 openssl 和 C...您可以选择自己喜欢的语言和 ASN.1
解析器库,然后使用它。例如,在Java中,您可以使用 http://jac-asn1.sourceforge.net/ 和许多其他方法。
较新版本的openssl有一个“-ext”选项,允许您仅打印subjectAltName记录。我在 Debian 9.9 上使用 'OpenSSL 1.1.1b'
openssl x509 -noout -ext subjectAltName -in cert.pem
尽管您仍然需要解析输出。
更改是在 https://github.com/openssl/openssl/issues/3932 中进行的
$ gnutls-cli example.com -p 443 --print-cert < /dev/null | certtool -i | grep -C3 -i dns
取自 https://stackoverflow.com/a/13128918/1695680
$ openssl s_client -connect example.com:443 < /dev/null | openssl x509 -noout -text | grep -C3 -i dns
| grep -C3 -i dns
适用于简单情况,如果您手动查看此数据确实足够好。但是,证书数据是分层的,而不是面向行的(因此greping会很混乱,特别是对于ca链)。
我不知道有任何 x509 命令行工具可以进行键值提取,我使用的大多数系统都有 python 在盒子上或附近,所以这里有一种使用 python、pypi 上的加密
提供的 x509 接口的方法。使用加密
有点冗长,我不习惯将其压缩成一行,但是使用此脚本,您可以从传递给 stdin 的证书中提取 dns 名称
#!/usr/bin/env python3
import sys
import cryptography.x509
import cryptography.hazmat.backends
import cryptography.hazmat.primitives
DEFAULT_FINGERPRINT_HASH = cryptography.hazmat.primitives.hashes.SHA256
def _x509_san_dns_names(certificate):
""" Return a list of strings containing san dns names
"""
crt_san_data = certificate.extensions.get_extension_for_oid(
cryptography.x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME
)
dns_names = crt_san_data.value.get_values_for_type(
cryptography.x509.DNSName
)
return dns_names
def _find_certificate_pem(stream):
""" Yield hunks of pem certificates
"""
certificate_pem = []
begin_certificate = False
for line in stream:
if line == b'-----END CERTIFICATE-----\n':
begin_certificate = False
certificate_pem.append(line)
yield b''.join(certificate_pem)
certificate_pem = []
if line == b'-----BEGIN CERTIFICATE-----\n':
begin_certificate = True
if begin_certificate:
certificate_pem.append(line)
def _dump_stdincert_san_dnsnames():
""" Print line-oriented certificate fingerprint and san dns name
"""
for certificate_pem in _find_certificate_pem(sys.stdin.buffer):
certificate = cryptography.x509.load_pem_x509_certificate(
certificate_pem,
cryptography.hazmat.backends.default_backend()
)
certificate_fingerprint = certificate.fingerprint(
DEFAULT_FINGERPRINT_HASH(),
)
certificate_fingerprint_str = ':'.join(
'{:02x}'.format(i) for i in certificate_fingerprint
)
try:
for dns_name in _x509_san_dns_names(certificate):
sys.stdout.write('{} {}\n'.format(certificate_fingerprint_str, dns_name))
except cryptography.x509.extensions.ExtensionNotFound:
sys.stderr.write('{} Certificate has no extension SubjectAlternativeName\n'.format(certificate_fingerprint_str))
def main():
_dump_stdincert_san_dnsnames()
if __name__ == '__main__':
main()
$ 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