commit edfe4d07154f5902ca8f52903923f02d2e943e76 Author: Damian Johnson atagar@torproject.org Date: Sun Jun 18 19:34:40 2017 -0700
Generate broken server descriptor signaures
This does *not* work yet but feels like we're making progress. This generates validly looking descriptors, now just gotta get all the crypto right... --- stem/descriptor/server_descriptor.py | 37 ++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py index 20948dd..8bafda5 100644 --- a/stem/descriptor/server_descriptor.py +++ b/stem/descriptor/server_descriptor.py @@ -239,6 +239,23 @@ def _generate_signing_key(): return SigningKey(public_key, private_key, pem)
+def _generate_signature(content, signing_key): + """ + Creates the 'router-signature' for the given descriptor content. + """ + + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import padding + + # generate the digest with required PKCS1 padding so it's 128 bytes + + digest = hashlib.sha1(content).hexdigest().lower().decode('hex_codec') + digest = b'\x00\x01' + (b'\xFF' * (125 - len(digest))) + b'\x00' + digest + + padding = padding.PSS(mgf = padding.MGF1(hashes.SHA256()), salt_length = padding.PSS.MAX_LENGTH) + return base64.b64encode(signing_key.private.sign(digest, padding, hashes.SHA256())) + + def _parse_router_line(descriptor, entries): # "router" nickname address ORPort SocksPort DirPort
@@ -846,14 +863,30 @@ class RelayDescriptor(ServerDescriptor):
@classmethod def content(cls, attr = None, exclude = (), sign = False): - if sign and (not attr or 'signing-key' not in attr): + if sign: + if not stem.prereq.is_crypto_available(): + raise ImportError('Signing requires the cryptography module') + elif attr and 'signing-key' in attr: + raise ValueError('Cannot sign the descriptor if a signing-key has been provided') + elif attr and 'router-signature' in attr: + raise ValueError('Cannot sign the descriptor if a router-signature has been provided') + if attr is None: attr = {}
+ # create descriptor content without the router-signature line, then + # appending the signature + signing_key = _generate_signing_key() attr['signing-key'] = signing_key.descriptor_signing_key + content = _descriptor_content(attr, exclude, sign, RELAY_SERVER_HEADER) + + signature = _generate_signature(content, signing_key) + content = '\n'.join([content, 'router-signature', '-----BEGIN SIGNATURE-----'] + stem.util.str_tools._split_by_length(signature, 64) + ['-----END SIGNATURE-----'])
- return _descriptor_content(attr, exclude, sign, RELAY_SERVER_HEADER, RELAY_SERVER_FOOTER) + return content + else: + return _descriptor_content(attr, exclude, sign, RELAY_SERVER_HEADER, RELAY_SERVER_FOOTER)
@classmethod def create(cls, attr = None, exclude = (), validate = True, sign = False):