Ejemplo n.º 1
0
    def make_server_conn(tls_start: tls.TlsStartData) -> None:
        ssl_context = SSL.Context(SSL.SSLv23_METHOD)
        ssl_context.load_verify_locations(cafile=tlsdata.path(
            "../../net/data/verificationcerts/trusted-root.crt"))
        if alpn is not None:
            ssl_context.set_alpn_protos([alpn])
        ssl_context.set_verify(SSL.VERIFY_PEER)

        tls_start.ssl_conn = SSL.Connection(ssl_context)
        tls_start.ssl_conn.set_connect_state()
        # Set SNI
        tls_start.ssl_conn.set_tlsext_host_name(tls_start.conn.sni.encode())

        # Manually enable hostname verification.
        # Recent OpenSSL versions provide slightly nicer ways to do this, but they are not exposed in
        # cryptography and likely a PITA to add.
        # https://wiki.openssl.org/index.php/Hostname_validation
        param = SSL._lib.SSL_get0_param(tls_start.ssl_conn._ssl)
        # Common Name matching is disabled in both Chrome and Firefox, so we should disable it, too.
        # https://www.chromestatus.com/feature/4981025180483584
        SSL._lib.X509_VERIFY_PARAM_set_hostflags(
            param, SSL._lib.X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
            | SSL._lib.X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)
        SSL._openssl_assert(
            SSL._lib.X509_VERIFY_PARAM_set1_host(
                param, tls_start.conn.sni.encode(), 0) == 1)
Ejemplo n.º 2
0
def create_proxy_server_context(
    *,
    min_version: Version,
    max_version: Version,
    cipher_list: Optional[Iterable[str]],
    verify: Verify,
    sni: Optional[str],
    ca_path: Optional[str],
    ca_pemfile: Optional[str],
    client_cert: Optional[str],
    alpn_protos: Optional[Iterable[bytes]],
) -> SSL.Context:
    context: SSL.Context = _create_ssl_context(
        method=Method.TLS_CLIENT_METHOD,
        min_version=min_version,
        max_version=max_version,
        cipher_list=cipher_list,
    )

    if verify is not Verify.VERIFY_NONE and sni is None:
        raise ValueError("Cannot validate certificate hostname without SNI")

    context.set_verify(verify.value, None)
    if sni is not None:
        assert isinstance(sni, str)
        # Manually enable hostname verification on the context object.
        # https://wiki.openssl.org/index.php/Hostname_validation
        param = SSL._lib.SSL_CTX_get0_param(context._context)
        # Matching on the CN is disabled in both Chrome and Firefox, so we disable it, too.
        # https://www.chromestatus.com/feature/4981025180483584
        SSL._lib.X509_VERIFY_PARAM_set_hostflags(
            param, SSL._lib.X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
            | SSL._lib.X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)
        SSL._openssl_assert(
            SSL._lib.X509_VERIFY_PARAM_set1_host(param, sni.encode(), 0) == 1)

    if ca_path is None and ca_pemfile is None:
        ca_pemfile = certifi.where()
    try:
        context.load_verify_locations(ca_pemfile, ca_path)
    except SSL.Error as e:
        raise RuntimeError(
            f"Cannot load trusted certificates ({ca_pemfile=}, {ca_path=})."
        ) from e

    # Client Certs
    if client_cert:
        try:
            context.use_privatekey_file(client_cert)
            context.use_certificate_chain_file(client_cert)
        except SSL.Error as e:
            raise RuntimeError(
                f"Cannot load TLS client certificate: {e}") from e

    if alpn_protos is not None:
        # advertise application layer protocols
        context.set_alpn_protos(alpn_protos)

    return context
def create_client_context(
        cert: str = None,
        sni: str = None,
        address: str = None,
        verify: int = SSL.VERIFY_NONE,
        **sslctx_kwargs
) -> SSL.Context:
    """
    Args:
        cert: Path to a file containing both client cert and private key.
        sni: Server Name Indication. Required for VERIFY_PEER
        address: server address, used for expressive error messages only
        verify: A bit field consisting of OpenSSL.SSL.VERIFY_* values
    """

    if sni is None and verify != SSL.VERIFY_NONE:
        raise exceptions.TlsException("Cannot validate certificate hostname without SNI")

    def verify_callback(
            conn: SSL.Connection,
            x509: SSL.X509,
            errno: int,
            depth: int,
            is_cert_verified: bool
    ) -> bool:
        if is_cert_verified and depth == 0 and not sni:
            conn.cert_error = exceptions.InvalidCertificateException(
                f"Certificate verification error for {address}: Cannot validate hostname, SNI missing."
            )
            is_cert_verified = False
        elif is_cert_verified:
            pass
        else:
            conn.cert_error = exceptions.InvalidCertificateException(
                "Certificate verification error for {}: {} (errno: {}, depth: {})".format(
                    sni,
                    SSL._ffi.string(SSL._lib.X509_verify_cert_error_string(errno)).decode(),
                    errno,
                    depth
                )
            )

        # SSL_VERIFY_NONE: The handshake will be continued regardless of the verification result.
        return is_cert_verified

    context = _create_ssl_context(
        verify=verify,
        verify_callback=verify_callback,
        **sslctx_kwargs,
    )

    if sni:
        # Manually enable hostname verification on the context object.
        # https://wiki.openssl.org/index.php/Hostname_validation
        param = SSL._lib.SSL_CTX_get0_param(context._context)
        # Matching on the CN is disabled in both Chrome and Firefox, so we disable it, too.
        # https://www.chromestatus.com/feature/4981025180483584
        SSL._lib.X509_VERIFY_PARAM_set_hostflags(
            param,
            SSL._lib.X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS | SSL._lib.X509_CHECK_FLAG_NEVER_CHECK_SUBJECT
        )
        SSL._openssl_assert(
            SSL._lib.X509_VERIFY_PARAM_set1_host(param, sni.encode("idna"), 0) == 1
        )

    # Client Certs
    if cert:
        try:
            context.use_privatekey_file(cert)
            context.use_certificate_chain_file(cert)
        except SSL.Error as v:
            raise exceptions.TlsException("SSL client certificate error: %s" % str(v))
    return context