[stem/master] Parse signing_cert as an ed25519 certificate
commit 80f4934183a0037926f11e18b54eda09bacb012c Author: Damian Johnson <atagar@torproject.org> Date: Wed Oct 2 15:59:10 2019 -0700 Parse signing_cert as an ed25519 certificate I was mistaken to parse signing_cert as a key blob. Server descriptors are deprecating their key blob copy (the 'ed25519_certificate' attribute) in favor of a Ed25519Certificate instance, and hidden service descriptors should do the same. Hidden service v3 parsing isn't yet in a release so we can simply fix this in place without concern for backward compatibility. --- stem/descriptor/certificate.py | 15 +++++++++++++++ stem/descriptor/hidden_service.py | 14 +++++++------- stem/descriptor/server_descriptor.py | 2 ++ test/unit/descriptor/hidden_service_v3.py | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py index 4a78fa3f..e336bbda 100644 --- a/stem/descriptor/certificate.py +++ b/stem/descriptor/certificate.py @@ -152,6 +152,21 @@ class Ed25519Certificate(object): else: raise ValueError('Ed25519 certificate is version %i. Parser presently only supports version 1.' % version) + @staticmethod + def _from_descriptor(keyword, attribute): + def _parse(descriptor, entries): + value, block_type, block_contents = entries[keyword][0] + + if not block_contents or block_type != 'ED25519 CERT': + raise ValueError("'%s' should be followed by a ED25519 CERT block, but was a %s" % (keyword, block_type)) + + setattr(descriptor, attribute, Ed25519Certificate.parse(block_contents)) + + return _parse + + def __str__(self): + return '-----BEGIN ED25519 CERT-----\n%s\n-----END ED25519 CERT-----' % self.encoded + class Ed25519CertificateV1(Ed25519Certificate): """ diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py index 2ca9f4bf..bf11c685 100644 --- a/stem/descriptor/hidden_service.py +++ b/stem/descriptor/hidden_service.py @@ -31,13 +31,14 @@ import collections import hashlib import io -import stem.descriptor.certificate import stem.descriptor.hsv3_crypto import stem.prereq import stem.util.connection import stem.util.str_tools import stem.util.tor_tools +from stem.descriptor.certificate import Ed25519Certificate + from stem.descriptor import ( PGP_BLOCK_END, Descriptor, @@ -199,7 +200,7 @@ _parse_v2_signature_line = _parse_key_block('signature', 'signature', 'SIGNATURE _parse_v3_version_line = _parse_int_line('hs-descriptor', 'version', allow_negative = False) _parse_lifetime_line = _parse_int_line('descriptor-lifetime', 'lifetime', allow_negative = False) -_parse_signing_key_line = _parse_key_block('descriptor-signing-key-cert', 'signing_cert', 'ED25519 CERT') +_parse_signing_cert = Ed25519Certificate._from_descriptor('descriptor-signing-key-cert', 'signing_cert') _parse_revision_counter_line = _parse_int_line('revision-counter', 'revision_counter', allow_negative = False) _parse_superencrypted_line = _parse_key_block('superencrypted', 'superencrypted', 'MESSAGE') _parse_v3_signature_line = _parse_simple_line('signature', 'signature') @@ -481,7 +482,7 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor): :var int version: **\\*** hidden service descriptor version :var int lifetime: **\\*** minutes after publication this descriptor is valid - :var str signing_cert: **\\*** cross-certifier for the short-term descriptor signing key + :var stem.certificate.Ed25519Certificate signing_cert: **\\*** cross-certifier for the short-term descriptor signing key :var int revision_counter: **\\*** descriptor revision number :var str superencrypted: **\\*** encrypted HS-DESC-ENC payload :var str signature: **\\*** signature of this descriptor @@ -497,7 +498,7 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor): ATTRIBUTES = { 'version': (None, _parse_v3_version_line), 'lifetime': (None, _parse_lifetime_line), - 'signing_cert': (None, _parse_signing_key_line), + 'signing_cert': (None, _parse_signing_cert), 'revision_counter': (None, _parse_revision_counter_line), 'superencrypted': (None, _parse_superencrypted_line), 'signature': (None, _parse_v3_signature_line), @@ -506,7 +507,7 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor): PARSER_FOR_LINE = { 'hs-descriptor': _parse_v3_version_line, 'descriptor-lifetime': _parse_lifetime_line, - 'descriptor-signing-key-cert': _parse_signing_key_line, + 'descriptor-signing-key-cert': _parse_signing_cert, 'revision-counter': _parse_revision_counter_line, 'superencrypted': _parse_superencrypted_line, 'signature': _parse_v3_signature_line, @@ -560,8 +561,7 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor): elif not stem.prereq._is_sha3_available(): raise ImportError('Hidden service descriptor decryption requires python 3.6+ or the pysha3 module (https://pypi.org/project/pysha3/)') - cert = stem.descriptor.certificate.Ed25519Certificate.parse(self.signing_cert) - blinded_key = cert.signing_key() + blinded_key = self.signing_cert.signing_key() if not blinded_key: raise ValueError('No signing key extension present') diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py index 71f3a803..ebadcde2 100644 --- a/stem/descriptor/server_descriptor.py +++ b/stem/descriptor/server_descriptor.py @@ -401,6 +401,8 @@ def _parse_exit_policy(descriptor, entries): def _parse_identity_ed25519_line(descriptor, entries): + # TODO: replace this with Ed25519Certificate._from_descriptor() in stem 2.x + _parse_key_block('identity-ed25519', 'ed25519_certificate', 'ED25519 CERT')(descriptor, entries) if descriptor.ed25519_certificate: diff --git a/test/unit/descriptor/hidden_service_v3.py b/test/unit/descriptor/hidden_service_v3.py index 2242d617..3824c8a6 100644 --- a/test/unit/descriptor/hidden_service_v3.py +++ b/test/unit/descriptor/hidden_service_v3.py @@ -46,7 +46,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase): self.assertEqual(3, desc.version) self.assertEqual(180, desc.lifetime) - self.assertEqual(EXPECTED_SIGNING_CERT, desc.signing_cert) + self.assertEqual(EXPECTED_SIGNING_CERT, str(desc.signing_cert)) self.assertEqual(42, desc.revision_counter) self.assertTrue('eaH8VdaTKS' in desc.superencrypted) self.assertEqual('aglChCQF+lbzKgyxJJTpYGVShV/GMDRJ4+cRGCp+a2y/yX/tLSh7hzqI7rVZrUoGj74Xr1CLMYO3fXYCS+DPDQ', desc.signature)
participants (1)
-
atagar@torproject.org