Exemple #1
0
    def parse_certs_cell(self, cell):
        circid, cell_content = self.decode_circid(cell)

        if circid != 0 or cell_content[0] != COMMAND_CERTS:
            raise ORError("Malformed CERTS cell")

        cert_num = struct.unpack("!B", cell_content[3])[0]
        cell_content = cell_content[4:]
        certs = []

        for _ in range(cert_num):
            if len(cell_content) < 3:
                raise ORError("Malformed CERTS cell")

            cert_type = struct.unpack("!B", cell_content[0])[0]
            length = struct.unpack("!H", cell_content[1:3])[0]

            if len(cell_content) < length + 3:
                raise ORError("Malformed CERTS cell")

            certs.append((cert_type, cell_content[3:length + 3]))

            cell_content = cell_content[length + 3:]

        return certs
Exemple #2
0
    def read_from_conn(self):
        data = self.conn.recv(4096)

        if not data:
            raise ORError("Connection is closed")

        self.buf += data
Exemple #3
0
    def add_circid(self, circid, content):
        if self.circid_len == 2:
            packed_circid = struct.pack("!H", circid)
        elif self.circid_len == 4:
            packed_circid = struct.pack("!I", circid)
        else:
            raise ORError("Unsupported CircID length")

        return packed_circid + content
Exemple #4
0
    def parse_versions_cell(self, cell):
        circid, cell_content = self.decode_circid(cell)

        if circid != 0 or cell_content[0] != COMMAND_VERSIONS:
            raise ORError("Malformed VERSIONS cell")

        cell_content = cell_content[3:]

        if len(cell_content) % 2 != 0:
            raise ORError("Malformed VERSIONS cell")

        versions = []

        for i in range(len(cell_content) / 2):
            versions.append(
                struct.unpack("!H", cell_content[i * 2:i * 2 + 2])[0])

        return versions
Exemple #5
0
    def process_versions_cell(self, versions_cell):
        versions = self.parse_versions_cell(versions_cell)

        common_versions = set(versions) & self.our_versions

        if not common_versions:
            raise ORError("Unable to negotiate a common version")

        self.version = max(common_versions)

        if self.version >= 4:
            self.circid_len = 4
        else:
            self.circid_len = 2
Exemple #6
0
def encrypt_onion_skin(content_no_digest, key, direction='f'):
    if direction == 'f':
        Dfunc = key.Dffunc
        Kfunc = key.Kffunc
    elif direction == 'b':
        Dfunc = key.Dbfunc
        Kfunc = key.Kbfunc
    else:
        raise ORError("Unrecognized direction {}".format(direction))

    Dfunc.update(content_no_digest)
    digest = Dfunc.digest()[:4]
    content = content_no_digest[0:5] + digest + content_no_digest[9:]
    payload = Kfunc.encrypt(content)

    return payload
Exemple #7
0
    def decode_circid(self, cell):
        if not self.circid_len:
            circid_len = 2
        else:
            circid_len = self.circid_len

        if circid_len == 2:
            circid = struct.unpack("!H", cell[:circid_len])[0]
        elif circid_len == 4:
            circid = struct.unpack("!I", cell[:circid_len])[0]
        else:
            raise ORError("Unsupported CircID length")

        cell_content = cell[circid_len:]

        return (circid, cell_content)
Exemple #8
0
    def relay_forward(self, circid, cell_content):
        with self.lock:
            if circid not in self.circuits_client:
                return (FINISHED,
                        self.client_or_conn.destroy_cell(
                            circid, ERROR_DESTROYED), None)

            if circid not in self.map_client_to_server:
                self.destroy(circid)
                return (FINISHED,
                        self.client_or_conn.destroy_cell(
                            circid, ERROR_DESTROYED), None)

            circid_server = self.map_client_to_server[circid]

            if circid_server not in self.circuits_server:
                self.destroy(circid)
                return (FINISHED,
                        self.client_or_conn.destroy_cell(
                            circid, ERROR_DESTROYED), None)

            key_client = self.circuits_client[circid]
            key_server = self.circuits_server[circid_server]

        command = cell_content[0]
        payload = cell_content[1:]

        content = key_client.Kffunc.decrypt(payload)

        if content[1:3] != "\x00\x00":  # not recognized
            new_payload = key_server.Kffunc.encrypt(content)
            return (FINISHED, None,
                    self.server_or_conn.add_circid(circid_server,
                                                   command + new_payload))

        temp_Dffunc = key_client.Dffunc.copy()

        cell_digest = content[5:9]
        content_no_digest = content[0:5] + "\x00\x00\x00\x00" + content[9:]

        temp_Dffunc.update(content_no_digest)
        computed_digest = temp_Dffunc.digest()[:4]

        if cell_digest == computed_digest:  # recognized
            key_client.Dffunc = temp_Dffunc

            streamid = struct.unpack("!H", content[3:5])[0]

            if content[0] == RELAY_DATA and key_client.has_dir_stream(
                    streamid):
                length = struct.unpack("!H", content[9:11])[0]

                if length > MAX_DATA_LEN:
                    raise ORError("Incorrect length in RELAY cell")

                data = content[11:11 + length]

                if data.startswith(GET_AUTHORITY_Z):  # a quick and dirty way
                    return (INJECTED, streamid, circid, circid_server)

            elif content[0] == RELAY_BEGIN_DIR:
                key_client.add_dir_stream(streamid)

            new_payload = encrypt_onion_skin(content_no_digest,
                                             key_server,
                                             direction='f')
            return (FINISHED, None,
                    self.server_or_conn.add_circid(circid_server,
                                                   command + new_payload))
        else:
            new_payload = key_server.Kffunc.encrypt(content)
            return (FINISHED, None,
                    self.server_or_conn.add_circid(circid_server,
                                                   command + new_payload))
Exemple #9
0
    def process_netinfo_cell(self, netinfo_cell):
        # TODO: actual decoding and parsing
        circid, cell_content = self.decode_circid(netinfo_cell)

        if circid != 0 or cell_content[0] != COMMAND_NETINFO:
            raise ORError("Malformed NETINFO cell")
Exemple #10
0
    def process_auth_challenge_cell(self, auth_challenge_cell):
        # TODO: actual decoding and parsing
        circid, cell_content = self.decode_circid(auth_challenge_cell)

        if circid != 0 or cell_content[0] != COMMAND_AUTH_CHALLENGE:
            raise ORError("Malformed AUTH_CHALLENGE cell")