How to display the Subject Alternative Name of a certificate?
Note that you can limit the output of -text
to just the extensions by adding the following option:
-certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux
i.e.:
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
However, you'll still need to apply some text parsing logic to get just the Subject Alternative Name
.
If that isn't sufficient, I think you'll need to write a small program that uses the openssl library to extract the specific field you are looking for. Here are some example programs that show how to parse a cert, including extracting extension fields such as Subject Alternative Name
:
https://zakird.com/2013/10/13/certificate-parsing-with-openssl
Note that you don't have to use openssl and C if you go the programming route... you can pick your favorite language and ASN.1
parser library, and use that. For example, in Java, you could use http://jac-asn1.sourceforge.net/, and many others.
Fetch Certificate Data
With gnutls
and certtool
$ gnutls-cli example.com -p 443 --print-cert < /dev/null | certtool -i | grep -C3 -i dns
With openssl
Taken from https://stackoverflow.com/a/13128918/1695680
$ openssl s_client -connect example.com:443 < /dev/null | openssl x509 -noout -text | grep -C3 -i dns
Extracting Certificate Data
| grep -C3 -i dns
works for a simple-case, if your reviewing this data by hand sure works well enough. However certificate data is hierarchical, not line-oriented (so greping will be messy, particularly for ca chains).
I don't know of any x509 command line tools that can do key-value extraction, most systems I work with have python on-box or nearby so here is an approach using python, x509 interface provided by cryptography
on pypi. Using cryptography
is a little verbose, I didn't feel comfortable condensing this into a oneliner, but with this script you can extract dns names from certificates passed to stdin
#!/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
Newer versions of openssl have an '-ext' option that allows you to print only the subjectAltName record. Am using 'OpenSSL 1.1.1b' on Debian 9.9
openssl x509 -noout -ext subjectAltName -in cert.pem
Though you'll still need to parse the output.
The change was made in https://github.com/openssl/openssl/issues/3932