commit 61f5a97ad2016b7f1f043a0e0c551fedcf1ad2e1 Author: Damian Johnson atagar@torproject.org Date: Wed Nov 6 16:24:37 2019 -0800
Generate defaults in introduction point creation
Making all the arguments except address/port optional so callers can opt to skip them. --- stem/descriptor/certificate.py | 2 ++ stem/descriptor/hidden_service.py | 57 ++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py index 760287d8..f9ab8f80 100644 --- a/stem/descriptor/certificate.py +++ b/stem/descriptor/certificate.py @@ -100,6 +100,8 @@ ED25519_SIGNATURE_LENGTH = 64 SIG_PREFIX_SERVER_DESC = b'Tor router descriptor signature v1' SIG_PREFIX_HS_V3 = b'Tor onion service descriptor sig v3'
+DEFAULT_EXPIRATION_HOURS = 54 # HSv3 certificate expiration of tor + CertType = stem.util.enum.UppercaseEnum( 'SIGNING', 'LINK_CERT', diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py index ce8af246..a052d965 100644 --- a/stem/descriptor/hidden_service.py +++ b/stem/descriptor/hidden_service.py @@ -205,7 +205,7 @@ class IntroductionPointV3(collections.namedtuple('IntroductionPointV3', ['link_s return IntroductionPointV3(link_specifiers, onion_key, auth_key_cert, enc_key, enc_key_cert, legacy_key, legacy_key_cert)
@staticmethod - def create(address, port, expiration, onion_key, enc_key, auth_key, signing_key): + def create(address, port, expiration = None, onion_key = None, enc_key = None, auth_key = None, signing_key = None): """ Simplified constructor. For more sophisticated use cases you can use this as a template for how introduction points are properly created. @@ -223,26 +223,8 @@ class IntroductionPointV3(collections.namedtuple('IntroductionPointV3', ['link_s :raises: **ValueError** if the address, port, or keys are malformed """
- def _key_bytes(key): - class_name = type(key).__name__ - - if isinstance(key, str): - return key - elif not class_name.endswith('PublicKey') and not class_name.endswith('PrivateKey'): - raise ValueError('Key must be a string or cryptographic public/private key (was %s)' % class_name) - elif not stem.prereq.is_crypto_available(): - raise ImportError('Serializing keys requires the cryptography module') - - from cryptography.hazmat.primitives import serialization - - if class_name.endswith('PrivateKey'): - key = key.public_key() - - return key.public_bytes( - encoding = serialization.Encoding.Raw, - format = serialization.PublicFormat.Raw, - ) - + if not stem.prereq.is_crypto_available(ed25519 = True): + raise ImportError('Introduction point creation requires the cryptography module ed25519 support') if not stem.util.connection.is_valid_port(port): raise ValueError("'%s' is an invalid port" % port)
@@ -253,12 +235,37 @@ class IntroductionPointV3(collections.namedtuple('IntroductionPointV3', ['link_s else: raise ValueError("'%s' is not a valid IPv4 or IPv6 address" % address)
- onion_key = base64.b64encode(_key_bytes(onion_key)) - enc_key = base64.b64encode(_key_bytes(enc_key)) + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey + from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey + + def _key_bytes(key): + if isinstance(key, str): + return key + elif isinstance(key, (X25519PrivateKey, Ed25519PrivateKey)): + return key.public_key().public_bytes( + encoding = serialization.Encoding.Raw, + format = serialization.PublicFormat.Raw, + ) + elif isinstance(key, (X25519PublicKey, Ed25519PublicKey)): + return key.public_bytes( + encoding = serialization.Encoding.Raw, + format = serialization.PublicFormat.Raw, + ) + else: + raise ValueError('Key must be a string or cryptographic public/private key (was %s)' % type(key).__name__) + + if expiration is None: + expiration = datetime.datetime.utcnow() + datetime.timedelta(hours = stem.descriptor.certificate.DEFAULT_EXPIRATION_HOURS) + + onion_key = base64.b64encode(_key_bytes(onion_key if onion_key else X25519PrivateKey.generate())) + enc_key = base64.b64encode(_key_bytes(enc_key if enc_key else X25519PrivateKey.generate())) + auth_key = _key_bytes(auth_key if auth_key else Ed25519PrivateKey.generate()) + signing_key = signing_key if signing_key else Ed25519PrivateKey.generate()
extensions = [Ed25519Extension(ExtensionType.HAS_SIGNING_KEY, None, _key_bytes(signing_key))] - auth_key_cert = Ed25519CertificateV1(CertType.HS_V3_INTRO_AUTH, expiration, 1, _key_bytes(auth_key), extensions, signing_key = signing_key) - enc_key_cert = Ed25519CertificateV1(CertType.HS_V3_NTOR_ENC, expiration, 1, _key_bytes(auth_key), extensions, signing_key = signing_key) + auth_key_cert = Ed25519CertificateV1(CertType.HS_V3_INTRO_AUTH, expiration, 1, auth_key, extensions, signing_key = signing_key) + enc_key_cert = Ed25519CertificateV1(CertType.HS_V3_NTOR_ENC, expiration, 1, auth_key, extensions, signing_key = signing_key)
return IntroductionPointV3(link_specifiers, onion_key, auth_key_cert, enc_key, enc_key_cert, None, None)
tor-commits@lists.torproject.org