Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9cd26e5
Add abstract BaseRelayCell class
dmr-x Aug 3, 2018
ba6d4c0
Provide a nicer error message for packing negative numbers with unsig…
dmr-x Aug 6, 2018
fcffb7f
Optimize error check for non-negative inputs
dmr-x Aug 7, 2018
aba5cd9
Adjust test expectation for the different exception rising from Size
dmr-x Aug 7, 2018
6033cd0
Add CANNOT_DIRECTLY_UNPACK facility; set True for existing RelayCell
dmr-x Aug 7, 2018
2175b7c
Add RawRelayCell and temp-fix RelayCell tests (interim)
dmr-x Aug 8, 2018
462c986
Document RawRelayCell in the module overview
dmr-x Aug 9, 2018
b179161
Simplify encryption/decryption implementation in Circuit
dmr-x Aug 8, 2018
e048639
Standardize some docstring keywords
dmr-x Aug 8, 2018
d63dd75
Refactor digest coercion into separate method
dmr-x Aug 10, 2018
3f56c3b
Refactor payload parsing (unpacking) into separate method
dmr-x Aug 8, 2018
05f083a
Refactor payload packing into separate method
dmr-x Aug 8, 2018
d427bfc
Refactor 'unused' and padding packing into the RELAY cell payload
dmr-x Aug 9, 2018
a2bb336
Further simplify digest calculation for encryption
dmr-x Aug 9, 2018
c342fb8
Fix docstring 'import path' for RelayCommand
dmr-x Aug 11, 2018
1a61269
Add convenience method for packing payload of a RELAY cell
dmr-x Aug 10, 2018
f0cdac3
Add apply_digest instance method to RelayCell
dmr-x Aug 10, 2018
7e59692
Further simplify digest application
dmr-x Aug 10, 2018
b47ea8e
Refactor apply_digest to remove side effects
dmr-x Aug 15, 2018
52a3632
Update stem.client.cell docstrings for style, consistency, and clarity
dmr-x Aug 17, 2018
ec56c05
Refactor RELAY cell encryption into new encrypt instance method
dmr-x Aug 17, 2018
b9877f3
Add check_digest instance method to BaseRelayCell
dmr-x Aug 18, 2018
caffd27
Add check_recognized_field instance method to BaseRelayCell
dmr-x Aug 19, 2018
0798b51
Add interpret_cell instance method to BaseRelayCell
dmr-x Aug 19, 2018
ae7feea
Add decrypt instance method to BaseRelayCell
dmr-x Aug 18, 2018
a9128d2
Now use the decrypt method in our Circuit class
dmr-x Aug 18, 2018
ce161c6
Actually make copies of the backward digest/key, too
dmr-x Aug 18, 2018
0be343d
Rearrange the digest/key copies to be a bit more spec-compliant
dmr-x Aug 18, 2018
e8a7599
Decouple payload processing from pop/unpack, add recognized/digest ch…
dmr-x Aug 19, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 32 additions & 39 deletions stem/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import stem.socket
import stem.util.connection

from stem.client.datatype import ZERO, LinkProtocol, Address, Size, KDF, split
from stem.client.datatype import ZERO, LinkProtocol, Address, KDF

__all__ = [
'cell',
Expand Down Expand Up @@ -226,62 +226,55 @@ def send(self, command, data = '', stream_id = 0):
"""
Sends a message over the circuit.

:param stem.client.RelayCommand command: command to be issued
:param stem.client.datatype.RelayCommand command: command to be issued
:param bytes data: message payload
:param int stream_id: specific stream this concerns

:returns: **list** of :class:`~stem.client.cell.RelayCell` responses
"""

with self.relay._orport_lock:
orig_digest = self.forward_digest.copy()
orig_key = copy.copy(self.forward_key)

# Digests and such are computed using the RELAY cell payload. This
# doesn't include the initial circuit id and cell type fields.
# Circuit ids vary in length depending on the protocol version.

header_size = self.relay.link_protocol.circ_id_size.size + 1
orig_forward_digest = self.forward_digest.copy()
orig_forward_key = copy.copy(self.forward_key)

try:
cell = stem.client.cell.RelayCell(self.id, command, data, 0, stream_id)
payload_without_digest = cell.pack(self.relay.link_protocol)[header_size:]
self.forward_digest.update(payload_without_digest)
cell = stem.client.cell.RelayCell(self.id, command, data, stream_id = stream_id)
encrypted_cell, self.forward_digest, self.forward_key = cell.encrypt(self.forward_digest, self.forward_key)

cell = stem.client.cell.RelayCell(self.id, command, data, self.forward_digest, stream_id)
header, payload = split(cell.pack(self.relay.link_protocol), header_size)
encrypted_payload = header + self.forward_key.update(payload)
self.relay._orport.send(encrypted_cell.pack(self.relay.link_protocol))
except:
self.forward_digest = orig_forward_digest
self.forward_key = orig_forward_key
raise

reply_cells = []
self.relay._orport.send(encrypted_payload)
reply = self.relay._orport.recv()
reply = self.relay._orport.recv()
reply_cells = []

# Check that we got the correct number of bytes for a series of RELAY cells
relay_cell_cmd = stem.client.cell.RelayCell.VALUE

relay_cell_size = header_size + stem.client.cell.FIXED_PAYLOAD_LEN
relay_cell_cmd = stem.client.cell.RelayCell.VALUE
while reply:
orig_backward_digest = self.backward_digest.copy()
orig_backward_key = copy.copy(self.backward_key)

if len(reply) % relay_cell_size != 0:
raise stem.ProtocolError('Circuit response should be a series of RELAY cells, but received an unexpected size for a response: %i' % len(reply))
try:
raw_cell, reply = stem.client.cell.Cell.pop(reply, self.relay.link_protocol)

while reply:
circ_id, reply = self.relay.link_protocol.circ_id_size.pop(reply)
command, reply = Size.CHAR.pop(reply)
payload, reply = split(reply, stem.client.cell.FIXED_PAYLOAD_LEN)
if raw_cell.VALUE != relay_cell_cmd:
raise stem.ProtocolError('RELAY cell responses should be %i but was %i' % (relay_cell_cmd, raw_cell.VALUE))
elif raw_cell.circ_id != self.id:
raise stem.ProtocolError('Response should be for circuit id %i, not %i' % (self.id, raw_cell.circ_id))

if command != relay_cell_cmd:
raise stem.ProtocolError('RELAY cell responses should be %i but was %i' % (relay_cell_cmd, command))
elif circ_id != self.id:
raise stem.ProtocolError('Response should be for circuit id %i, not %i' % (self.id, circ_id))
decrypted_cell, fully_decrypted, self.backward_digest, self.backward_key = raw_cell.decrypt(self.backward_digest, self.backward_key, interpret = True)
if not fully_decrypted:
raise stem.ProtocolError('Response for circuit id %i was not fully decrypted, when expected to be' % self.id)
except:
self.backward_digest = orig_backward_digest
self.backward_key = orig_backward_key
raise

decrypted = self.backward_key.update(payload)
reply_cells.append(stem.client.cell.RelayCell._unpack(decrypted, self.id, self.relay.link_protocol))
reply_cells.append(decrypted_cell)

return reply_cells
except:
self.forward_digest = orig_digest
self.forward_key = orig_key
raise
return reply_cells

def close(self):
with self.relay._orport_lock:
Expand Down
Loading