提问者:小点点

如何显示证书的使用者备用名称?


我找到的最接近的答案是使用“grep”。

> openssl x509 -text -noout -in cert.pem | grep DNS

有没有更好的方法可以做到这一点?我只喜欢命令行。

谢谢。


共3个答案

匿名用户

请注意,您可以通过添加以下选项将 -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