[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