[tor-commits] [stem/master] Python3 support for ed25519

atagar at torproject.org atagar at torproject.org
Thu Mar 30 04:18:03 UTC 2017


commit 7bac71f5952a36ba4a2dffcc20c7a79f4fb7d7be
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed Mar 29 20:57:31 2017 -0700

    Python3 support for ed25519
    
    Handful of tweaks to get this working with python3.
---
 stem/descriptor/certificate.py            | 21 +++++++++++----------
 stem/descriptor/server_descriptor.py      |  2 +-
 test/unit/descriptor/certificate.py       | 15 ++++++++-------
 test/unit/descriptor/server_descriptor.py |  6 +++---
 4 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py
index d9a36f3..cd7710c 100644
--- a/stem/descriptor/certificate.py
+++ b/stem/descriptor/certificate.py
@@ -57,6 +57,7 @@ used to validate the key used to sign server descriptors.
 """
 
 import base64
+import binascii
 import collections
 import datetime
 import hashlib
@@ -111,14 +112,14 @@ class Ed25519Certificate(object):
     """
 
     try:
-      decoded = base64.b64decode(content)
+      decoded = base64.b64decode(stem.util.str_tools._to_bytes(content))
 
       if not decoded:
         raise TypeError('empty')
-    except TypeError as exc:
+    except (TypeError, binascii.Error) as exc:
       raise ValueError("Ed25519 certificate wasn't propoerly base64 encoded (%s):\n%s" % (exc, content))
 
-    version = stem.util.str_tools._to_int(decoded[0])
+    version = stem.util.str_tools._to_int(decoded[0:1])
 
     if version == 1:
       return Ed25519CertificateV1(version, content, decoded)
@@ -145,7 +146,7 @@ class Ed25519CertificateV1(Ed25519Certificate):
     if len(decoded) < ED25519_HEADER_LENGTH + ED25519_SIGNATURE_LENGTH:
       raise ValueError('Ed25519 certificate was %i bytes, but should be at least %i' % (len(decoded), ED25519_HEADER_LENGTH + ED25519_SIGNATURE_LENGTH))
 
-    cert_type = stem.util.str_tools._to_int(decoded[1])
+    cert_type = stem.util.str_tools._to_int(decoded[1:2])
 
     if cert_type in (0, 1, 2, 3):
       raise ValueError('Ed25519 certificate cannot have a type of %i. This is reserved to avoid conflicts with tor CERTS cells.' % cert_type)
@@ -163,12 +164,12 @@ class Ed25519CertificateV1(Ed25519Certificate):
     # expiration time is in hours since epoch
     self.expiration = datetime.datetime.utcfromtimestamp(stem.util.str_tools._to_int(decoded[2:6]) * 3600)
 
-    self.key_type = stem.util.str_tools._to_int(decoded[6])
+    self.key_type = stem.util.str_tools._to_int(decoded[6:7])
     self.key = decoded[7:39]
     self.signature = decoded[-ED25519_SIGNATURE_LENGTH:]
 
     self.extensions = []
-    extension_count = stem.util.str_tools._to_int(decoded[39])
+    extension_count = stem.util.str_tools._to_int(decoded[39:40])
     remaining_data = decoded[40:-ED25519_SIGNATURE_LENGTH]
 
     for i in range(extension_count):
@@ -176,8 +177,8 @@ class Ed25519CertificateV1(Ed25519Certificate):
         raise ValueError('Ed25519 extension is missing header field data')
 
       extension_length = stem.util.str_tools._to_int(remaining_data[:2])
-      extension_type = stem.util.str_tools._to_int(remaining_data[2])
-      extension_flags = stem.util.str_tools._to_int(remaining_data[3])
+      extension_type = stem.util.str_tools._to_int(remaining_data[2:3])
+      extension_flags = stem.util.str_tools._to_int(remaining_data[3:4])
       extension_data = remaining_data[4:4 + extension_length]
 
       if extension_length != len(extension_data):
@@ -234,7 +235,7 @@ class Ed25519CertificateV1(Ed25519Certificate):
     signing_key = None
 
     if server_descriptor.ed25519_master_key:
-      signing_key = nacl.signing.VerifyKey(server_descriptor.ed25519_master_key + '=', encoder = nacl.encoding.Base64Encoder)
+      signing_key = nacl.signing.VerifyKey(stem.util.str_tools._to_bytes(server_descriptor.ed25519_master_key) + b'=', encoder = nacl.encoding.Base64Encoder)
     else:
       for extension in self.extensions:
         if extension.type == ExtensionType.HAS_SIGNING_KEY:
@@ -245,7 +246,7 @@ class Ed25519CertificateV1(Ed25519Certificate):
       raise ValueError('Server descriptor missing an ed25519 signing key')
 
     try:
-      signing_key.verify(base64.b64decode(self.encoded)[:-ED25519_SIGNATURE_LENGTH], self.signature)
+      signing_key.verify(base64.b64decode(stem.util.str_tools._to_bytes(self.encoded))[:-ED25519_SIGNATURE_LENGTH], self.signature)
     except BadSignatureError as exc:
       raise ValueError('Ed25519KeyCertificate signing key is invalid (%s)' % exc)
 
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 35b1303..1cedbe5 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -811,7 +811,7 @@ class RelayDescriptor(ServerDescriptor):
     """
 
     signing_key_digest = hashlib.sha1(_bytes_for_block(self.signing_key)).digest()
-    data = signing_key_digest + base64.b64decode(self.ed25519_master_key + '=')
+    data = signing_key_digest + base64.b64decode(stem.util.str_tools._to_bytes(self.ed25519_master_key) + b'=')
     return stem.util.str_tools._to_unicode(binascii.hexlify(data).upper())
 
   def _compare(self, other, method):
diff --git a/test/unit/descriptor/certificate.py b/test/unit/descriptor/certificate.py
index a3bea04..669d9ad 100644
--- a/test/unit/descriptor/certificate.py
+++ b/test/unit/descriptor/certificate.py
@@ -8,6 +8,7 @@ import re
 import unittest
 
 import stem.descriptor.certificate
+import stem.util.str_tools
 import stem.prereq
 import test.runner
 
@@ -20,9 +21,9 @@ ptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8sGG8lTjx1
 g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98Ljhdp2w4=
 """.strip()
 
-EXPECTED_CERT_KEY = '\xa5\xb6\x1a\x80D\x0fR#cp:\x7f\xa1\x8d\xa8\x11%\xe4\x0f7|=\x99k\xdb\xa9\x1aG\xb9\xd4\x91\xaa'
-EXPECTED_EXTENSION_DATA = 'g\xa6\xb5Q\xa6\xd2+\xe3v\xd6>\x8d\x9f#:7\xb8\xec\xb0~\x83+\xaf*k\xa5\xb9\xb8\x1e\x10\xa4d'
-EXPECTED_SIGNATURE = '\xc6\x8e\xd3\xae\x0b?\xedJ6\xe2\xef\x95\xcf,\x18o%N<u\x83\x897\x10\xbb\x96b\x01\xd8YNk\x02&\xbb\x9e^ Q\xf0Y8G\xc7\x01\xf2\x84K\xb9ww\xad\xdd\x04H\xc4_\xdf\x0b\x8e\x17i\xdb\x0e'
+EXPECTED_CERT_KEY = b'\xa5\xb6\x1a\x80D\x0fR#cp:\x7f\xa1\x8d\xa8\x11%\xe4\x0f7|=\x99k\xdb\xa9\x1aG\xb9\xd4\x91\xaa'
+EXPECTED_EXTENSION_DATA = b'g\xa6\xb5Q\xa6\xd2+\xe3v\xd6>\x8d\x9f#:7\xb8\xec\xb0~\x83+\xaf*k\xa5\xb9\xb8\x1e\x10\xa4d'
+EXPECTED_SIGNATURE = b'\xc6\x8e\xd3\xae\x0b?\xedJ6\xe2\xef\x95\xcf,\x18o%N<u\x83\x897\x10\xbb\x96b\x01\xd8YNk\x02&\xbb\x9e^ Q\xf0Y8G\xc7\x01\xf2\x84K\xb9ww\xad\xdd\x04H\xc4_\xdf\x0b\x8e\x17i\xdb\x0e'
 
 
 def certificate(version = 1, cert_type = 4, extension_data = []):
@@ -34,13 +35,13 @@ def certificate(version = 1, cert_type = 4, extension_data = []):
   :param list extension_data: extensions to embed within the certificate
   """
 
-  return base64.b64encode(''.join([
-    chr(version),
-    chr(cert_type),
+  return base64.b64encode(b''.join([
+    stem.util.str_tools._to_bytes(chr(version)),
+    stem.util.str_tools._to_bytes(chr(cert_type)),
     b'\x00' * 4,               # expiration date, leaving this as the epoch
     b'\x01',                   # key type
     b'\x03' * 32,              # key
-    chr(len(extension_data)),  # extension count
+    stem.util.str_tools._to_bytes(chr(len(extension_data))),  # extension count
     b''.join(extension_data),
     b'\x01' * ED25519_SIGNATURE_LENGTH]))
 
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index 38dcdce..42fa392 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -270,8 +270,8 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
     self.assertEqual(CertType.SIGNING, desc.certificate.type)
     self.assertEqual(datetime.datetime(2015, 8, 28, 17, 0, 0), desc.certificate.expiration)
     self.assertEqual(1, desc.certificate.key_type)
-    self.assertTrue(desc.certificate.key.startswith('\xa5\xb6\x1a\x80D\x0f'))
-    self.assertTrue(desc.certificate.signature.startswith('\xc6\x8e\xd3\xae\x0b'))
+    self.assertTrue(desc.certificate.key.startswith(b'\xa5\xb6\x1a\x80D\x0f'))
+    self.assertTrue(desc.certificate.signature.startswith(b'\xc6\x8e\xd3\xae\x0b'))
     self.assertEqual(1, len(desc.certificate.extensions))
     self.assertTrue('bWPo2fIzo3uOywfoM' in desc.certificate.encoded)
 
@@ -279,7 +279,7 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
     self.assertEqual(ExtensionType.HAS_SIGNING_KEY, extension.type)
     self.assertEqual([], extension.flags)
     self.assertEqual(0, extension.flag_int)
-    self.assertTrue(extension.data.startswith('g\xa6\xb5Q\xa6\xd2'))
+    self.assertTrue(extension.data.startswith(b'g\xa6\xb5Q\xa6\xd2'))
 
     self.assertEqual('destiny', desc.nickname)
     self.assertEqual('F65E0196C94DFFF48AFBF2F5F9E3E19AAE583FD0', desc.fingerprint)





More information about the tor-commits mailing list