commit cd648f6d23665dce369958a43635f62b48912d4f Author: Damian Johnson atagar@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): """
tor-commits@lists.torproject.org