Exemple #1
0
    def make(circ_id, hlen=DEF.NTOR_HLEN, hdata='', link_version=3):
        '''Build and return a Created2 cell, using default values where
        possible.

        Automatically create and use an appropriate FixedLenCell.Header.

        .. note: oppy only supports the NTor handshake, so *make()* will
            currently reject any *htype*'s or *hlen*'s that are not
            recognized as used in the NTor handshake.

        :param int circ_id: Circuit ID to use for this cell
        :param int hlen: Length of **hdata** segment
        :param str hdata: Actual handshake data to use (an *onion skin*)
        :param int link_version: Link Protocol version in use
        :returns: :class:`~oppy.cell.fixedlen.Created2Cell`
        '''
        if hlen != DEF.NTOR_HLEN:
            msg = 'hlen was {}, expected {}.'
            raise BadPayloadData(msg.format(hlen, DEF.NTOR_HLEN))

        if hlen != len(hdata):
            msg = 'hlen was {}, but len(hdata) was {}.'
            raise BadPayloadData(msg.format(hlen, len(hdata)))

        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=DEF.CREATED2_CMD,
                                link_version=link_version)

        return Created2Cell(h, hlen=hlen, hdata=hdata)
Exemple #2
0
 def _checkMethods(methods):
     for method in methods:
         if len(method) != 2:
             msg = "AuthChallengeCell auth methods must be 2 bytes long."
             msg += " Found auth method {} bytes long."
             raise BadPayloadData(msg.format(len(method)))
         if method not in SUPPORTED_METHODS:
             msg = "Tried to use method {}, but oppy only supports method"
             msg += " {}."
             raise BadPayloadData(msg.format(method, SUPPORTED_METHODS))
Exemple #3
0
    def make(versions):
        '''Construct and return a VersionsCell, using default values
        where possible.

        Automatically create and use an appropriate FixedLenCell.Header.

        .. note: A VersionsCell always has len(circ_id_bytes) == 2 for
            backward compatibility (tor-spec, Section 3).

        .. note: oppy can currently only support Link Protocol versions
            3 and 4, so any other versions will be rejected.

        :param list, int versions: Link Protocol versions to indicate support
            for in this VersionsCell
        :returns: :class:`~cell.varlen.VersionsCell`
        '''
        for version in versions:
            if version not in CONN_DEFS.SUPPORTED_LINK_PROTOCOLS:
                msg = "Tried to build a VersionsCell that supports versions "
                msg += "{}, but oppy only supports versions {}."
                msg = msg.format(versions, CONN_DEFS.SUPPORTED_LINK_PROTOCOLS)
                raise BadPayloadData(msg)

        h = VarLenCell.Header(circ_id=0, cmd=DEF.VERSIONS_CMD,
                              payload_len=len(versions) * 2,
                              link_version=3)

        return VersionsCell(h, versions)
Exemple #4
0
    def _parsePayload(self, data):
        '''Parse the string data and extract cell fields.

        :param str data: string to parse
        '''
        start, _ = self.payloadRange()
        offset = start

        self.timestamp = data[offset:offset + TIMESTAMP_LEN]
        offset += TIMESTAMP_LEN

        self.other_or_address = TLVTriple.parse(data, offset)
        offset += len(self.other_or_address)

        self.num_addresses = data[offset:offset + NUM_ADDRESSES_LEN]
        self.num_addresses = struct.unpack('!B', self.num_addresses)[0]
        offset += NUM_ADDRESSES_LEN

        if self.num_addresses > MAX_THIS_OR_ADDRESSES:
            msg = "oppy only supports up to 5 'this_or_addresses' in a "
            msg += "NetInfoCell, received: {}."
            msg = msg.format(MAX_THIS_OR_ADDRESSES)
            raise BadPayloadData(msg)

        self.this_or_addresses = []
        for i in xrange(self.num_addresses):
            t = TLVTriple.parse(data, offset)
            self.this_or_addresses.append(t)
            offset += len(t)
Exemple #5
0
    def _parsePayload(self, data):
        '''Parse the string *data* and extract cell fields.

        Set this cell's attributes.

        :param str data: string to parse
        '''
        start, _ = self.payloadRange()
        self.reason = struct.unpack('!B', data[start:start + REASON_LEN])[0]
        if self.reason not in DEF.DESTROY_TRUNCATE_REASONS:
            msg = 'Unrecognized DESTROY reason: {}'.format(self.reason)
            raise BadPayloadData(msg)
Exemple #6
0
    def parse(data, offset):
        cert_type = struct.unpack('!B', data[offset:offset + CERT_TYPE_LEN])[0]
        offset += CERT_TYPE_LEN
        if cert_type not in SUPPORTED_CERT_TYPES:
            msg = "Got cert type {}, but oppy only supports cert types {}."
            raise BadPayloadData(msg.format(cert_type, SUPPORTED_CERT_TYPES))

        cert_len = struct.unpack('!H', data[offset:offset + CERT_LEN_LEN])[0]
        offset += CERT_LEN_LEN

        cert = data[offset:offset + cert_len]

        return CertsCellPayloadItem(cert_type, cert_len, cert)
Exemple #7
0
    def _parsePayload(self, data):
        '''Parse data and extract this cell's fields.

        Fill in this cell's attributes.

        :param str data: bytes to parse
        '''
        start, end = self.payloadRange()
        offset = start

        if end - start < CERT_TYPE_LEN + CERT_LEN_LEN:
            msg = "CertsCell payload was too few bytes to make a valid "
            msg += "CertsCell."
            raise BadPayloadData(msg)

        self.num_certs = struct.unpack('!B',
                                       data[offset:offset + NUM_CERT_LEN])[0]
        offset += NUM_CERT_LEN
        if self.num_certs > MAX_CERTS_PER_CELL:
            msg = "CertsCell cannot have more than {} certificates per cell."
            msg += " Found {}."
            raise BadPayloadData(msg.format(MAX_CERTS_PER_CELL,
                                            self.num_certs))

        self.cert_payload_items = []

        try:
            for i in xrange(self.num_certs):
                cert_payload_item = CertsCellPayloadItem.parse(data, offset)
                offset += len(cert_payload_item)
                self.cert_payload_items.append(cert_payload_item)
                # catch times when the sender 'lies' and sends a cert
                # larger than the claimed payload length of the cell
                if offset > end:
                    raise IndexError
        except IndexError:
            msg = "CertsCell payload was not enough bytes to construct "
            msg += "a valid CertsCell."
            raise BadPayloadData(msg)
Exemple #8
0
    def _parsePayload(self, data):
        '''Parse the string *data* and extract cell fields.

        Set this cell's attributes from extracted values.

        :param str data: string to parse
        '''
        start, end = self.payloadRange()
        offset = start

        if end - start < HTYPE_LEN + HLEN_LEN:
            msg = "Create2Cell payload was not enough bytes to construct "
            msg += "a valid Create2Cell."
            raise BadPayloadData(msg)

        self.htype = struct.unpack('!H', data[offset:offset + HTYPE_LEN])[0]

        if self.htype != DEF.NTOR_HTYPE:
            msg = "Create2 got htype: {}, but oppy only supports ntor: {}."
            raise BadPayloadData(msg.format(self.htype, DEF.NTOR_HTYPE))

        offset += HTYPE_LEN

        self.hlen = struct.unpack('!H', data[offset:offset + HLEN_LEN])[0]

        if self.hlen != DEF.NTOR_HLEN:
            msg = "Create2 got hlen: {}, but oppy only supports ntor hlen: {}."
            raise BadPayloadData(msg.format(self.hlen, DEF.NTOR_HLEN))

        offset += HLEN_LEN

        try:
            self.hdata = data[offset:offset + self.hlen]
        except IndexError:
            msg = "Create2 hlen was specified to be {} bytes, but actual "
            msg += "hdata was {} bytes."
            raise BadPayloadData(msg.format(self.hlen, len(data) - offset))
Exemple #9
0
    def _parseRelayPayload(self, data):
        '''Parse the string *data* and extract Extended2 fields.

        Fill in this cell's attributes.

        :param str data: data string to parse
        '''
        start, _ = self.relayPayloadRange()
        offset = start

        self.hlen = struct.unpack('!H', data[offset:offset + HLEN_LEN])[0]
        offset += HLEN_LEN

        try:
            self.hdata = data[offset:offset + self.hlen]
        except IndexError:
            raise BadPayloadData('Not enough hdata bytes.')
Exemple #10
0
    def make(circ_id, cert_payload_items, link_version=3):
        
        num_certs = len(cert_payload_items)
        if num_certs > MAX_CERTS_PER_CELL:
            msg = "CertsCell cannot have more than {} certificates per cell."
            msg += " Found {}."
            raise BadPayloadData(msg.format(MAX_CERTS_PER_CELL, num_certs))

        payload_len = NUM_CERT_LEN
        for cert_item in cert_payload_items:
            payload_len += len(cert_item)

        h = VarLenCell.Header(circ_id=circ_id, cmd=DEF.CERTS_CMD,
                              payload_len=payload_len,
                              link_version=link_version)

        return CertsCell(h, num_certs, cert_payload_items)
Exemple #11
0
    def _parsePayload(self, data):
        '''Parse data and extract this cell's fields.

        Fill in this cell's attributes.

        :param str data: bytes to parse
        '''
        start, end = self.payloadRange()
        offset = start

        self.versions = []
        while offset < end:
            v = struct.unpack('!H', data[offset:offset + VERSIONS_LEN])[0]
            if v not in CONN_DEFS.KNOWN_LINK_PROTOCOLS:
                msg = "VersionsCell claims to support an unknown Link "
                msg += "Protocol version {}.".format(v)
                raise BadPayloadData(msg)
            self.versions.append(v)
            offset += VERSIONS_LEN
Exemple #12
0
    def make(circ_id, stream_id, request, flags=None, link_version=3):
        '''Build and return a RelayBegin cell, filling in default values
        when possible.

        Automatically create a default FixedLenCell.Header and
        RelayCell.RelayHeader.

        :param int circ_id: Circuit ID to use in this cell
        :param int stream_id: Stream ID to use in this cell
        :param oppy.util.ExitRequest request: destination this
            cell will request a connection to
        :param list, int flags: flags to use for this connection
        :param int link_version: Link Protocol version in use on this
            connection
        :returns: :class:`~cell.relay.RelayBeginCell`
        '''
        addr = str(request)

        if flags is None:
            flags = [DEF.BEGIN_FLAG_IPv6_OK]

        f = 0
        for flag in flags:
            if flag not in DEF.RELAY_BEGIN_FLAGS:
                msg = 'Unrecognized Relay Begin flag: {}'.format(flag)
                raise BadPayloadData(msg)
            f |= (1 << (flag - 1))

        flags = struct.pack('!I', f)

        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=DEF.RELAY_CMD,
                                link_version=link_version)
        r = RelayCell.RelayHeader(cmd=DEF.RELAY_BEGIN_CMD,
                                  recognized=DEF.RECOGNIZED,
                                  stream_id=stream_id,
                                  digest=DEF.EMPTY_DIGEST,
                                  rpayload_len=len(addr + flags))

        return RelayBeginCell(h, rheader=r, addr=addr, flags=flags)
Exemple #13
0
    def make(circ_id,
             other_or_address,
             this_or_addresses,
             timestamp=None,
             link_version=3):
        '''Build and return a Destroy cell, using default values where
        possible.

        Automatically create and use an appropriate FixedLenCell.Header.

        :param int circ_id: Circuit ID to use for this cell
        :param str timestamp: Time this `NetInfoCell` was created. Big-endian
            unsigned integer of seconds since the Unix epoch (packed
            format).
        :param oppy.cell.util.TLVTriple other_or_address: Public IP
            address of the recipient of this NetInfoCell.
        :param list, oppy.cell.util.TLVTriple this_or_addresses: List
            of the public IP address(es) of the originator of this
            NetInfoCell.
        :returns: :class:`~oppy.cell.fixedlen.NetInfoCell`
        '''
        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=DEF.NETINFO_CMD,
                                link_version=link_version)

        if timestamp is None:
            timestamp = struct.pack('!I', int(time.time()))

        if len(this_or_addresses) > MAX_THIS_OR_ADDRESSES:
            msg = "oppy only supports up to 5 'this_or_addresses' in a "
            msg += "NetInfoCell, received: {}."
            msg = msg.format(MAX_THIS_OR_ADDRESSES)
            raise BadPayloadData(msg)

        return NetInfoCell(h,
                           timestamp=timestamp,
                           other_or_address=other_or_address,
                           num_addresses=len(this_or_addresses),
                           this_or_addresses=this_or_addresses)
Exemple #14
0
    def make(circ_id, payload, link_version=3, early=False):
        '''Build and return a Destroy cell, using default values where
        possible.

        Automatically create and use an appropriate FixedLenCell.Header. The
        *early* parameter specifies whether we should send a RELAY cell or
        a RELAY_EARLY cell.

        .. warning::

            RELAY_EARLY cells should always be used during circuit creation
            to avoid certain classes of attacks. That is, whenever oppy
            sends a relay EXTEND2 cell, it would be sent as a RELAY_EARLY
            cell instead of a RELAY cell.

            Reference: tor-spec, Section 5.6

        .. note: *payload* field should be fully padded and equal to
            maximum relay cell payload length (498).

        :param int circ_id: Circuit ID to use for this cell
        :param str payload: Payload bytes to use in this cell
        :param int link_version: Link Protocol version in use
        :param bool early: Dictate whether or not to use a RELAY_EARLY cell
        :returns: :class:`~oppy.cell.fixedlen.EncryptedCell`
        '''
        if len(payload) != DEF.MAX_PAYLOAD_LEN:
            msg = 'EncryptedCell enc_payload should be padding to length {}; '
            msg += 'found enc_payload length {} instead.'
            msg = msg.format(DEF.MAX_PAYLOAD_LEN, len(payload))
            raise BadPayloadData(msg)

        cmd = DEF.RELAY_EARLY_CMD if early is True else DEF.RELAY_CMD

        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=cmd,
                                link_version=link_version)

        return EncryptedCell(h, enc_payload=payload)
Exemple #15
0
    def make(circ_id, stream_id, rpayload, link_version=3):
        '''Construct and return a RelayData cell, using default values
        where possible.

        Create a FixedLenCell.Header and a RelayCell.RelayHeader.

        :param int circ_id: Circuit ID to use in this cell
        :param int stream_id: Stream ID to use in this cell
        :param str rpayload: data to use as the relay payload
        :param int link_version: Link Protocol version in use
        '''
        if len(rpayload) > DEF.MAX_RPAYLOAD_LEN:
            raise BadPayloadData()
        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=DEF.RELAY_CMD,
                                link_version=link_version)
        r = RelayCell.RelayHeader(cmd=DEF.RELAY_DATA_CMD,
                                  recognized=DEF.RECOGNIZED,
                                  stream_id=stream_id,
                                  digest=DEF.EMPTY_DIGEST,
                                  rpayload_len=len(rpayload))
        return RelayDataCell(h, rheader=r, rpayload=rpayload)
Exemple #16
0
    def make(circ_id, reason=DEF.DESTROY_NONE, link_version=3):
        '''Build and return a Destroy cell, using default values where
        possible.

        Automatically create and use an appropriate FixedLenCell.Header.

        .. warning: reason 0 (DESTROY_NONE in oppy.cell.definitions)
            should always be sent forward to avoid leaking version
            information.

        :param int circ_id: Circuit ID to use for this cell
        :param int reason: Reason this DESTROY cell is being sent
        :param int link_version: Link Protocol version in use
        :returns: :class:`~oppy.cell.fixedlen.DestroyCell`
        '''
        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=DEF.DESTROY_CMD,
                                link_version=link_version)

        if reason not in DEF.DESTROY_TRUNCATE_REASONS:
            msg = 'Unrecognized DESTROY reason: {}'.format(reason)
            raise BadPayloadData(msg)

        return DestroyCell(h, reason=reason)
Exemple #17
0
    def make(circ_id,
             stream_id=0,
             nspec=None,
             lspecs=None,
             htype=DEF.NTOR_HTYPE,
             hlen=DEF.NTOR_HLEN,
             hdata='',
             link_version=3,
             early=True):
        '''Construct and return a RelayExtend2Cell, using default values where
        possible.

        Create a FixedLenCell.Header and a RelayCell.RelayHeader for use
        in this cell.

        .. note:: oppy currently only supports the NTor handshake and will
            reject unrecognized htype's and hlen's.

        :param int circ_id: Circuit ID to use in this cell
        :param int stream_id: Stream ID to use in this cell (should be zero)
        :param int nspec: the number of Link Specifiers in this cell
        :param list, oppy.cell.util.LinkSpecifier lspecs: list of
            Link Specifiers to include in this cell
        :param int htype: Type of handshake in use
        :param int hlen: length of the handshake data field
        :param str hdata: handshake data (*onion skin*)
        :param int link_version: Link Protocol version in use
        :param bool early: if **True**, use a RELAY_EARLY cmd instead of
            RELAY cmd
        :returns: :class:`~oppy.cell.relay.RelayExtend2Cell`
        '''
        if lspecs is None:
            lspecs = []

        if stream_id != 0:
            msg = "EXTEND2 cells should use stream_id=0."
            raise BadPayloadData(msg)

        if htype != DEF.NTOR_HTYPE:
            msg = 'htype was {}, but we currently only support '
            msg += '{} (NTor) handshakes.'
            msg = msg.format(htype, DEF.NTOR_HTYPE)
            raise BadPayloadData(msg)

        if hlen != DEF.NTOR_HLEN:
            msg = 'htype was NTor and hlen was {} but expecting {}'
            msg = msg.format(hlen, DEF.NTOR_HLEN)
            raise BadPayloadData(msg)

        if hlen != len(hdata):
            msg = 'hlen {} neq len(hdata) {}'.format(hlen, len(hdata))
            raise BadPayloadData(msg)

        cmd = DEF.RELAY_EARLY_CMD if early is True else DEF.RELAY_CMD

        h = FixedLenCell.Header(circ_id=circ_id,
                                cmd=cmd,
                                link_version=link_version)

        if nspec is None:
            nspec = len(lspecs)

        if len(lspecs) == 0:
            msg = 'No Link Specifiers found. At least 1 Link Specifier '
            msg += 'is required.'
            raise BadPayloadData(msg)

        if nspec != len(lspecs):
            msg = 'Expected {} LinkSpecifiers but found {}'
            msg = msg.format(nspec, len(lspecs))
            raise BadPayloadData(msg)

        rpayload_len = NSPEC_LEN
        for lspec in lspecs:
            rpayload_len += len(lspec)
        rpayload_len += HTYPE_LEN + HLEN_LEN + hlen

        r = RelayCell.RelayHeader(cmd=DEF.RELAY_EXTEND2_CMD,
                                  recognized=DEF.RECOGNIZED,
                                  stream_id=stream_id,
                                  digest=DEF.EMPTY_DIGEST,
                                  rpayload_len=rpayload_len)

        return RelayExtend2Cell(h,
                                rheader=r,
                                nspec=nspec,
                                lspecs=lspecs,
                                htype=htype,
                                hlen=hlen,
                                hdata=hdata)
Exemple #18
0
 def _checkChallenge(challenge):
     if len(challenge) != CHALLENGE_LEN:
         msg = "AuthChallengeCell must have a 'challenge' of length {}."
         msg += " Got challenge of length {}."
         raise BadPayloadData(msg.format(CHALLENGE_LEN, len(challenge)))
Exemple #19
0
 def _checkNMethods(n_methods):
     if n_methods != NUM_SUPPORTED_METHODS:
         msg = "AuthChallengeCells currently only support {} methods. "
         msg += "Got {} methods."
         raise BadPayloadData(msg.format(NUM_SUPPORTED_METHODS,
                                         n_methods))