def get_certificate_chain(host: str, port: int) -> List[str]:

    """ Connect to the host on the port and obtain certificate chain.
     TODO: Tests against WantReadError and WantX509LookupError needed. """

    cert_chain = []

    soc = socket(AF_INET, SOCK_STREAM, proto=0)
    soc.settimeout(3)

    try:
        soc.connect((host, port))

    except gaierror:
        raise Exception(f"{host}:{port} is invalid or not known.") from None

    except timeout:
        raise Exception(f"Connection to {host}:{port} timed out.") from None

    except OverflowError:
        raise Exception(f"Illegal port: {port}. Port must be between 0-65535.") from None

    except TypeError:
        raise Exception(f"Illegal port: {port}. Port must be between 0-65535.") from None

    ssl_client = SslClient(
        ssl_version=OpenSslVersionEnum.SSLV23,
        underlying_socket=soc,
        ssl_verify=OpenSslVerifyEnum.NONE
    )

    # Add Server Name Indication (SNI) extension to the CLIENT HELLO
    ssl_client.set_tlsext_host_name(host)

    try:
        ssl_client.do_handshake()
        cert_chain = ssl_client.get_received_chain()

    except WantReadError as err:
        raise ValueError(err.strerror) from None

    except WantX509LookupError as err:
        raise ValueError(err.strerror) from None

    except OpenSSLError as err:
        raise ValueError(err) from None

    finally:
        ssl_client.shutdown()
        soc = None

    return cert_chain
Exemple #2
0
def get_certificate_chain(host: str, port: int) -> List[str]:
    """Connect to the host on the port and obtain certificate chain"""

    func_name: str = "get_certificate_chain"

    cert_chain: list = []

    soc = socket(AF_INET, SOCK_STREAM, proto=0)
    soc.settimeout(3)

    try:
        soc.connect((host, port))

    except gaierror:
        raise Exception(
            f"{func_name}: {host}:{port} is invalid or not known.") from None

    except timeout:
        raise Exception(
            f"{func_name}: Connection to {host}:{port} timed out.") from None

    except (OverflowError, TypeError):
        raise Exception(
            f"{func_name}: Illegal port: {port}. Port must be between 0-65535."
        ) from None

    except ConnectionRefusedError:
        raise Exception(
            f"{func_name}: Connection to {host}:{port} refused.") from None

    ssl_client = SslClient(
        ssl_version=OpenSslVersionEnum.SSLV23,
        underlying_socket=soc,
        ssl_verify=OpenSslVerifyEnum.NONE,
    )

    # Add Server Name Indication (SNI) extension to the Client Hello
    ssl_client.set_tlsext_host_name(host)

    try:
        ssl_client.do_handshake()
        cert_chain = ssl_client.get_received_chain()

    except IOError as err:
        raise ValueError(
            f"{func_name}: {host} did not respond to the Client Hello."
        ) from None

    except (WantReadError, WantX509LookupError) as err:
        raise ValueError(f"{func_name}: {err.strerror}") from None

    except OpenSSLError as err:
        if "1408F10B" in err.args[0]:
            # https://github.com/openssl/openssl/issues/6805
            raise ValueError(
                f"{func_name}: Remote host is not using SSL/TLS on port: {port}"
            ) from None

        raise ValueError(f"{func_name}: {err}") from None

    finally:
        # shutdown() will also close the underlying socket
        ssl_client.shutdown()

    return cert_chain