[tor-commits] [stem/master] Support hash types and encodings for server descriptor digests

atagar at torproject.org atagar at torproject.org
Thu Nov 15 20:29:50 UTC 2018


commit de42798f432d05fc1e7d626ab8ce311b1368f5f0
Author: Damian Johnson <atagar at torproject.org>
Date:   Thu Nov 15 11:56:20 2018 -0800

    Support hash types and encodings for server descriptor digests
    
    Replicating what I just did for extrainfo descriptors with server descriptors.
---
 stem/descriptor/extrainfo_descriptor.py   |  5 ++--
 stem/descriptor/server_descriptor.py      | 38 ++++++++++++++++++++++++-------
 test/unit/descriptor/server_descriptor.py |  1 +
 3 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 4319bb05..401b9643 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -966,9 +966,8 @@ class RelayExtraInfoDescriptor(ExtraInfoDescriptor):
     if hash_type == DigestHash.SHA1:
       # our digest is calculated from everything except our signature
 
-      raw_content, ending = str(self), '\nrouter-signature\n'
-      raw_content = stem.util.str_tools._to_bytes(raw_content[:raw_content.find(ending) + len(ending)])
-      return stem.descriptor._encode_digest(hashlib.sha1(raw_content), encoding)
+      content = self._content_range(end = '\nrouter-signature\n')
+      return stem.descriptor._encode_digest(hashlib.sha1(content), encoding)
     elif hash_type == DigestHash.SHA256:
       # Due to a tor bug sha256 digests are calculated from the
       # whole descriptor rather than ommiting the signature...
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 0d12f875..748a2a9d 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -68,6 +68,8 @@ from stem.descriptor.router_status_entry import RouterStatusEntryV3
 from stem.descriptor import (
   PGP_BLOCK_END,
   Descriptor,
+  DigestHash,
+  DigestEncoding,
   create_signing_key,
   _descriptor_content,
   _descriptor_components,
@@ -654,12 +656,22 @@ class ServerDescriptor(Descriptor):
     else:
       self._entries = entries
 
-  def digest(self):
+  def digest(self, hash_type = DigestHash.SHA1, encoding = DigestEncoding.HEX):
     """
-    Provides the hex encoded sha1 of our content. This value is part of the
-    network status entry for this relay.
+    Digest of this descriptor's content. These are referenced by...
 
-    :returns: **unicode** with the upper-case hex digest value for this server descriptor
+      * **Consensus**
+
+        * Referer: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` **digest** attribute
+        * Format: **SHA1/BASE64**
+
+    .. versionchanged:: 1.8.0
+       Added the hash_type and encoding arguments.
+
+    :param stem.descriptor.DigestHash hash_type: digest hashing algorithm
+    :param stem.descriptor.DigestEncoding encoding: digest encoding
+
+    :returns: **hashlib.HASH** or **str** based on our encoding argument
     """
 
     raise NotImplementedError('Unsupported Operation: this should be implemented by the ServerDescriptor subclass')
@@ -890,7 +902,7 @@ class RelayDescriptor(ServerDescriptor):
     return cls(cls.content(attr, exclude, sign, signing_key), validate = validate, skip_crypto_validation = not sign)
 
   @lru_cache()
-  def digest(self):
+  def digest(self, hash_type = DigestHash.SHA1, encoding = DigestEncoding.HEX):
     """
     Provides the digest of our descriptor's content.
 
@@ -899,7 +911,14 @@ class RelayDescriptor(ServerDescriptor):
     :raises: ValueError if the digest cannot be calculated
     """
 
-    return self._digest_for_content(b'router ', b'\nrouter-signature\n')
+    content = self._content_range(start = 'router', end = '\nrouter-signature\n')
+
+    if hash_type == DigestHash.SHA1:
+      return stem.descriptor._encode_digest(hashlib.sha1(content), encoding)
+    elif hash_type == DigestHash.SHA256:
+      return stem.descriptor._encode_digest(hashlib.sha256(content), encoding)
+    else:
+      raise NotImplementedError('Server descriptor digests are only available in sha1 and sha256, not %s' % hash_type)
 
   def make_router_status_entry(self):
     """
@@ -1026,8 +1045,11 @@ class BridgeDescriptor(ServerDescriptor):
       ('reject', '*:*'),
     ))
 
-  def digest(self):
-    return self._digest
+  def digest(self, hash_type = DigestHash.SHA1, encoding = DigestEncoding.HEX):
+    if hash_type == DigestHash.SHA1 and encoding == DigestEncoding.HEX:
+      return self._digest
+    else:
+      raise NotImplementedError('Bridge server descriptor digests are only available as sha1/hex, not %s/%s' % (hash_type, encoding))
 
   def is_scrubbed(self):
     """
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index ec1af553..796286c5 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -154,6 +154,7 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
     self.assertEqual(expected_signature, desc.signature)
     self.assertEqual([], desc.get_unrecognized_lines())
     self.assertEqual('2C7B27BEAB04B4E2459D89CA6D5CD1CC5F95A689', desc.digest())
+    self.assertEqual('LHsnvqsEtOJFnYnKbVzRzF+Vpok', desc.digest(encoding = stem.descriptor.DigestEncoding.BASE64))
 
     self.assertEqual('@type server-descriptor 1.0', str(desc.type_annotation()))
     self.assertEqual(['2'], desc.hidden_service_dir)  # obsolete field





More information about the tor-commits mailing list