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
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()
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)
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
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)
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
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
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)
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)