[tor-commits] [stem/master] Implement PADDING and VPADDING cells
atagar at torproject.org
atagar at torproject.org
Sun Jan 21 02:04:04 UTC 2018
commit 9fb787cd89b10254df58deb0d190ac5fdbe58c16
Author: Damian Johnson <atagar at torproject.org>
Date: Sun Jan 14 13:06:00 2018 -0800
Implement PADDING and VPADDING cells
Couple particularly easy cell types.
---
stem/client/cell.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++--
test/unit/client/cell.py | 38 +++++++++++++++++++++++++--
2 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/stem/client/cell.py b/stem/client/cell.py
index 4fe7952e..995b482a 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -38,6 +38,8 @@ Messages communicated over a Tor relay's ORPort.
import inspect
import io
+import os
+import random
import sys
from stem import UNDEFINED
@@ -219,10 +221,36 @@ class CircuitCell(Cell):
class PaddingCell(Cell):
+ """
+ Randomized content to either keep activity going on a circuit.
+
+ :var bytes payload: randomized payload
+ """
+
NAME = 'PADDING'
VALUE = 0
IS_FIXED_SIZE = True
+ def __init__(self, payload):
+ self.payload = payload
+
+ @classmethod
+ def pack(cls, link_version, payload = None):
+ """
+ Provides a randomized padding payload.
+
+ :param int link_version: link protocol version
+ :param bytes payload: padding payload
+
+ :returns: **bytes** with randomized content
+ """
+
+ return cls._pack(link_version, payload if payload else os.urandom(FIXED_PAYLOAD_LEN))
+
+ @classmethod
+ def _unpack(cls, content, circ_id, link_version):
+ return PaddingCell(content)
+
class CreateCell(CircuitCell):
NAME = 'CREATE'
@@ -332,10 +360,46 @@ class PaddingNegotiateCell(Cell):
class VPaddingCell(Cell):
+ """
+ Variable length randomized content to either keep activity going on a circuit.
+
+ :var bytes payload: randomized payload
+ """
+
NAME = 'VPADDING'
VALUE = 128
IS_FIXED_SIZE = False
+ def __init__(self, payload):
+ self.payload = payload
+
+ @classmethod
+ def pack(cls, link_version, size = None, payload = None):
+ """
+ Provides a randomized padding payload. If no size or payload is provided
+ then this provides padding of an arbitrarily chosen size between 128-1024.
+
+ :param int link_version: link protocol version
+ :param int size: number of bytes to pad
+ :param bytes payload: padding payload
+
+ :returns: **bytes** with randomized content
+
+ :raises: **ValueError** if both a size and payload are provided, and they
+ mismatch
+ """
+
+ if payload is None:
+ payload = os.urandom(size) if size else os.urandom(random.randint(128, 1024))
+ elif size is not None and size != len(payload):
+ raise ValueError('VPaddingCell.pack caller specified both a size of %i bytes and payload of %i bytes' % (size, len(payload)))
+
+ return cls._pack(link_version, payload)
+
+ @classmethod
+ def _unpack(cls, content, circ_id, link_version):
+ return VPaddingCell(content)
+
class CertsCell(Cell):
"""
@@ -352,12 +416,12 @@ class CertsCell(Cell):
self.certificates = certs
@classmethod
- def pack(cls, certs, link_version):
+ def pack(cls, link_version, certs):
"""
Provides the payload for a series of certificates.
- :param list certs: series of :class:`~stem.client.Certificate` for the cell
:param int link_version: link protocol version
+ :param list certs: series of :class:`~stem.client.Certificate` for the cell
:returns: **bytes** with a payload for these versions
"""
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index b26549e2..0d2b677d 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -2,18 +2,40 @@
Unit tests for the stem.client.cell.
"""
+import os
import unittest
from stem.client import Certificate
-from stem.client.cell import Cell, VersionsCell, CertsCell
from test.unit.client import test_data
+from stem.client.cell import (
+ FIXED_PAYLOAD_LEN,
+ Cell,
+ PaddingCell,
+ VersionsCell,
+ VPaddingCell,
+ CertsCell,
+)
+
+RANDOM_PAYLOAD = os.urandom(FIXED_PAYLOAD_LEN)
+
+PADDING_CELLS = {
+ '\x00\x00\x00' + RANDOM_PAYLOAD: RANDOM_PAYLOAD,
+}
+
VERSIONS_CELLS = {
'\x00\x00\x07\x00\x00': [],
'\x00\x00\x07\x00\x02\x00\x01': [1],
'\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': [1, 2, 3],
}
+VPADDING_CELLS = {
+ '\x00\x00\x80\x00\x00': '',
+ '\x00\x00\x80\x00\x01\x08': '\x08',
+ '\x00\x00\x80\x00\x02\x08\x11': '\x08\x11',
+ '\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: RANDOM_PAYLOAD,
+}
+
CERTS_CELLS = {
'\x00\x00\x81\x00\x01\x00': [],
'\x00\x00\x81\x00\x04\x01\x01\x00\x00': [Certificate(type = 1, value = '')],
@@ -49,14 +71,26 @@ class TestCell(unittest.TestCase):
# TODO: we need to support more cell types before we can test this
self.assertRaisesRegexp(NotImplementedError, 'Unpacking not yet implemented for AUTH_CHALLENGE cells', Cell.unpack, test_data('new_link_cells'), 2)
+ def test_padding_packing(self):
+ for cell_bytes, payload in PADDING_CELLS.items():
+ self.assertEqual(cell_bytes, PaddingCell.pack(2, payload))
+ self.assertEqual(payload, Cell.unpack(cell_bytes, 2)[0].payload)
+
def test_versions_packing(self):
for cell_bytes, versions in VERSIONS_CELLS.items():
self.assertEqual(cell_bytes, VersionsCell.pack(versions))
self.assertEqual(versions, Cell.unpack(cell_bytes, 2)[0].versions)
+ def test_vpadding_packing(self):
+ for cell_bytes, payload in VPADDING_CELLS.items():
+ self.assertEqual(cell_bytes, VPaddingCell.pack(2, payload = payload))
+ self.assertEqual(payload, Cell.unpack(cell_bytes, 2)[0].payload)
+
+ self.assertRaisesRegexp(ValueError, 'VPaddingCell.pack caller specified both a size of 5 bytes and payload of 1 bytes', VPaddingCell.pack, 2, 5, '\x02')
+
def test_certs_packing(self):
for cell_bytes, certs in CERTS_CELLS.items():
- self.assertEqual(cell_bytes, CertsCell.pack(certs, 2))
+ self.assertEqual(cell_bytes, CertsCell.pack(2, certs))
self.assertEqual(certs, Cell.unpack(cell_bytes, 2)[0].certificates)
# extra bytes after the last certificate should be ignored
More information about the tor-commits
mailing list