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()

#### Example
$ 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