[tor-commits] [stem/master] Adjust extended v3 HS address validation

atagar at torproject.org atagar at torproject.org
Wed Feb 10 00:15:02 UTC 2021


commit 63a476056017dda5ede35efc4e4f7acfcc1d7d1a
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Feb 9 16:12:36 2021 -0800

    Adjust extended v3 HS address validation
    
    Mostly minor stylistic adjustments. The only functional bit is correcting a
    unit test failure...
    
            ======================================================================
            FAIL: test_identity_key_from_address
            ----------------------------------------------------------------------
            ValueError: '55555555555555555555555555555555555555555555555555555555.onion' isn't a valid hidden service v3 address
    
            During handling of the above exception, another exception occurred:
    
            Traceback (most recent call last):
            File "/home/atagar/Desktop/stem/test/unit/descriptor/hidden_service_v3.py", line 220, in test_identity_key_from_address
            self.assertRaisesWith(ValueError, 'Bad checksum (expected def7 but was 842e)', HiddenServiceDescriptorV3.identity_key_from_address, '5' * 56)
            File "/home/atagar/Desktop/stem/stem/util/test_tools.py", line 249, in assertRaisesWith
            return self.assertRaisesRegexp(exc_type, '^%s$' % re.escape(exc_msg), *args, **kwargs)
            AssertionError: "^Bad\ checksum\ \(expected\ def7\ but\ was\ 842e\)$" does not match "'55555555555555555555555555555555555555555555555555555555.onion' isn't a valid hidden service v3 address"
    
    ----------------------------------------------------------------------
---
 stem/descriptor/hidden_service.py |  2 +-
 stem/util/tor_tools.py            | 35 +++++++++++++----------------
 test/unit/util/tor_tools.py       | 46 ++++++++++++++++++---------------------
 3 files changed, 37 insertions(+), 46 deletions(-)

diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py
index 63f107e7..249c2153 100644
--- a/stem/descriptor/hidden_service.py
+++ b/stem/descriptor/hidden_service.py
@@ -1129,7 +1129,7 @@ class HiddenServiceDescriptorV3(HiddenServiceDescriptor):
     if onion_address.endswith('.onion'):
       onion_address = onion_address[:-6]
 
-    if not stem.util.tor_tools.is_valid_hidden_service_address(onion_address, version = 3):
+    if not stem.util.tor_tools.HS_V3_ADDRESS_PATTERN.match(onion_address):
       raise ValueError("'%s.onion' isn't a valid hidden service v3 address" % onion_address)
 
     # onion_address = base32(PUBKEY | CHECKSUM | VERSION) + '.onion'
diff --git a/stem/util/tor_tools.py b/stem/util/tor_tools.py
index c9a04e33..e758b897 100644
--- a/stem/util/tor_tools.py
+++ b/stem/util/tor_tools.py
@@ -19,9 +19,9 @@ Miscellaneous utility functions for working with tor.
   is_hex_digits - checks if a string is only made up of hex digits
 """
 
+import base64
+import hashlib
 import re
-from base64 import b32decode
-from hashlib import sha3_256
 
 import stem.util.str_tools
 
@@ -47,7 +47,6 @@ CIRC_ID_PATTERN = re.compile('^[a-zA-Z0-9]{1,16}$')
 
 HS_V2_ADDRESS_PATTERN = re.compile('^[a-z2-7]{16}$')
 HS_V3_ADDRESS_PATTERN = re.compile('^[a-z2-7]{56}$')
-HS_V3_CHECKSUM_CONSTANT = ".onion checksum"
 
 
 def is_valid_fingerprint(entry: str, check_prefix: bool = False) -> bool:
@@ -156,14 +155,6 @@ def is_valid_hidden_service_address(entry: str, version: Optional[Union[int, Seq
     otherwise
   """
 
-  def _extract_v3_parts(address):
-    decoded = b32decode(address.upper())
-    return (decoded[:32], decoded[32:34])
-
-  v3_pubkey = None
-  v3_checksum = None
-  v3_version = int(3).to_bytes(1, 'little')
-
   if isinstance(entry, bytes):
     entry = stem.util.str_tools._to_unicode(entry)
 
@@ -179,15 +170,19 @@ def is_valid_hidden_service_address(entry: str, version: Optional[Union[int, Seq
       return True
 
     if 3 in version and bool(HS_V3_ADDRESS_PATTERN.match(entry)):
-      # v3+ onions have a consistent version at end of address
-      if not entry.endswith('d'):
-        return False
-      # Test that the checksum (part of every v3 address) is valid
-      v3_pubkey, v3_checksum = _extract_v3_parts(entry)
-      expected_checksum = sha3_256(HS_V3_CHECKSUM_CONSTANT.encode('utf-8') + v3_pubkey + v3_version).digest()[:2]
-      if expected_checksum != v3_checksum:
-        return False
-      return True
+      # onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
+
+      decoded = base64.b32decode(entry.upper())
+      pubkey, checksum, addr_version = decoded[:32], decoded[32:34], decoded[34:]
+
+      if addr_version != b'\x03':
+        return False  # VERSION component must be three
+
+      # CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
+
+      expected_checksum = hashlib.sha3_256(b'.onion checksum' + pubkey + addr_version).digest()[:2]
+
+      return checksum == expected_checksum
 
     return False
   except TypeError:
diff --git a/test/unit/util/tor_tools.py b/test/unit/util/tor_tools.py
index 285b4dde..06707390 100644
--- a/test/unit/util/tor_tools.py
+++ b/test/unit/util/tor_tools.py
@@ -3,66 +3,62 @@ Unit tests for the stem.util.tor_tools functions.
 """
 
 import unittest
-import os
 
 import stem.util.str_tools
 import stem.util.tor_tools
 
 
 class TestTorTools(unittest.TestCase):
-
-  def test_is_valid_hidden_service_address(self):
+  def test_is_valid_hidden_service_address_v2(self):
     """
-    Check hidden service addresses are valid (no .onion)
+    Checks the is_valid_hidden_service_address for v2 addresses.
     """
+
     valid_v2_addresses = [
       'facebookcorewwwi',
       'aaaaaaaaaaaaaaaa',
     ]
+
     invalid_v2_addresses = [
       'facebookcorewww',
       'facebookcorewwyi'
       'facebookc0rewwwi',
       'facebookcorew wi',
-      None,
-      0,
-      1,
-      -1,
-      os.urandom(8)
     ]
 
     for address in valid_v2_addresses:
       self.assertTrue(stem.util.tor_tools.is_valid_hidden_service_address(address))
-      self.assertTrue(stem.util.tor_tools.is_valid_hidden_service_address(address, version=2))
+      self.assertTrue(stem.util.tor_tools.is_valid_hidden_service_address(address, version = 2))
 
     for address in invalid_v2_addresses:
       self.assertFalse(stem.util.tor_tools.is_valid_hidden_service_address(address))
-      self.assertFalse(stem.util.tor_tools.is_valid_hidden_service_address(address, version=2))
+      self.assertFalse(stem.util.tor_tools.is_valid_hidden_service_address(address, version = 2))
+
+  def test_is_valid_hidden_service_address_v3(self):
+    """
+    Checks the is_valid_hidden_service_address for v3 addresses.
+    """
 
-    # Test version 3 addresses
     valid_v3_addresses = [
       'pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd',
       'sp3k262uwy4r2k3ycr5awluarykdpag6a7y33jxop4cs2lu5uz5sseqd',
-      'xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jyd'
-      ]
+      'xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jyd',
+    ]
+
     invalid_v3_addresses = [
-      'pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryc', # bad version
-      'xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jy', # too short
-      'sp3k262uwy4r2k4ycr5awluarykdpag6a7y33jxop4cs2lu5uz5sseqd', # checksum mismatch
-      'pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscrybd', # too long
-      None,
-      0,
-      1,
-      -1,
-      os.urandom(56)
+      'pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryc',  # bad version
+      'xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jy',  # too short
+      'sp3k262uwy4r2k4ycr5awluarykdpag6a7y33jxop4cs2lu5uz5sseqd',  # checksum mismatch
+      'pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscrybd',  # too long
     ]
 
     for address in valid_v3_addresses:
       self.assertTrue(stem.util.tor_tools.is_valid_hidden_service_address(address))
-      self.assertTrue(stem.util.tor_tools.is_valid_hidden_service_address(address, version=3))
+      self.assertTrue(stem.util.tor_tools.is_valid_hidden_service_address(address, version = 3))
+
     for address in invalid_v3_addresses:
       self.assertFalse(stem.util.tor_tools.is_valid_hidden_service_address(address))
-      self.assertFalse(stem.util.tor_tools.is_valid_hidden_service_address(address, version=3))
+      self.assertFalse(stem.util.tor_tools.is_valid_hidden_service_address(address, version = 3))
 
   def test_is_valid_fingerprint(self):
     """



More information about the tor-commits mailing list