Return information for a particular certificate

    cert
        path to the certifiate PEM file or string

        .. versionchanged:: 2018.3.4

    digest
        what digest to use for fingerprinting

    CLI Example:

    .. code-block:: bash

        salt '*' tls.cert_info /dir/for/certs/cert.pem

def cert_info(cert, digest='sha256'):
    '''
    Return information for a particular certificate

    cert
        path to the certifiate PEM file or string

        .. versionchanged:: 2018.3.4

    digest
        what digest to use for fingerprinting

    CLI Example:

    .. code-block:: bash

        salt '*' tls.cert_info /dir/for/certs/cert.pem

    '''
    # format that OpenSSL returns dates in
    date_fmt = '%Y%m%d%H%M%SZ'
    if '-----BEGIN' not in cert:
        with salt.utils.files.fopen(cert) as cert_file:
            cert = cert_file.read()
    cert = OpenSSL.crypto.load_certificate(
        OpenSSL.crypto.FILETYPE_PEM,
        cert
    )

    issuer = {}
    for key, value in cert.get_issuer().get_components():
        if isinstance(key, bytes):
            key = salt.utils.stringutils.to_unicode(key)
        if isinstance(value, bytes):
            value = salt.utils.stringutils.to_unicode(value)
        issuer[key] = value

    subject = {}
    for key, value in cert.get_subject().get_components():
        if isinstance(key, bytes):
            key = salt.utils.stringutils.to_unicode(key)
        if isinstance(value, bytes):
            value = salt.utils.stringutils.to_unicode(value)
        subject[key] = value

    ret = {
        'fingerprint': salt.utils.stringutils.to_unicode(
            cert.digest(salt.utils.stringutils.to_str(digest))
            ),
        'subject': subject,
        'issuer': issuer,
        'serial_number': cert.get_serial_number(),
        'not_before': calendar.timegm(time.strptime(
            str(cert.get_notBefore().decode(__salt_system_encoding__)),
            date_fmt)),
        'not_after': calendar.timegm(time.strptime(
            cert.get_notAfter().decode(__salt_system_encoding__),
            date_fmt)),
    }

    # add additional info if your version of pyOpenSSL supports it
    if hasattr(cert, 'get_extension_count'):
        ret['extensions'] = {}
        for i in _range(cert.get_extension_count()):
            try:
                ext = cert.get_extension(i)
                key = salt.utils.stringutils.to_unicode(ext.get_short_name())
                ret['extensions'][key] = str(ext).strip()
            except AttributeError:
                continue

    if 'subjectAltName' in ret.get('extensions', {}):
        valid_entries = ('DNS', 'IP Address')
        valid_names = set()
        for name in str(ret['extensions']['subjectAltName']).split(', '):
            entry, name = name.split(':', 1)
            if entry not in valid_entries:
                log.error('Cert %s has an entry (%s) which does not start '
                          'with %s', ret['subject'], name, '/'.join(valid_entries))
            else:
                valid_names.add(name)
        ret['subject_alt_names'] = list(valid_names)

    if hasattr(cert, 'get_signature_algorithm'):
        try:
            value = cert.get_signature_algorithm()
            if isinstance(value, bytes):
                value = salt.utils.stringutils.to_unicode(value)
            ret['signature_algorithm'] = value
        except AttributeError:
            # On py3 at least
            # AttributeError: cdata 'X509 *' points to an opaque type: cannot read fields
            pass

    return ret