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)
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))
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)
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)
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)
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)
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)
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))
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.')
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)
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
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)
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)
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)
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)
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)
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)
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)))
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))