commit 8530ad6f5386c8dd1112a9e071f60aa002d14566 Author: Damian Johnson atagar@torproject.org Date: Thu Nov 14 14:19:40 2019 -0800
Fix python 3.x support
This might *not* fully fix python3 support, but closer. I don't quite grok why but my openssl bindings have ed25519 support with python 2.7 but not 3.5. Oh well, fixing what I can for now.
% python Python 2.7.12 (default, Oct 8 2019, 14:14:10)
>>> import cryptography >>> cryptography.__version__ '2.7'
>>> from cryptography.hazmat.backends.openssl.backend import backend >>> backend.ed25519_supported() True
------------------------------------------------------------
% python3 Python 3.5.2 (default, Oct 8 2019, 13:06:37)
>>> import cryptography >>> cryptography.__version__ '2.8'
>>> from cryptography.hazmat.backends.openssl.backend import backend >>> backend.ed25519_supported() False --- stem/descriptor/certificate.py | 10 ++++------ stem/descriptor/hidden_service.py | 7 ++++--- stem/util/__init__.py | 7 ++++--- test/unit/descriptor/hidden_service_v3.py | 9 +++++++-- 4 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py index 10518364..74a4e08c 100644 --- a/stem/descriptor/certificate.py +++ b/stem/descriptor/certificate.py @@ -307,7 +307,7 @@ class Ed25519CertificateV1(Ed25519Certificate): self.type, self.type_int = ClientCertType.get(cert_type) self.expiration = expiration if expiration else datetime.datetime.utcnow() + datetime.timedelta(hours = DEFAULT_EXPIRATION_HOURS) self.key_type = key_type if key_type else 1 - self.key = key if isinstance(key, str) else stem.util._pubkey_bytes(key) + self.key = stem.util._pubkey_bytes(key) self.extensions = extensions if extensions else [] self.signature = signature
@@ -371,9 +371,7 @@ class Ed25519CertificateV1(Ed25519Certificate): if extension_data: raise ValueError('Ed25519 certificate had %i bytes of unused extension data' % len(extension_data))
- instance = Ed25519CertificateV1(cert_type, datetime.datetime.utcfromtimestamp(expiration_hours * 3600), key_type, key, extensions, signature) - - return instance + return Ed25519CertificateV1(cert_type, datetime.datetime.utcfromtimestamp(expiration_hours * 3600), key_type, key, extensions, signature)
def is_expired(self): """ @@ -448,10 +446,10 @@ class Ed25519CertificateV1(Ed25519Certificate):
if isinstance(descriptor, stem.descriptor.server_descriptor.RelayDescriptor): prefix = SIG_PREFIX_SERVER_DESC - regex = '(.+router-sig-ed25519 )' + regex = b'(.+router-sig-ed25519 )' elif isinstance(descriptor, stem.descriptor.hidden_service.HiddenServiceDescriptorV3): prefix = SIG_PREFIX_HS_V3 - regex = '(.+)signature ' + regex = b'(.+)signature ' else: raise ValueError('BUG: %s type unexpected' % type(descriptor).__name__)
diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py index 604c3849..dd4ab934 100644 --- a/stem/descriptor/hidden_service.py +++ b/stem/descriptor/hidden_service.py @@ -563,7 +563,7 @@ def _parse_v3_introduction_points(descriptor, entries): remaining = descriptor._unparsed_introduction_points
while remaining: - div = remaining.find('\nintroduction-point ', 10) + div = remaining.find(b'\nintroduction-point ', 10) content, remaining = (remaining[:div], remaining[div + 1:]) if div != -1 else (remaining, '')
introduction_points.append(IntroductionPointV3.parse(content)) @@ -1257,7 +1257,7 @@ class InnerLayer(Descriptor):
return _descriptor_content(attr, exclude, ( ('create2-formats', '2'), - )) + suffix + )) + stem.util.str_tools._to_bytes(suffix)
@classmethod def create(cls, attr = None, exclude = (), validate = True, sign = False, introduction_points = None): @@ -1270,7 +1270,8 @@ class InnerLayer(Descriptor): # inner layer begins with a few header fields, followed by any # number of introduction-points
- div = content.find('\nintroduction-point ') + content = stem.util.str_tools._to_bytes(content) + div = content.find(b'\nintroduction-point ')
if div != -1: self._unparsed_introduction_points = content[div + 1:] diff --git a/stem/util/__init__.py b/stem/util/__init__.py index a8870499..eb4e0618 100644 --- a/stem/util/__init__.py +++ b/stem/util/__init__.py @@ -132,6 +132,9 @@ def _pubkey_bytes(key): Normalizes X25509 and ED25519 keys into their public key bytes. """
+ if _is_str(key): + return key + if not stem.prereq.is_crypto_available(): raise ImportError('Key normalization requires the cryptography module') elif not stem.prereq.is_crypto_available(ed25519 = True): @@ -141,9 +144,7 @@ def _pubkey_bytes(key): from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
- if isinstance(key, str): - return key - elif isinstance(key, (X25519PrivateKey, Ed25519PrivateKey)): + if isinstance(key, (X25519PrivateKey, Ed25519PrivateKey)): return key.public_key().public_bytes( encoding = serialization.Encoding.Raw, format = serialization.PublicFormat.Raw, diff --git a/test/unit/descriptor/hidden_service_v3.py b/test/unit/descriptor/hidden_service_v3.py index 81e04a0f..893ef29e 100644 --- a/test/unit/descriptor/hidden_service_v3.py +++ b/test/unit/descriptor/hidden_service_v3.py @@ -162,6 +162,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase): self.assertEqual(None, intro_point.legacy_key_raw) self.assertEqual(None, intro_point.legacy_key_cert)
+ @test.require.ed25519_support def test_required_fields(self): """ Check that we require the mandatory fields. @@ -180,6 +181,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase): desc_text = HiddenServiceDescriptorV3.content(exclude = (line,)) expect_invalid_attr_for_text(self, desc_text, line_to_attr[line], None)
+ @test.require.ed25519_support def test_invalid_version(self): """ Checks that our version field expects a numeric value. @@ -194,6 +196,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase): for test_value in test_values: expect_invalid_attr(self, {'hs-descriptor': test_value}, 'version')
+ @test.require.ed25519_support def test_invalid_lifetime(self): """ Checks that our lifetime field expects a numeric value. @@ -208,6 +211,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase): for test_value in test_values: expect_invalid_attr(self, {'descriptor-lifetime': test_value}, 'lifetime')
+ @test.require.ed25519_support def test_invalid_revision_counter(self): """ Checks that our revision counter field expects a numeric value. @@ -302,6 +306,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase): reparsed = IntroductionPointV3.parse(intro_point.encode()) self.assertEqual(intro_point, reparsed)
+ @test.require.ed25519_support def test_inner_layer_creation(self): """ Internal layer creation. @@ -309,12 +314,12 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase):
# minimal layer
- self.assertEqual('create2-formats 2', InnerLayer.content()) + self.assertEqual(b'create2-formats 2', InnerLayer.content()) self.assertEqual([2], InnerLayer.create().formats)
# specify their only mandatory parameter (formats)
- self.assertEqual('create2-formats 1 2 3', InnerLayer.content({'create2-formats': '1 2 3'})) + self.assertEqual(b'create2-formats 1 2 3', InnerLayer.content({'create2-formats': '1 2 3'})) self.assertEqual([1, 2, 3], InnerLayer.create({'create2-formats': '1 2 3'}).formats)
# include optional parameters