Ejemplo n.º 1
0
    def test_tcp(self):
        n = self.pathod("304")
        self._tcpproxy_on()
        i = self.pathod("305")
        i2 = self.pathod("306")
        self._tcpproxy_off()

        assert n.status_code == 304
        assert i.status_code == 305
        assert i2.status_code == 306
        assert any(f.response.status_code == 304
                   for f in self.master.state.flows
                   if isinstance(f, http.HTTPFlow))
        assert not any(f.response.status_code == 305
                       for f in self.master.state.flows
                       if isinstance(f, http.HTTPFlow))
        assert not any(f.response.status_code == 306
                       for f in self.master.state.flows
                       if isinstance(f, http.HTTPFlow))

        # Test that we get the original SSL cert
        if self.ssl:
            i_cert = certs.Cert(i.sslinfo.certchain[0])
            i2_cert = certs.Cert(i2.sslinfo.certchain[0])
            n_cert = certs.Cert(n.sslinfo.certchain[0])

            assert i_cert == i2_cert
            assert i_cert != n_cert
Ejemplo n.º 2
0
    def test_ignore(self):
        n = self.pathod("304")
        self._ignore_on()
        i = self.pathod("305")
        i2 = self.pathod("306")
        self._ignore_off()

        assert n.status_code == 304
        assert i.status_code == 305
        assert i2.status_code == 306
        assert any(f.response.status_code == 304
                   for f in self.master.state.flows)
        assert not any(f.response.status_code == 305
                       for f in self.master.state.flows)
        assert not any(f.response.status_code == 306
                       for f in self.master.state.flows)

        # Test that we get the original SSL cert
        if self.ssl:
            i_cert = certs.Cert(i.sslinfo.certchain[0])
            i2_cert = certs.Cert(i2.sslinfo.certchain[0])
            n_cert = certs.Cert(n.sslinfo.certchain[0])

            assert i_cert == i2_cert
            assert i_cert != n_cert

        # Test Non-HTTP traffic
        spec = "200:i0,@100:d0"  # this results in just 100 random bytes
        # mitmproxy responds with bad gateway
        assert self.pathod(spec).status_code == 502
        self._ignore_on()
        with pytest.raises(exceptions.HttpException):
            self.pathod(spec)  # pathoc tries to parse answer as HTTP

        self._ignore_off()
Ejemplo n.º 3
0
    def convert_to_tls(self, sni=None, alpn_protos=None, **sslctx_kwargs):
        context = tls.create_client_context(
            alpn_protos=alpn_protos,
            sni=sni,
            **sslctx_kwargs
        )
        self.connection = SSL.Connection(context, self.connection)
        if sni:
            self.sni = sni
            self.connection.set_tlsext_host_name(sni.encode("idna"))
        self.connection.set_connect_state()
        try:
            self.connection.do_handshake()
        except SSL.Error as v:
            if self.ssl_verification_error:
                raise self.ssl_verification_error
            else:
                raise exceptions.TlsException("SSL handshake error: %s" % repr(v))

        self.cert = certs.Cert(self.connection.get_peer_certificate())

        # Keep all server certificates in a list
        for i in self.connection.get_peer_cert_chain():
            self.server_certs.append(certs.Cert(i))

        self.tls_established = True
        self.rfile.set_descriptor(self.connection)
        self.wfile.set_descriptor(self.connection)
Ejemplo n.º 4
0
    def receive_handshake_data(
            self,
            data: bytes) -> layer.CommandGenerator[Tuple[bool, Optional[str]]]:
        # bio_write errors for b"", so we need to check first if we actually received something.
        if data:
            self.tls.bio_write(data)
        try:
            self.tls.do_handshake()
        except SSL.WantReadError:
            yield from self.tls_interact()
            return False, None
        except SSL.Error as e:
            # provide more detailed information for some errors.
            last_err = e.args and isinstance(
                e.args[0], list) and e.args[0] and e.args[0][-1]
            if last_err == ('SSL routines', 'tls_process_server_certificate',
                            'certificate verify failed'):
                verify_result = SSL._lib.SSL_get_verify_result(self.tls._ssl)
                error = SSL._ffi.string(
                    SSL._lib.X509_verify_cert_error_string(
                        verify_result)).decode()
                err = f"Certificate verify failed: {error}"
            elif last_err in [('SSL routines', 'ssl3_read_bytes',
                               'tlsv1 alert unknown ca'),
                              ('SSL routines', 'ssl3_read_bytes',
                               'sslv3 alert bad certificate')]:
                assert isinstance(last_err, tuple)
                err = last_err[2]
            elif last_err == ('SSL routines', 'ssl3_get_record',
                              'wrong version number') and data[:4].isascii():
                err = f"The remote server does not speak TLS."
            else:  # pragma: no cover
                # TODO: Add test case one we find one.
                err = f"OpenSSL {e!r}"
            return False, err
        else:
            # Get all peer certificates.
            # https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_cert_chain.html
            # If called on the client side, the stack also contains the peer's certificate; if called on the server
            # side, the peer's certificate must be obtained separately using SSL_get_peer_certificate(3).
            all_certs = self.tls.get_peer_cert_chain() or []
            if self.conn == self.context.client:
                cert = self.tls.get_peer_certificate()
                if cert:
                    all_certs.insert(0, cert)

            self.conn.timestamp_tls_setup = time.time()
            self.conn.sni = self.tls.get_servername()
            self.conn.alpn = self.tls.get_alpn_proto_negotiated()
            self.conn.certificate_list = [certs.Cert(x) for x in all_certs]
            self.conn.cipher = self.tls.get_cipher_name()
            self.conn.cipher_list = self.tls.get_cipher_list()
            self.conn.tls_version = self.tls.get_protocol_version_name()
            if self.debug:
                yield commands.Log(
                    f"{self.debug}[tls] tls established: {self.conn}", "debug")
            yield from self.receive_data(b"")
            return True, None
Ejemplo n.º 5
0
    def convert_to_tls(self, sni=None, alpn_protos=None, **sslctx_kwargs):
        context = tls.create_client_context(alpn_protos=alpn_protos,
                                            sni=sni,
                                            **sslctx_kwargs)
        self.connection = SSL.Connection(context, self.connection)
        if sni:
            self.sni = sni
            self.connection.set_tlsext_host_name(sni.encode("idna"))
        self.connection.set_connect_state()
        try:
            idle_timeout = self.connection_idle_seconds
            if idle_timeout != -1:
                timeout = idle_timeout
            else:
                timeout = 60
            if self.channel is not None:
                self.channel.ask("ssl_handshake_started", self)
            TimeoutHelper.wrap_with_timeout(self.connection.do_handshake,
                                            timeout)
        except SSL.Error as v:
            if self.ssl_verification_error:
                raise self.ssl_verification_error
            else:
                raise exceptions.TlsException("SSL handshake error: %s" %
                                              repr(v))
        finally:
            if self.channel is not None:
                self.channel.ask("ssl_handshake_finished", self)

        self.cert = certs.Cert(self.connection.get_peer_certificate())

        # Keep all server certificates in a list
        for i in self.connection.get_peer_cert_chain():
            self.server_certs.append(certs.Cert(i))

        self.tls_established = True
        self.rfile.set_descriptor(self.connection)
        self.wfile.set_descriptor(self.connection)
Ejemplo n.º 6
0
    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:
            # Verify hostname of leaf certificate.
            cert = certs.Cert(x509)
            try:
                crt: typing.Dict[str, typing.Any] = dict(
                    subjectAltName=[("DNS", x.decode("ascii", "strict")) for x in cert.altnames]
                )
                if cert.cn:
                    crt["subject"] = [[["commonName", cert.cn.decode("ascii", "strict")]]]
                if sni:
                    # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding
                    # Conversion algorithm is in RFC 3490 which is implemented by idna codec
                    # https://docs.python.org/3/library/codecs.html#text-encodings
                    # https://tools.ietf.org/html/rfc6066#section-3
                    # https://tools.ietf.org/html/rfc4985#section-3
                    hostname = sni.encode("idna").decode("ascii")
                else:
                    hostname = "no-hostname"
                match_hostname(crt, hostname)
            except (ValueError, CertificateError) as e:
                conn.cert_error = exceptions.InvalidCertificateException(
                    "Certificate verification error for {}: {}".format(
                        sni or repr(address),
                        str(e)
                    )
                )
                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
Ejemplo n.º 7
0
    def test_state(self, tdata):
        with open(tdata.path("mitmproxy/net/data/text_cert"), "rb") as f:
            d = f.read()
        c = certs.Cert.from_pem(d)

        c.get_state()
        c2 = c.copy()
        a = c.get_state()
        b = c2.get_state()
        assert a == b
        assert c == c2
        assert c is not c2

        x = certs.Cert('')
        x.set_state(a)
        assert x == c
Ejemplo n.º 8
0
 def __str__(self):
     parts = [
         "Application Layer Protocol: %s" % strutils.always_str(self.alp, "utf8"),
         "Cipher: %s, %s bit, %s" % self.cipher,
         "SSL certificate chain:"
     ]
     for n, i in enumerate(self.certchain):
         parts.append("  Certificate [%s]" % n)
         parts.append("\tSubject: ")
         for cn in i.get_subject().get_components():
             parts.append("\t\t%s=%s" % (
                 strutils.always_str(cn[0], "utf8"),
                 strutils.always_str(cn[1], "utf8"))
             )
         parts.append("\tIssuer: ")
         for cn in i.get_issuer().get_components():
             parts.append("\t\t%s=%s" % (
                 strutils.always_str(cn[0], "utf8"),
                 strutils.always_str(cn[1], "utf8"))
             )
         parts.extend(
             [
                 "\tVersion: %s" % i.get_version(),
                 "\tValidity: %s - %s" % (
                     strutils.always_str(i.get_notBefore(), "utf8"),
                     strutils.always_str(i.get_notAfter(), "utf8")
                 ),
                 "\tSerial: %s" % i.get_serial_number(),
                 "\tAlgorithm: %s" % strutils.always_str(i.get_signature_algorithm(), "utf8")
             ]
         )
         pk = i.get_pubkey()
         types = {
             OpenSSL.crypto.TYPE_RSA: "RSA",
             OpenSSL.crypto.TYPE_DSA: "DSA"
         }
         t = types.get(pk.type(), "Uknown")
         parts.append("\tPubkey: %s bit %s" % (pk.bits(), t))
         s = certs.Cert(i)
         if s.altnames:
             parts.append("\tSANs: %s" % " ".join(strutils.always_str(n, "utf8") for n in s.altnames))
     return "\n".join(parts)
Ejemplo n.º 9
0
    def convert_to_tls(self, cert, key, **sslctx_kwargs):
        """
        Convert connection to SSL.
        For a list of parameters, see tls.create_server_context(...)
        """

        context = tls.create_server_context(cert=cert,
                                            key=key,
                                            **sslctx_kwargs)
        self.connection = SSL.Connection(context, self.connection)
        self.connection.set_accept_state()
        try:
            self.connection.do_handshake()
        except SSL.Error as v:
            raise exceptions.TlsException("SSL handshake error: %s" % repr(v))
        self.tls_established = True
        cert = self.connection.get_peer_certificate()
        if cert:
            self.clientcert = certs.Cert(cert)
        self.rfile.set_descriptor(self.connection)
        self.wfile.set_descriptor(self.connection)