[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Support unpacking CERTS cells
commit b43bd7b72de2a50c094601771bf43ed33301071a
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Sat Jan 13 18:44:46 2018 -0800
Support unpacking CERTS cells
---
stem/client/__init__.py | 19 +++++++++++++++++++
stem/client/cell.py | 34 ++++++++++++++++++++++++++++++++--
test/unit/client/cell.py | 33 +++++++++++++++++++++++++++++----
3 files changed, 80 insertions(+), 6 deletions(-)
diff --git a/stem/client/__init__.py b/stem/client/__init__.py
index c3b18c6c..6909c1a7 100644
--- a/stem/client/__init__.py
+++ b/stem/client/__init__.py
@@ -17,6 +17,7 @@ a wrapper for :class:`~stem.socket.RelaySocket`, much the same way as
+- pop - decodes content with remainder
"""
+import collections
import struct
ZERO = '\x00'
@@ -26,6 +27,24 @@ __all__ = [
]
+class Certificate(collections.namedtuple('Certificate', ['type', 'value'])):
+ """
+ Relay certificate as defined in tor-spec section 4.2. Certificate types
+ are...
+
+ ==================== ===========
+ Type Value Description
+ ==================== ===========
+ 1 Link key certificate certified by RSA1024 identity
+ 2 RSA1024 Identity certificate
+ 3 RSA1024 AUTHENTICATE cell link certificate
+ ==================== ===========
+
+ :var int type: certificate type
+ :var bytes value: certificate value
+ """
+
+
class Size(object):
"""
Unsigned `struct.pack format
diff --git a/stem/client/cell.py b/stem/client/cell.py
index 4d4667d0..e3793491 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -40,7 +40,7 @@ import inspect
import sys
from stem import UNDEFINED
-from stem.client import ZERO, Size
+from stem.client import ZERO, Certificate, Size
FIXED_PAYLOAD_LEN = 509
@@ -123,7 +123,7 @@ class Cell(object):
if len(content) < payload_len:
raise ValueError('%s cell should have a payload of %i bytes, but only had %i' % (cls.NAME, payload_len, len(content)))
- payload = content[:payload_len].rstrip(ZERO) # strip padding
+ payload = content[:payload_len]
content = content[payload_len:]
cells.append(cls._unpack(payload, link_version, circ_id))
@@ -328,10 +328,40 @@ class VPaddingCell(Cell):
class CertsCell(Cell):
+ """
+ Certificate held by the relay we're communicating with.
+
+ :var list certificates: :class:`~stem.client.Certificate` of the relay
+ """
+
NAME = 'CERTS'
VALUE = 129
IS_FIXED_SIZE = False
+ def __init__(self, certs):
+ self.certificates = certs
+
+ @classmethod
+ def _unpack(cls, content, circ_id, link_version):
+ cert_count, content = Size.CHAR.pop(content)
+ certs = []
+
+ for i in range(cert_count):
+ if not content:
+ raise ValueError('CERTS cell indicates it should have %i certificates, but only contained %i' % (cert_count, len(certs)))
+
+ cert_type, content = Size.CHAR.pop(content)
+ cert_size, content = Size.SHORT.pop(content)
+
+ if cert_size > len(content):
+ raise ValueError('CERTS cell should have a certificate with %i bytes, but only had %i remaining' % (cert_size, len(content)))
+
+ cert_bytes = content[:cert_size]
+ content = content[cert_size:]
+ certs.append(Certificate(cert_type, cert_bytes))
+
+ return CertsCell(certs)
+
class AuthChallengeCell(Cell):
NAME = 'AUTH_CHALLENGE'
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index 3a2a55f2..b1001eb7 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -4,6 +4,7 @@ Unit tests for the stem.client.cell.
import unittest
+from stem.client import Certificate
from stem.client.cell import Cell, VersionsCell
from test.unit.client import test_data
@@ -34,7 +35,7 @@ class TestCell(unittest.TestCase):
def test_unpack_for_new_link(self):
# TODO: we need to support more cell types before we can test this
- self.assertRaisesRegexp(NotImplementedError, 'Unpacking not yet implemented for CERTS cells', Cell.unpack, test_data('new_link_cells'), 2)
+ self.assertRaisesRegexp(NotImplementedError, 'Unpacking not yet implemented for AUTH_CHALLENGE cells', Cell.unpack, test_data('new_link_cells'), 2)
def test_versions_pack(self):
self.assertEqual('\x00\x00\x07\x00\x00', VersionsCell.pack([]))
@@ -42,6 +43,30 @@ class TestCell(unittest.TestCase):
self.assertEqual('\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03', VersionsCell.pack([1, 2, 3]))
def test_versions_unpack(self):
- self.assertEqual([], Cell.unpack('\x00\x00\x07\x00\x00', 2)[0].versions)
- self.assertEqual([1], Cell.unpack('\x00\x00\x07\x00\x02\x00\x01', 2)[0].versions)
- self.assertEqual([1, 2, 3], Cell.unpack('\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03', 2)[0].versions)
+ test_data = {
+ '\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],
+ }
+
+ for cell_bytes, expected in test_data.items():
+ self.assertEqual(expected, Cell.unpack(cell_bytes, 2)[0].versions)
+
+ def test_certs_unpack(self):
+ test_data = {
+ '\x00\x00\x81\x00\x01\x00': [],
+ '\x00\x00\x81\x00\x04\x01\x01\x00\x00': [Certificate(type = 1, value = '')],
+ '\x00\x00\x81\x00\x05\x01\x01\x00\x01\x08': [Certificate(type = 1, value = '\x08')],
+ }
+
+ for cell_bytes, expected in test_data.items():
+ self.assertEqual(expected, Cell.unpack(cell_bytes, 2)[0].certificates)
+
+ # extra bytes after the last certificate should be ignored
+
+ self.assertEqual([Certificate(type = 1, value = '\x08')], Cell.unpack('\x00\x00\x81\x00\x07\x01\x01\x00\x01\x08\x06\x04', 2)[0].certificates)
+
+ # ... but truncated or missing certificates should error
+
+ self.assertRaisesRegexp(ValueError, 'CERTS cell should have a certificate with 3 bytes, but only had 1 remaining', Cell.unpack, '\x00\x00\x81\x00\x05\x01\x01\x00\x03\x08', 2)
+ self.assertRaisesRegexp(ValueError, 'CERTS cell indicates it should have 2 certificates, but only contained 1', Cell.unpack, '\x00\x00\x81\x00\x05\x02\x01\x00\x01\x08', 2)
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits