[tor-commits] [stem/master] Only import crypto modules if available

atagar at torproject.org atagar at torproject.org
Sun Oct 6 02:07:34 UTC 2019


commit ec4d6f99e55b2ca62b7def152d31364de605c2fd
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed Sep 4 17:34:00 2019 -0700

    Only import crypto modules if available
    
    Stem has a soft dependency on the cryptography module. If unavailable we should
    gracefully degrade or explicitly error with a message saying that cryptography
    is required.
    
    Also, cryptography's ed25519 class is pretty new, so folks will have outdated
    module versions for a while...
    
      ======================================================================
      ERROR: test_for_decrypt
      ----------------------------------------------------------------------
      Traceback (most recent call last):
        File "/home/atagar/Desktop/stem/test/unit/descriptor/hidden_service_v3.py", line 43, in test_for_decrypt
          onion_address="sltib6sxkuxh2scmtuvd5w2g7pahnzkovefxpo4e4ptnkzl5kkq5h2ad.onion"))
        File "/home/atagar/Desktop/stem/stem/descriptor/__init__.py", line 442, in parse_file
          for desc in parse(descriptor_file):
        File "/home/atagar/Desktop/stem/stem/descriptor/__init__.py", line 545, in _parse_metrics_file
          for desc in stem.descriptor.hidden_service._parse_file(descriptor_file, desc_type, validate = validate, **kwargs):
        File "/home/atagar/Desktop/stem/stem/descriptor/hidden_service.py", line 156, in _parse_file
          yield desc_type(bytes.join(b'', descriptor_content), validate, **kwargs)
        File "/home/atagar/Desktop/stem/stem/descriptor/hidden_service.py", line 571, in __init__
          plaintext = self.decrypt_descriptor(desc_signing_cert)
        File "/home/atagar/Desktop/stem/stem/descriptor/hidden_service.py", line 579, in decrypt_descriptor
          identity_public_key = stem.descriptor.hsv3_crypto.decode_address(self.onion_address)
        File "/home/atagar/Desktop/stem/stem/descriptor/hsv3_crypto.py", line 30, in decode_address
          from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
      ImportError: No module named ed25519
---
 stem/descriptor/hidden_service.py | 20 +++++++++++---------
 stem/descriptor/hsv3_crypto.py    | 16 ++++++++++++----
 stem/prereq.py                    | 10 +++++++++-
 3 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py
index 5397d057..150ba368 100644
--- a/stem/descriptor/hidden_service.py
+++ b/stem/descriptor/hidden_service.py
@@ -31,6 +31,8 @@ import collections
 import hashlib
 import io
 
+import stem.descriptor.certificate
+import stem.descriptor.hsv3_crypto
 import stem.prereq
 import stem.util.connection
 import stem.util.str_tools
@@ -470,9 +472,6 @@ class HiddenServiceDescriptorV2(BaseHiddenServiceDescriptor):
 
     return introduction_points
 
-import stem.descriptor.certificate
-import stem.descriptor.hsv3_crypto as hsv3_crypto
-from cryptography.hazmat.primitives import serialization
 
 class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor):
   """
@@ -568,29 +567,32 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor):
     # ASN XXX need to verify descriptor signing certificate (for now we trust Tor to do it)
     # ASN XXX need to verify descriptor signature (for now we trust Tor to do it)
 
-    plaintext = self.decrypt_descriptor(desc_signing_cert)
+    if not skip_crypto_validation and stem.prereq.is_crypto_available():
+      plaintext = self.decrypt_descriptor(desc_signing_cert)
 
   def decrypt_descriptor(self, desc_signing_cert):
     # Get crypto material.
     # ASN XXX Extract to its own function and assign them to class variables
+    from cryptography.hazmat.primitives import serialization
+
     blinded_key_bytes = desc_signing_cert.get_signing_key()
-    identity_public_key = hsv3_crypto.decode_address(self.onion_address)
+    identity_public_key = stem.descriptor.hsv3_crypto.decode_address(self.onion_address)
     identity_public_key_bytes = identity_public_key.public_bytes(encoding=serialization.Encoding.Raw,
                                                                  format=serialization.PublicFormat.Raw)
     assert(len(identity_public_key_bytes) == 32)
     assert(len(blinded_key_bytes) == 32)
 
-    subcredential_bytes = hsv3_crypto.get_subcredential(identity_public_key_bytes, blinded_key_bytes)
+    subcredential_bytes = stem.descriptor.hsv3_crypto.get_subcredential(identity_public_key_bytes, blinded_key_bytes)
 
     ####################################### Do the decryption ###################################
 
-    outter_layer_plaintext = hsv3_crypto.decrypt_outter_layer(self.superencrypted, self.revision_counter,
+    outter_layer_plaintext = stem.descriptor.hsv3_crypto.decrypt_outter_layer(self.superencrypted, self.revision_counter,
                                                               identity_public_key_bytes, blinded_key_bytes, subcredential_bytes)
 
     # ATAGAR XXX this parsing function is a hack. need to replace it with some stem parsing.
-    inner_layer_ciphertext = hsv3_crypto.parse_superencrypted_plaintext(outter_layer_plaintext)
+    inner_layer_ciphertext = stem.descriptor.hsv3_crypto.parse_superencrypted_plaintext(outter_layer_plaintext)
 
-    inner_layer_plaintext =  hsv3_crypto.decrypt_inner_layer(inner_layer_ciphertext, self.revision_counter,
+    inner_layer_plaintext =  stem.descriptor.hsv3_crypto.decrypt_inner_layer(inner_layer_ciphertext, self.revision_counter,
                                                               identity_public_key_bytes, blinded_key_bytes, subcredential_bytes)
 
     print(inner_layer_plaintext)
diff --git a/stem/descriptor/hsv3_crypto.py b/stem/descriptor/hsv3_crypto.py
index de88b7ac..8f304c52 100644
--- a/stem/descriptor/hsv3_crypto.py
+++ b/stem/descriptor/hsv3_crypto.py
@@ -1,10 +1,7 @@
 import base64
 import hashlib
 
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
-from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
-from cryptography.hazmat.backends import default_backend
-
+import stem.prereq
 
 """
 Onion addresses
@@ -32,6 +29,14 @@ def decode_address(onion_address_str):
 
     :raises: ValueError
     """
+
+    # TODO: note the module version
+
+    if not stem.prereq.is_crypto_available(ed25519 = True):
+      raise ImportError('Onion address decoding requires cryptography version XXX')
+
+    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
+
     if (len(onion_address_str) != 56 + len(".onion")):
         raise ValueError("Wrong address length")
 
@@ -149,6 +154,9 @@ def _ciphertext_mac_is_valid(key, salt, ciphertext, mac):
 def _decrypt_descriptor_layer(ciphertext_blob_b64, revision_counter,
                               public_identity_key, subcredential,
                               secret_data, string_constant):
+    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+    from cryptography.hazmat.backends import default_backend
+
     # decode the thing
     ciphertext_blob = base64.b64decode(ciphertext_blob_b64)
 
diff --git a/stem/prereq.py b/stem/prereq.py
index 4cb51113..0aadb35a 100644
--- a/stem/prereq.py
+++ b/stem/prereq.py
@@ -114,11 +114,13 @@ def is_sqlite_available():
     return False
 
 
-def is_crypto_available():
+def is_crypto_available(ed25519 = False):
   """
   Checks if the cryptography functions we use are available. This is used for
   verifying relay descriptor signatures.
 
+  :param bool ed25519: check for ed25519 support
+
   :returns: **True** if we can use the cryptography module and **False**
     otherwise
   """
@@ -134,6 +136,12 @@ def is_crypto_available():
     if not hasattr(rsa.RSAPrivateKey, 'sign'):
       raise ImportError()
 
+    # TODO: Check when the cryptography module's ed25519 class was added
+    # (it's not present in 2.0.3).
+
+    if ed25519:
+      from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
+
     return True
   except ImportError:
     from stem.util import log





More information about the tor-commits mailing list