[tor-commits] [stem/master] Drop undocumented 'encoded' attribute from certificates

atagar at torproject.org atagar at torproject.org
Tue Feb 18 07:57:23 UTC 2020


commit 657b8acf95c83ec3836039bf1844d9e55c607956
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Feb 17 16:42:27 2020 -0800

    Drop undocumented 'encoded' attribute from certificates
    
    When an Ed25519Certificate was created through from_base64() we appended an
    undocumented 'encoded' attribute with the base64 content we were created from.
    Our to_base64() method computes the exact same thing.
    
    This attribute was only used in a single place for server descriptor
    validation.
    
    If 'encoded' and to_base64() mismatches that is a bug. Fiddling with these I
    cound't come up with a scenario where that is a case, so dropping the redundant
    attribute.
    
    Also merging _validate_server_desc_signing_key() into its sole caller.
---
 stem/descriptor/certificate.py            | 44 +++++++++++++------------------
 test/unit/descriptor/certificate.py       |  7 +++--
 test/unit/descriptor/server_descriptor.py |  2 +-
 3 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py
index d7c0743d..ae2d6636 100644
--- a/stem/descriptor/certificate.py
+++ b/stem/descriptor/certificate.py
@@ -6,8 +6,8 @@ Parsing for `Tor Ed25519 certificates
 <https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt>`_, which are
 used to for a variety of purposes...
 
-  * validating the key used to sign server descriptors
-  * validating the key used to sign hidden service v3 descriptors
+  * validate the signing key of server descriptors
+  * validate the signing key of hidden service v3 descriptors
   * signing and encrypting hidden service v3 indroductory points
 
 .. versionadded:: 1.6.0
@@ -185,9 +185,7 @@ class Ed25519Certificate(object):
       if not decoded:
         raise TypeError('empty')
 
-      instance = Ed25519Certificate.unpack(decoded)
-      instance.encoded = content
-      return instance
+      return Ed25519Certificate.unpack(decoded)
     except (TypeError, binascii.Error) as exc:
       raise ValueError("Ed25519 certificate wasn't propoerly base64 encoded (%s):\n%s" % (exc, content))
 
@@ -236,7 +234,7 @@ class Ed25519Certificate(object):
 
 class Ed25519CertificateV1(Ed25519Certificate):
   """
-  Version 1 Ed25519 certificate, which are used for signing tor server
+  Version 1 Ed25519 certificate, which sign tor server and hidden service v3
   descriptors.
 
   :var stem.client.datatype.CertType type: certificate purpose
@@ -381,7 +379,21 @@ class Ed25519CertificateV1(Ed25519Certificate):
       signed_content = hashlib.sha256(Ed25519CertificateV1._signed_content(descriptor)).digest()
       signature = stem.util.str_tools._decode_b64(descriptor.ed25519_signature)
 
-      self._validate_server_desc_signing_key(descriptor)
+      # verify that we're created from this descriptor's signing key
+
+      if descriptor.ed25519_master_key:
+        signing_key = base64.b64decode(stem.util.str_tools._to_bytes(descriptor.ed25519_master_key) + b'=')
+      else:
+        signing_key = self.signing_key()
+
+      if not signing_key:
+        raise ValueError('Server descriptor missing an ed25519 signing key')
+
+      try:
+        key = Ed25519PublicKey.from_public_bytes(signing_key)
+        key.verify(self.signature, base64.b64decode(stem.util.str_tools._to_bytes(self.to_base64()))[:-ED25519_SIGNATURE_LENGTH])
+      except InvalidSignature:
+        raise ValueError('Ed25519KeyCertificate signing key is invalid (signature forged or corrupt)')
     elif isinstance(descriptor, stem.descriptor.hidden_service.HiddenServiceDescriptorV3):
       signed_content = Ed25519CertificateV1._signed_content(descriptor)
       signature = stem.util.str_tools._decode_b64(descriptor.signature)
@@ -418,21 +430,3 @@ class Ed25519CertificateV1(Ed25519Certificate):
       raise ValueError('Malformed descriptor missing signature line')
 
     return prefix + match.group(1)
-
-  def _validate_server_desc_signing_key(self, descriptor):
-    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
-    from cryptography.exceptions import InvalidSignature
-
-    if descriptor.ed25519_master_key:
-      signing_key = base64.b64decode(stem.util.str_tools._to_bytes(descriptor.ed25519_master_key) + b'=')
-    else:
-      signing_key = self.signing_key()
-
-    if not signing_key:
-      raise ValueError('Server descriptor missing an ed25519 signing key')
-
-    try:
-      key = Ed25519PublicKey.from_public_bytes(signing_key)
-      key.verify(self.signature, base64.b64decode(stem.util.str_tools._to_bytes(self.encoded))[:-ED25519_SIGNATURE_LENGTH])
-    except InvalidSignature:
-      raise ValueError('Ed25519KeyCertificate signing key is invalid (signature forged or corrupt)')
diff --git a/test/unit/descriptor/certificate.py b/test/unit/descriptor/certificate.py
index 9e29556a..000de2de 100644
--- a/test/unit/descriptor/certificate.py
+++ b/test/unit/descriptor/certificate.py
@@ -58,7 +58,7 @@ class TestEd25519Certificate(unittest.TestCase):
 
     self.assertEqual(Ed25519CertificateV1, type(cert))
     self.assertEqual(1, cert.version)
-    self.assertEqual(stem.util.str_tools._to_unicode(cert_bytes), cert.encoded)
+    self.assertEqual(stem.util.str_tools._to_unicode(cert_bytes), cert.to_base64().replace('\n', ''))
     self.assertEqual(CertType.ED25519_SIGNING, cert.type)
     self.assertEqual(datetime.datetime(1970, 1, 1, 0, 0), cert.expiration)
     self.assertEqual(1, cert.key_type)
@@ -82,7 +82,7 @@ class TestEd25519Certificate(unittest.TestCase):
 
     self.assertEqual(Ed25519CertificateV1, type(cert))
     self.assertEqual(1, cert.version)
-    self.assertEqual(ED25519_CERT, cert.encoded)
+    self.assertEqual(ED25519_CERT, cert.to_base64())
     self.assertEqual(CertType.ED25519_SIGNING, cert.type)
     self.assertEqual(datetime.datetime(2015, 8, 28, 17, 0), cert.expiration)
     self.assertEqual(1, cert.key_type)
@@ -109,8 +109,7 @@ class TestEd25519Certificate(unittest.TestCase):
     """
 
     cert = Ed25519Certificate.from_base64(ED25519_CERT)
-    self.assertEqual(ED25519_CERT, cert.encoded)  # read base64 encoding (getting removed in stem 2.x)
-    self.assertEqual(ED25519_CERT, cert.to_base64())  # computed base64 encoding
+    self.assertEqual(ED25519_CERT, cert.to_base64())
 
   def test_non_base64(self):
     """
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index e1036ada..07f50013 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -355,7 +355,7 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
     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)
+    self.assertTrue('bWPo2fIzo3uOywfoM' in desc.certificate.to_base64())
 
     extension = desc.certificate.extensions[0]
     self.assertEqual(ExtensionType.HAS_SIGNING_KEY, extension.type)



More information about the tor-commits mailing list