[tor-commits] [stem/master] Working onion-key-crosscert verification

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


commit ba1796674172f837e931033d8a060e435b768744
Author: Patrick O'Doherty <p at trickod.com>
Date:   Sun Feb 5 17:08:58 2017 -0800

    Working onion-key-crosscert verification
    
    Compares the digest in the signature block provided with a calculated
    onion-key-crosscert digest and raises a ValueError if they do not match.
---
 stem/descriptor/certificate.py       |  6 +++++-
 stem/descriptor/server_descriptor.py | 38 ++++++++++++++++++++++++++----------
 2 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py
index e26992f..63ebace 100644
--- a/stem/descriptor/certificate.py
+++ b/stem/descriptor/certificate.py
@@ -162,7 +162,11 @@ class Ed25519KeyCertificate(Certificate):
     signed_part = descriptor[:descriptor.index('router-sig-ed25519 ') + len('router-sig-ed25519 ')]
     descriptor_with_prefix = ED25519_ROUTER_SIGNATURE_PREFIX + signed_part
     descriptor_sha256_digest = hashlib.sha256(descriptor_with_prefix).digest()
-    verify_key.verify(descriptor_sha256_digest, signature_bytes)
+
+    try:
+      verify_key.verify(descriptor_sha256_digest, signature_bytes)
+    except BadSignatureError:
+      raise ValueError('Descriptor Ed25519 certificate signature invalid')
 
   def _verify_signature(self):
     if self.identity_key:
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index c5bcaad..7d134dd 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -34,6 +34,7 @@ etc). This information is provided from a few sources...
 import functools
 import hashlib
 import re
+import base64
 
 import stem.descriptor.extrainfo_descriptor
 import stem.exit_policy
@@ -760,23 +761,22 @@ class RelayDescriptor(ServerDescriptor):
         if signed_digest != self.digest():
           raise ValueError('Decrypted digest does not match local digest (calculated: %s, local: %s)' % (signed_digest, self.digest()))
 
+        if self.onion_key_crosscert:
+          onion_key_crosscert_digest = self._digest_for_signature(self.onion_key, self.onion_key_crosscert)
+          if onion_key_crosscert_digest != self.onion_key_crosscert_digest():
+            raise ValueError('Decrypted onion-key-crosscert digest does not match local digest (calculated: %s, local: %s)' % (onion_key_crosscert_digest, self.onion_key_crosscert_digest()))
+
       if stem.prereq.is_nacl_available() and self.ed25519_certificate:
         self.certificate = _parse_certificate(_bytes_for_block(self.ed25519_certificate),
                                               self.ed25519_master_key,
                                               validate)
 
-        if self.ed25519_master_key is not None:
-          if self.certificate.identity_key != self.ed25519_master_key:
-            raise ValueError("master-key-ed25519 does not match ed25519 certificate identity key")
+        if self.certificate.identity_key != self.ed25519_master_key:
+          raise ValueError("master-key-ed25519 does not match ed25519 certificate identity key")
 
-        self.certificate.verify_descriptor_signature(stem.util.str_tools._to_unicode(raw_contents),
+        self.certificate.verify_descriptor_signature(raw_contents,
                                                      self.ed25519_signature)
 
-        onion_key_bytes = _bytes_for_block(self.onion_key)
-        from Crypto.Util import asn1
-        seq = asn1.DerSequence()
-        seq.decode(onion_key_bytes)
-        self._digest_for_signature(self.onion_key, self.onion_key_crosscert)
 
 
   @lru_cache()
@@ -786,11 +786,29 @@ class RelayDescriptor(ServerDescriptor):
 
     :returns: the digest string encoded in uppercase hex
 
-    :raises: ValueError if the digest canot be calculated
+    :raises: ValueError if the digest cannot be calculated
     """
 
     return self._digest_for_content(b'router ', b'\nrouter-signature\n')
 
+
+  @lru_cache()
+  def onion_key_crosscert_digest(self):
+    """
+    Provides the digest of the onion-key-crosscert data consisting of the following:
+
+    1. SHA1 digest of the RSA identity key
+    2. the ed25519 identity key
+
+    :returns: the digest encoded in uppercase hex
+
+    :raises: ValueError if the digest cannot be calculated
+    """
+    signing_key_digest = hashlib.sha1(_bytes_for_block(self.signing_key)).digest()
+    data = signing_key_digest + base64.b64decode(self.ed25519_master_key +  b'=')
+    return data.encode("hex").upper()
+
+
   def _compare(self, other, method):
     if not isinstance(other, RelayDescriptor):
       return False





More information about the tor-commits mailing list