[tor-commits] [stem/master] Generate signing keys

atagar at torproject.org atagar at torproject.org
Tue Jun 20 16:17:12 UTC 2017


commit cd648f6d23665dce369958a43635f62b48912d4f
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Jun 18 18:27:02 2017 -0700

    Generate signing keys
    
    When a signing key isn't provided filling one in. We'll need this so we can
    generate a valid digest. This adds a test that presently fails to exercise
    signing.
---
 stem/descriptor/__init__.py                  |  1 +
 stem/descriptor/hidden_service_descriptor.py |  2 +-
 stem/descriptor/server_descriptor.py         | 37 +++++++++++++++++++++++++++-
 test/unit/descriptor/server_descriptor.py    |  5 ++++
 4 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index 13dc84c..82b71d5 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -718,6 +718,7 @@ class Descriptor(object):
     # More info here http://www.ietf.org/rfc/rfc2313.txt
     #                esp the Notes in section 8.1
     ############################################################################
+
     try:
       if decrypted_bytes.index(b'\x00\x01') != 0:
         raise ValueError('Verification failed, identifier missing')
diff --git a/stem/descriptor/hidden_service_descriptor.py b/stem/descriptor/hidden_service_descriptor.py
index 91d49b5..b188012 100644
--- a/stem/descriptor/hidden_service_descriptor.py
+++ b/stem/descriptor/hidden_service_descriptor.py
@@ -255,7 +255,7 @@ class HiddenServiceDescriptor(Descriptor):
 
   @classmethod
   def create(cls, attr = None, exclude = (), validate = True, sign = False):
-    return cls(cls.content(attr, exclude, sign), validate = validate, skip_crypto_validation = True)
+    return cls(cls.content(attr, exclude, sign), validate = validate, skip_crypto_validation = not sign)
 
   def __init__(self, raw_contents, validate = False, skip_crypto_validation = False):
     super(HiddenServiceDescriptor, self).__init__(raw_contents, lazy_load = not validate)
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index ce3300b..20948dd 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -33,6 +33,7 @@ etc). This information is provided from a few sources...
 
 import base64
 import binascii
+import collections
 import functools
 import hashlib
 import re
@@ -73,6 +74,8 @@ try:
 except ImportError:
   from stem.util.lru_cache import lru_cache
 
+SigningKey = collections.namedtuple('SigningKey', ['public', 'private', 'descriptor_signing_key'])
+
 # relay descriptors must have exactly one of the following
 REQUIRED_FIELDS = (
   'router',
@@ -211,6 +214,31 @@ def _parse_file(descriptor_file, is_bridge = False, validate = False, **kwargs):
       break  # done parsing descriptors
 
 
+def _generate_signing_key():
+  """
+  Creates a key that can be used to sign server descriptors.
+  """
+
+  from cryptography.hazmat.backends import default_backend
+  from cryptography.hazmat.primitives import serialization
+  from cryptography.hazmat.primitives.asymmetric import rsa
+
+  private_key = rsa.generate_private_key(
+    public_exponent = 65537,
+    key_size = 1024,
+    backend = default_backend(),
+  )
+
+  public_key = private_key.public_key()
+
+  pem = '\n' + public_key.public_bytes(
+    encoding = serialization.Encoding.PEM,
+    format = serialization.PublicFormat.PKCS1,
+  ).strip()
+
+  return SigningKey(public_key, private_key, pem)
+
+
 def _parse_router_line(descriptor, entries):
   # "router" nickname address ORPort SocksPort DirPort
 
@@ -818,11 +846,18 @@ class RelayDescriptor(ServerDescriptor):
 
   @classmethod
   def content(cls, attr = None, exclude = (), sign = False):
+    if sign and (not attr or 'signing-key' not in attr):
+      if attr is None:
+        attr = {}
+
+      signing_key = _generate_signing_key()
+      attr['signing-key'] = signing_key.descriptor_signing_key
+
     return _descriptor_content(attr, exclude, sign, RELAY_SERVER_HEADER, RELAY_SERVER_FOOTER)
 
   @classmethod
   def create(cls, attr = None, exclude = (), validate = True, sign = False):
-    return cls(cls.content(attr, exclude, sign), validate = validate, skip_crypto_validation = True)
+    return cls(cls.content(attr, exclude, sign), validate = validate, skip_crypto_validation = not sign)
 
   @lru_cache()
   def digest(self):
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index 0014049..227df12 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -16,6 +16,7 @@ import stem.exit_policy
 import stem.prereq
 import stem.version
 import stem.util.str_tools
+import test.require
 
 from stem.util import str_type
 from stem.descriptor.certificate import CertType, ExtensionType
@@ -254,6 +255,10 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
 
     self.assertTrue(isinstance(str(desc), str))
 
+  @test.require.cryptography
+  def test_descriptor_signing(self):
+    RelayDescriptor.create(sign = True)
+
   @patch('time.time', Mock(return_value = time.mktime(datetime.date(2010, 1, 1).timetuple())))
   def test_with_ed25519(self):
     """





More information about the tor-commits mailing list