[tor-commits] [stem/master] Fix python 3.x support

atagar at torproject.org atagar at torproject.org
Sun Nov 17 23:40:39 UTC 2019


commit 8530ad6f5386c8dd1112a9e071f60aa002d14566
Author: Damian Johnson <atagar at 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





More information about the tor-commits mailing list