commit de42798f432d05fc1e7d626ab8ce311b1368f5f0 Author: Damian Johnson atagar@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