Exemplo n.º 1
0
    def dataReceived(self, data):
        '''We received data from the remote connection.

        Extract cells from the data stream and send them along to be
        processed.

        :param str data: data received from remote end
        '''
        self._buffer += data

        while Cell.enoughDataForCell(self._buffer):
            try:
                cell = Cell.parse(self._buffer, encrypted=True)
                self._deliverCell(cell)
                self._buffer = self._buffer[len(cell):]
            # this shouldn't happen and if it does, it's probably a bug
            except NotEnoughBytes as e:
                logging.debug(str(e))
                break
            # XXX remove len(unimplemented cell bytes) from buffer
            except NotImplementedError:
                logging.debug("Received a cell we can't handle yet.")
                logging.debug('buffer contents:\n')
                logging.debug([ord(i) for i in self._buffer])
                raise
            except (BadHandshakeState, HandshakeFailed, UnexpectedCell) as e:
                logging.warning(e)
                self.closeConnection()
                self._buffer = ''
                break
Exemplo n.º 2
0
    def dataReceived(self, data):
        '''We received data from the remote connection.

        Extract cells from the data stream and send them along to be
        processed.

        :param str data: data received from remote end
        '''
        self._buffer += data

        while Cell.enoughDataForCell(self._buffer):
            try:
                cell = Cell.parse(self._buffer, encrypted=True)
                self._deliverCell(cell)
                self._buffer = self._buffer[len(cell):]
            # this shouldn't happen and if it does, it's probably a bug
            except NotEnoughBytes as e:
                logging.debug(str(e))
                break
            # XXX remove len(unimplemented cell bytes) from buffer
            except NotImplementedError:
                logging.debug("Received a cell we can't handle yet.")
                logging.debug('buffer contents:\n')
                logging.debug([ord(i) for i in self._buffer])
                raise
            except (BadHandshakeState, HandshakeFailed, UnexpectedCell) as e:
                logging.warning(e)
                self.closeConnection()
                self._buffer = ''
                break
Exemplo n.º 3
0
 def test_parse(self):
     """Try to parse concrete cell type from a byte string and verify
     we read the correct cell attributes.
     """
     cell = Cell.parse(self.cell_constants["cell-bytes-good"], encrypted=self.encrypted)
     assert isinstance(cell, self.cell_constants["cell-type"])
     assert cell.header.__dict__ == self.cell_header
     for key in self.cell_attributes:
         assert getattr(cell, key) == self.cell_attributes[key]
     cell2 = Cell.parse(cell.getBytes(), encrypted=self.encrypted)
     assert cell.getBytes() == cell2.getBytes()
     assert cell == cell2
Exemplo n.º 4
0
 def test_parse(self):
     '''Try to parse concrete cell type from a byte string and verify
     we read the correct cell attributes.
     '''
     cell = Cell.parse(self.cell_constants['cell-bytes-good'],
                       encrypted=self.encrypted)
     assert isinstance(cell, self.cell_constants['cell-type'])
     assert cell.header.__dict__ == self.cell_header
     for key in self.cell_attributes:
         assert getattr(cell, key) == self.cell_attributes[key]
     cell2 = Cell.parse(cell.getBytes(), encrypted=self.encrypted)
     assert cell.getBytes() == cell2.getBytes()
     assert cell == cell2
Exemplo n.º 5
0
 def test_repr(self):
     '''Verify that a cell's repr can be used to create the same cell.
     '''
     from oppy.cell.fixedlen import (
         FixedLenCell,
         Create2Cell,
         Created2Cell,
         DestroyCell,
         EncryptedCell,
         NetInfoCell,
         PaddingCell,
     )
     from oppy.cell.varlen import (
         VarLenCell,
         AuthChallengeCell,
         CertsCell,
         VersionsCell,
         VPaddingCell,
     )
     from oppy.cell.util import (
         TLVTriple,
         CertsCellPayloadItem,
     )
     # XXX should realy just define eq method on cells...
     cell = Cell.parse(self.cell_constants['cell-bytes-good'],
                       encrypted=self.encrypted)
     cell2 = eval(repr(cell))
     assert cell.getBytes() == cell2.getBytes()
     assert len(cell) == len(cell2)
     assert cell == cell2
Exemplo n.º 6
0
 def test_getBytes(self):
     '''Verify that cell's 'getBytes()' method returns the correct byte
     string when cell is parsed from a string.
     '''
     cell = Cell.parse(self.cell_constants['cell-bytes-good'],
                       encrypted=self.encrypted)
     assert cell.getBytes() == self.cell_constants['cell-bytes-good']
Exemplo n.º 7
0
    def test_fixed_length_command_shorter_than_required(self):
        self.mock_struct.unpack.return_value = (None, 0)

        result = AbstractCell.enoughDataForCell(
            self.gen_data(509), link_version=4)

        self.assertFalse(result)
        self.mock_struct.unpack.assert_called_once_with('!IB', 'abcde')
Exemplo n.º 8
0
    def test_fixed_length_command_shorter_than_required(self):
        self.mock_struct.unpack.return_value = (None, 0)

        result = AbstractCell.enoughDataForCell(self.gen_data(509),
                                                link_version=4)

        self.assertFalse(result)
        self.mock_struct.unpack.assert_called_once_with('!IB', 'abcde')
Exemplo n.º 9
0
    def test_variable_length_command_shorter_than_required(self):
        self.mock_struct.unpack.side_effect = [(None, 7), (8, None)]

        result = AbstractCell.enoughDataForCell(self.gen_data(7),
                                                link_version=4)

        self.assertFalse(result)
        self.mock_struct.unpack.assert_has_calls(
            [call('!IB', 'abcde'), call('!H', 'fg')])
Exemplo n.º 10
0
 def test_len(self):
     '''Verify that len(cell) works properly.'''
     cell = Cell.parse(self.cell_constants['cell-bytes-good'],
                       encrypted=self.encrypted)
     cell_2 = self.cell_constants['cell-type'].make(
                                           self.cell_header['circ_id'],
                                           *self.cell_attributes.values())
     assert len(cell) == len(cell_2)
     assert len(cell) == len(self.cell_constants['cell-bytes-good'])
Exemplo n.º 11
0
    def test_variable_length_command_shorter_than_required(self):
        self.mock_struct.unpack.side_effect = [(None, 7), (8, None)]

        result = AbstractCell.enoughDataForCell(
            self.gen_data(7), link_version=4)

        self.assertFalse(result)
        self.mock_struct.unpack.assert_has_calls([
            call('!IB', 'abcde'),
            call('!H', 'fg')])
Exemplo n.º 12
0
 def test_len(self):
     """Verify that len(cell) works properly."""
     cell = Cell.parse(self.cell_constants["cell-bytes-good"], encrypted=self.encrypted)
     cell_2 = self.cell_constants["cell-type"].make(self.cell_header["circ_id"], *self.cell_attributes.values())
     assert len(cell) == len(cell_2)
     assert len(cell) == len(self.cell_constants["cell-bytes-good"])
     if cell.header.link_version < 4:
         assert len(cell) == 512
     else:
         assert len(cell) == 514
Exemplo n.º 13
0
    def dataReceived(self, data):
        self._buffer += data

        # TODO: fix underlying cell parsing code. current code does not
        #       handle malicious inputs properly and can't recover from
        #       weird/broken inputs
        while Cell.enoughDataForCell(self._buffer):
            try:
                cell = Cell.parse(self._buffer)
                self._read_queue.put(cell)
                self._buffer = self._buffer[len(cell):]
            # TODO: catch all exceptions and remove that length
            #       from the buffer
            # TODO: remove len(NotImplementedBytes) from buffer
            except NotImplementedError as e:
                msg = ("Connection to {} received an unexpected cell. {}."
                       .format(self.micro_status_entry.fingerprint, e))
                self._current_task.errback(msg)
                break
Exemplo n.º 14
0
    def dataReceived(self, data):
        self._buffer += data

        # TODO: fix underlying cell parsing code. current code does not
        #       handle malicious inputs properly and can't recover from
        #       weird/broken inputs
        while Cell.enoughDataForCell(self._buffer):
            try:
                cell = Cell.parse(self._buffer)
                self._read_queue.put(cell)
                self._buffer = self._buffer[len(cell):]
            # TODO: catch all exceptions and remove that length
            #       from the buffer
            # TODO: remove len(NotImplementedBytes) from buffer
            except NotImplementedError as e:
                msg = (
                    "Connection to {} received an unexpected cell. {}.".format(
                        self.micro_status_entry.fingerprint, e))
                self._current_task.errback(msg)
                break
Exemplo n.º 15
0
    def test_parse_helper(self):
        self.mock_cell.__len__.return_value = 5
        header = Mock(spec=AbstractCell.Header, cmd='command', link_version=4)

        result = AbstractCell._parse(self.gen_data(5), header)

        self.assertEqual(result, self.mock_cell)
        self.mock_get_subclass.assert_called_once_with(header, 'abcde')
        self.mock_get_subclass.return_value.assert_called_once_with(header)
        self.mock_cell._parseHeader.assert_called_once_with('abcde')
        self.mock_cell._parsePayload.assert_called_once_with('abcde')
Exemplo n.º 16
0
    def test_parse_helper(self):
        self.mock_cell.__len__.return_value = 5
        header = Mock(
            spec=AbstractCell.Header, cmd='command', link_version=4)

        result = AbstractCell._parse(self.gen_data(5), header)

        self.assertEqual(result, self.mock_cell)
        self.mock_get_subclass.assert_called_once_with(header, 'abcde')
        self.mock_get_subclass.return_value.assert_called_once_with(header)
        self.mock_cell._parseHeader.assert_called_once_with('abcde')
        self.mock_cell._parsePayload.assert_called_once_with('abcde')
Exemplo n.º 17
0
    def test_relay_cmd(self, mock_relaycell):
        self.mock_struct.unpack.return_value = ('circ id', 3)

        result = AbstractCell.parse(self.gen_data(6), link_version=4)

        self.assertEqual(result, mock_relaycell._parse.return_value)
        self.mock_struct.calcsize.assert_called_once_with('!IB')
        self.mock_struct.unpack.assert_called_once_with('!IB', 'abcde')
        mock_relaycell.Header.assert_called_once_with(
            circ_id='circ id', cmd=3, link_version=4)

        mock_relaycell._parse.assert_called_once_with(
            'abcdef', mock_relaycell.Header.return_value)
Exemplo n.º 18
0
    def test_fixedlen(self, mock_fixedlencell):
        self.mock_struct.unpack.return_value = ('circ id', 0)

        result = AbstractCell.parse(self.gen_data(6), link_version=1)

        self.assertEqual(result, mock_fixedlencell._parse.return_value)
        self.mock_struct.calcsize.assert_called_once_with('!HB')
        self.mock_struct.unpack.assert_called_once_with('!HB', 'abcde')
        mock_fixedlencell.Header.assert_called_once_with(
            circ_id='circ id', cmd=0, link_version=1)

        mock_fixedlencell._parse.assert_called_once_with(
            'abcdef', mock_fixedlencell.Header.return_value)
Exemplo n.º 19
0
    def test_varlen(self, mock_varlencell):
        self.mock_struct.unpack.return_value = ('circ id', 7)

        result = AbstractCell.parse(self.gen_data(6), link_version=1)

        self.assertEqual(result, mock_varlencell._parse.return_value)
        self.mock_struct.calcsize.assert_called_once_with('!HB')
        self.mock_struct.unpack.assert_called_once_with('!HB', 'abcde')
        mock_varlencell.Header.assert_called_once_with(circ_id='circ id',
                                                       cmd=7,
                                                       link_version=1)

        mock_varlencell._parse.assert_called_once_with(
            'abcdef', mock_varlencell.Header.return_value)
Exemplo n.º 20
0
    def dataReceived(self, data):
        '''We received data from the remote connection.

        Extract cells from the data stream and send them along to be
        processed.

        :param str data: data received from remote end
        '''
        self._buffer += data

        while Cell.enoughDataForCell(self._buffer):
            try:
                cell = Cell.parse(self._buffer, encrypted=True)
                self._recv(cell)
                self._buffer = self._buffer[len(cell):]
            except NotEnoughBytes as e:
                logging.debug(e)
                break
            # TODO: remove len(unimplemented cell bytes) from buffer
            except NotImplementedError:
                logging.debug("Received a cell we can't handle yet.")
                logging.debug('buffer contents:\n')
                logging.debug([ord(i) for i in self._buffer])
                raise
Exemplo n.º 21
0
    def dataReceived(self, data):
        '''We received data from the remote connection.

        Extract cells from the data stream and send them along to be
        processed.

        :param str data: data received from remote end
        '''
        self._buffer += data

        while Cell.enoughDataForCell(self._buffer):
            try:
                cell = Cell.parse(self._buffer, encrypted=True)
                self._recv(cell)
                self._buffer = self._buffer[len(cell):]
            except NotEnoughBytes as e:
                logging.debug(e)
                break
            # TODO: remove len(unimplemented cell bytes) from buffer
            except NotImplementedError:
                logging.debug("Received a cell we can't handle yet.")
                logging.debug('buffer contents:\n')
                logging.debug([ord(i) for i in self._buffer])
                raise
Exemplo n.º 22
0
    def test_relay_early_encrypted(self, mock_fixedlencell):
        self.mock_struct.unpack.return_value = ('circ id', 9)

        result = AbstractCell.parse(self.gen_data(6),
                                    link_version=4,
                                    encrypted=True)

        self.assertEqual(result, mock_fixedlencell._parse.return_value)
        self.mock_struct.calcsize.assert_called_once_with('!IB')
        self.mock_struct.unpack.assert_called_once_with('!IB', 'abcde')
        mock_fixedlencell.Header.assert_called_once_with(circ_id='circ id',
                                                         cmd=9,
                                                         link_version=4)

        mock_fixedlencell._parse.assert_called_once_with(
            'abcdef', mock_fixedlencell.Header.return_value)
Exemplo n.º 23
0
    def test_repr(self):
        """Verify that a cell's repr can be used to create the same cell.
        """
        from oppy.cell.fixedlen import (
            FixedLenCell,
            Create2Cell,
            Created2Cell,
            DestroyCell,
            EncryptedCell,
            NetInfoCell,
            PaddingCell,
        )
        from oppy.cell.varlen import VarLenCell, AuthChallengeCell, CertsCell, VersionsCell, VPaddingCell
        from oppy.cell.util import TLVTriple, CertsCellPayloadItem

        # XXX should realy just define eq method on cells...
        cell = Cell.parse(self.cell_constants["cell-bytes-good"], encrypted=self.encrypted)
        cell2 = eval(repr(cell))
        assert cell.getBytes() == cell2.getBytes()
        assert len(cell) == len(cell2)
        assert cell == cell2
Exemplo n.º 24
0
def decryptCellUntilRecognized(cell, crypt_path, origin=2):
    '''Decrypt *cell* until it is recognized or we've tried all RelayCrypto's
    in *crypt_path*.

    Attempt to decrypt the cell one hop at a time. Stop if the cell is
    recognized. Raise an exception if the cell is not recognized at all.

    :param cell cell: cell to decrypt
    :param list, oppy.crypto.relaycrypto.RelayCrypto crypt_path: list of
        RelayCrypto instances to use for decryption
    :param int origin: the originating hop we think this cell came from
    :returns: the concrete RelayCell type of this decrypted cell
    '''
    assert 0 <= origin <= 2, 'We can only handle 3-hop paths'

    recognized = False
    payload = cell.getPayload()
    for node in xrange(len(crypt_path)):
        relay_crypto = crypt_path[node]
        payload = relay_crypto.backward_cipher.decrypt(payload)
        if cellRecognized(payload, relay_crypto):
            recognized = True
            origin = node
            break

    if recognized:
        updated_payload = makePayloadWithDigest(payload)
        crypt_path[origin].backward_digest.update(updated_payload)
        if cell.header.link_version < 4:
            cid = struct.pack('!H', cell.header.circ_id)
        else:
            cid = struct.pack('!I', cell.header.circ_id)
        cmd = struct.pack('!B', cell.header.cmd)

        dec = Cell.parse(cid + cmd + payload)
        return (dec, origin)
    else:
        raise UnrecognizedCell()
Exemplo n.º 25
0
def decryptCell(cell, crypt_path):
    '''Decrypt *cell* until it is recognized or we've tried all RelayCrypto's
    in *crypt_path*.

    Attempt to decrypt the cell one hop at a time. Stop if the cell is
    recognized. Raise an exception if the cell is not recognized at all.

    :param cell cell: cell to decrypt
    :param list, oppy.crypto.relaycrypto.RelayCrypto crypt_path: list of
        RelayCrypto instances to use for decryption
    :param int origin: the originating hop we think this cell came from
    :returns: the concrete RelayCell type of this decrypted cell
    '''
    origin = 0
    recognized = False
    payload = cell.getPayload()

    for node in crypt_path:
        payload = node.backward_cipher.decrypt(payload)
        if _cellRecognized(payload, node):
            recognized = True
            break
        origin += 1

    if not recognized:
        raise UnrecognizedCell()

    updated_payload = _makePayloadWithDigest(payload)
    crypt_path[origin].backward_digest.update(updated_payload)
    if cell.header.link_version < 4:
        cid = struct.pack('!H', cell.header.circ_id)
    else:
        cid = struct.pack('!I', cell.header.circ_id)
    cmd = struct.pack('!B', cell.header.cmd)

    dec = Cell.parse(cid + cmd + payload)
    return (dec, origin)
Exemplo n.º 26
0
def decryptCell(cell, crypt_path):
    '''Decrypt *cell* until it is recognized or we've tried all RelayCrypto's
    in *crypt_path*.

    Attempt to decrypt the cell one hop at a time. Stop if the cell is
    recognized. Raise an exception if the cell is not recognized at all.

    :param cell cell: cell to decrypt
    :param list, oppy.crypto.relaycrypto.RelayCrypto crypt_path: list of
        RelayCrypto instances to use for decryption
    :param int origin: the originating hop we think this cell came from
    :returns: the concrete RelayCell type of this decrypted cell
    '''
    origin = 0
    recognized = False
    payload = cell.getPayload()

    for node in crypt_path:
        payload = node.backward_cipher.decrypt(payload)
        if _cellRecognized(payload, node):
            recognized = True
            break
        origin += 1

    if not recognized:
        raise UnrecognizedCell()

    updated_payload = _makePayloadWithDigest(payload)
    crypt_path[origin].backward_digest.update(updated_payload)
    if cell.header.link_version < 4:
        cid = struct.pack('!H', cell.header.circ_id)
    else:
        cid = struct.pack('!I', cell.header.circ_id)
    cmd = struct.pack('!B', cell.header.cmd)

    dec = Cell.parse(cid + cmd + payload)
    return (dec, origin)
Exemplo n.º 27
0
 def test_getBytes_trimmed(self):
     cell = Cell.parse(self.cell_constants['cell-bytes-good'],
                       encrypted=self.encrypted)
     assert cell.getBytes(trimmed=True) == self.cell_constants['cell-bytes-good-nopadding']
Exemplo n.º 28
0
 def test_len(self):
     from oppy.cell.cell import Cell
     cell = Cell.parse(vpadding_bytes_good)
     cell_2 = VPaddingCell.make(CIRC_ID, padding_len=VPADDING_CELL_LEN)
     assert len(cell) == len(cell_2)
     assert len(cell) == VPADDING_CELL_LEN + 2 + 1 + 2
Exemplo n.º 29
0
    def test_data_shorter_than_header(self):
        result = AbstractCell.enoughDataForCell(
            self.gen_data(2), link_version=1)

        self.assertFalse(result)
        self.assertFalse(self.mock_struct.unpack.called)
Exemplo n.º 30
0
    def test_data_shorter_than_header(self):
        result = AbstractCell.enoughDataForCell(self.gen_data(2),
                                                link_version=1)

        self.assertFalse(result)
        self.assertFalse(self.mock_struct.unpack.called)
Exemplo n.º 31
0
 def test_len(self):
     from oppy.cell.cell import Cell
     cell = Cell.parse(versions_bytes_good)
     cell_2 = VersionsCell.make(versions=[3])
     assert len(cell) == len(cell_2)
     assert len(cell) == VERSIONS_CELL_LEN + 2 + 1 + 2
Exemplo n.º 32
0
 def test_len(self):
     from oppy.cell.cell import Cell
     cell = Cell.parse(vpadding_bytes_good)
     cell_2 = VPaddingCell.make(CIRC_ID, padding_len=VPADDING_CELL_LEN)
     assert len(cell) == len(cell_2)
     assert len(cell) == VPADDING_CELL_LEN + 2 + 1 + 2
Exemplo n.º 33
0
 def test_len(self):
     from oppy.cell.cell import Cell
     cell = Cell.parse(versions_bytes_good)
     cell_2 = VersionsCell.make(versions=[3])
     assert len(cell) == len(cell_2)
     assert len(cell) == VERSIONS_CELL_LEN + 2 + 1 + 2
Exemplo n.º 34
0
 def test_getBytes(self):
     """Verify that cell's 'getBytes()' method returns the correct byte
     string when cell is parsed from a string.
     """
     cell = Cell.parse(self.cell_constants["cell-bytes-good"], encrypted=self.encrypted)
     assert cell.getBytes() == self.cell_constants["cell-bytes-good"]
Exemplo n.º 35
0
 def test_getBytes_trimmed(self):
     cell = Cell.parse(self.cell_constants["cell-bytes-good"], encrypted=self.encrypted)
     assert cell.getBytes(trimmed=True) == self.cell_constants["cell-bytes-good-nopadding"]