def _parse_introduction_points_line(descriptor, entries): _, block_type, block_contents = entries['introduction-points'][0] if not block_contents or block_type != 'MESSAGE': raise ValueError( "'introduction-points' should be followed by a MESSAGE block, but was a %s" % block_type) descriptor.introduction_points_encoded = block_contents try: decoded_field = _bytes_for_block(block_contents) except TypeError: raise ValueError( "'introduction-points' isn't base64 encoded content:\n%s" % block_contents) auth_types = [] while decoded_field.startswith( b'service-authentication ') and b'\n' in decoded_field: auth_line, decoded_field = decoded_field.split(b'\n', 1) auth_line_comp = auth_line.split(b' ') if len(auth_line_comp) < 3: raise ValueError( "Within introduction-points we expected 'service-authentication [auth_type] [auth_data]', but had '%s'" % auth_line) auth_types.append((auth_line_comp[1], auth_line_comp[2])) descriptor.introduction_points_auth = auth_types descriptor.introduction_points_content = decoded_field
def _parse_introduction_points_line(descriptor, entries): _, block_type, block_contents = entries['introduction-points'][0] if not block_contents or block_type != 'MESSAGE': raise ValueError("'introduction-points' should be followed by a MESSAGE block, but was a %s" % block_type) descriptor.introduction_points_encoded = block_contents try: decoded_field = _bytes_for_block(block_contents) except TypeError: raise ValueError("'introduction-points' isn't base64 encoded content:\n%s" % block_contents) auth_types = [] while decoded_field.startswith(b'service-authentication ') and b'\n' in decoded_field: auth_line, decoded_field = decoded_field.split(b'\n', 1) auth_line_comp = auth_line.split(b' ') if len(auth_line_comp) < 3: raise ValueError("Within introduction-points we expected 'service-authentication [auth_type] [auth_data]', but had '%s'" % auth_line) auth_types.append((auth_line_comp[1], auth_line_comp[2])) descriptor.introduction_points_auth = auth_types descriptor.introduction_points_content = decoded_field
def __init__(self, raw_contents, validate = False, skip_crypto_validation = False): super(RelayDescriptor, self).__init__(raw_contents, validate) if validate: if self.fingerprint: key_hash = hashlib.sha1(_bytes_for_block(self.signing_key)).hexdigest() if key_hash != self.fingerprint.lower(): raise ValueError('Fingerprint does not match the hash of our signing key (fingerprint: %s, signing key hash: %s)' % (self.fingerprint.lower(), key_hash)) if not skip_crypto_validation: try: signed_digest = self._digest_for_signature(self.signing_key, self.signature) if signed_digest != self.digest(): raise ValueError('Decrypted digest does not match local digest (calculated: %s, local: %s)' % (signed_digest, self.digest())) if self.onion_key_crosscert: onion_key_crosscert_digest = self._digest_for_signature(self.onion_key, self.onion_key_crosscert) if onion_key_crosscert_digest != self._onion_key_crosscert_digest(): raise ValueError('Decrypted onion-key-crosscert digest does not match local digest (calculated: %s, local: %s)' % (onion_key_crosscert_digest, self._onion_key_crosscert_digest())) except ImportError: pass # cryptography module unavailable if self.certificate: try: self.certificate.validate(self) except ImportError: pass # cryptography module unavailable
def content( cls: Type['stem.descriptor.server_descriptor.RelayDescriptor'], attr: Optional[Mapping[str, str]] = None, exclude: Sequence[str] = (), sign: bool = False, signing_key: Optional['stem.descriptor.SigningKey'] = None, exit_policy: Optional['stem.exit_policy.ExitPolicy'] = None ) -> bytes: attr = dict(attr) if attr else {} if exit_policy is None: exit_policy = REJECT_ALL_POLICY base_header = [ ('router', '%s %s 9001 0 0' % (_random_nickname(), _random_ipv4_address())), ('published', _random_date()), ('bandwidth', '153600 256000 104590'), ] + [ tuple(line.split(' ', 1)) for line in str(exit_policy).splitlines() # type: ignore ] + [ ('onion-key', _random_crypto_blob('RSA PUBLIC KEY')), ('signing-key', _random_crypto_blob('RSA PUBLIC KEY')), ] if sign or signing_key: if 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 signing_key is None: signing_key = create_signing_key() if 'fingerprint' not in attr: fingerprint = hashlib.sha1( _bytes_for_block( stem.util.str_tools._to_unicode( signing_key.public_digest.strip()))).hexdigest( ).upper() attr['fingerprint'] = ' '.join( stem.util.str_tools._split_by_length(fingerprint, 4)) attr['signing-key'] = signing_key.public_digest content = _descriptor_content( attr, exclude, base_header) + b'\nrouter-signature\n' return _append_router_signature(content, signing_key.private) else: return _descriptor_content(attr, exclude, base_header, ( ('router-sig-ed25519', None), ('router-signature', _random_crypto_blob('SIGNATURE')), ))
def _parse_introduction_points_line(descriptor, entries): _, block_type, block_contents = entries['introduction-points'][0] if not block_contents or block_type != 'MESSAGE': raise ValueError("'introduction-points' should be followed by a MESSAGE block, but was a %s" % block_type) descriptor.introduction_points_encoded = block_contents descriptor.introduction_points_auth = [] # field was never implemented in tor (#15190) try: descriptor.introduction_points_content = _bytes_for_block(block_contents) except TypeError: raise ValueError("'introduction-points' isn't base64 encoded content:\n%s" % block_contents)
def _onion_key_crosscert_digest(self): """ Provides the digest of the onion-key-crosscert data. This consists of the RSA identity key sha1 and ed25519 identity key. :returns: **unicode** digest encoded in uppercase hex :raises: ValueError if the digest cannot be calculated """ signing_key_digest = hashlib.sha1(_bytes_for_block(self.signing_key)).digest() data = signing_key_digest + base64.b64decode(stem.util.str_tools._to_bytes(self.ed25519_master_key) + b'=') return stem.util.str_tools._to_unicode(binascii.hexlify(data).upper())
def content(cls, attr=None, exclude=(), sign=False, signing_key=None): if signing_key: sign = True if attr is None: attr = {} base_header = ( ('router', '%s %s 9001 0 0' % (_random_nickname(), _random_ipv4_address())), ('published', _random_date()), ('bandwidth', '153600 256000 104590'), ('reject', '*:*'), ('onion-key', _random_crypto_blob('RSA PUBLIC KEY')), ('signing-key', _random_crypto_blob('RSA PUBLIC KEY')), ) if sign: if 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 signing_key is None: signing_key = create_signing_key() if 'fingerprint' not in attr: fingerprint = hashlib.sha1( _bytes_for_block( stem.util.str_tools._to_unicode( signing_key.public_digest.strip()))).hexdigest( ).upper() attr['fingerprint'] = ' '.join( stem.util.str_tools._split_by_length(fingerprint, 4)) attr['signing-key'] = signing_key.public_digest content = _descriptor_content( attr, exclude, base_header) + b'\nrouter-signature\n' return _append_router_signature(content, signing_key.private) else: return _descriptor_content(attr, exclude, base_header, ( ('router-sig-ed25519', None), ('router-signature', _random_crypto_blob('SIGNATURE')), ))
def __init__(self, raw_contents, validate = False, annotations = None): super(RelayDescriptor, self).__init__(raw_contents, validate, annotations) if validate: if self.fingerprint: key_hash = hashlib.sha1(_bytes_for_block(self.signing_key)).hexdigest() if key_hash != self.fingerprint.lower(): raise ValueError('Fingerprint does not match the hash of our signing key (fingerprint: %s, signing key hash: %s)' % (self.fingerprint.lower(), key_hash)) if stem.prereq.is_crypto_available(): signed_digest = self._digest_for_signature(self.signing_key, self.signature) if signed_digest != self.digest(): raise ValueError('Decrypted digest does not match local digest (calculated: %s, local: %s)' % (signed_digest, self.digest()))
def __init__(self, raw_contents, validate=False, annotations=None, skip_crypto_validation=False): super(RelayDescriptor, self).__init__(raw_contents, validate, annotations) if validate: if self.fingerprint: key_hash = hashlib.sha1(_bytes_for_block( self.signing_key)).hexdigest() if key_hash != self.fingerprint.lower(): raise ValueError( 'Fingerprint does not match the hash of our signing key (fingerprint: %s, signing key hash: %s)' % (self.fingerprint.lower(), key_hash)) if not skip_crypto_validation and stem.prereq.is_crypto_available( ): signed_digest = self._digest_for_signature( self.signing_key, self.signature) if signed_digest != self.digest(): raise ValueError( 'Decrypted digest does not match local digest (calculated: %s, local: %s)' % (signed_digest, self.digest())) if self.onion_key_crosscert and stem.prereq.is_crypto_available( ): onion_key_crosscert_digest = self._digest_for_signature( self.onion_key, self.onion_key_crosscert) if onion_key_crosscert_digest != self._onion_key_crosscert_digest( ): raise ValueError( 'Decrypted onion-key-crosscert digest does not match local digest (calculated: %s, local: %s)' % (onion_key_crosscert_digest, self._onion_key_crosscert_digest())) if stem.prereq._is_crypto_ed25519_supported() and self.certificate: self.certificate.validate(self)
def __init__(self, raw_contents, validate=False, annotations=None): super(RelayDescriptor, self).__init__(raw_contents, validate, annotations) if validate: if self.fingerprint: key_hash = hashlib.sha1(_bytes_for_block( self.signing_key)).hexdigest() if key_hash != self.fingerprint.lower(): raise ValueError( 'Fingerprint does not match the hash of our signing key (fingerprint: %s, signing key hash: %s)' % (self.fingerprint.lower(), key_hash)) if stem.prereq.is_crypto_available(): signed_digest = self._digest_for_signature( self.signing_key, self.signature) if signed_digest != self.digest(): raise ValueError( 'Decrypted digest does not match local digest (calculated: %s, local: %s)' % (signed_digest, self.digest()))
def content(cls, attr = None, exclude = (), sign = False, signing_key = None): if signing_key: sign = True if attr is None: attr = {} base_header = ( ('router', '%s %s 9001 0 0' % (_random_nickname(), _random_ipv4_address())), ('published', _random_date()), ('bandwidth', '153600 256000 104590'), ('reject', '*:*'), ('onion-key', _random_crypto_blob('RSA PUBLIC KEY')), ('signing-key', _random_crypto_blob('RSA PUBLIC KEY')), ) if sign: if 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 signing_key is None: signing_key = create_signing_key() if 'fingerprint' not in attr: fingerprint = hashlib.sha1(_bytes_for_block(stem.util.str_tools._to_unicode(signing_key.public_digest.strip()))).hexdigest().upper() attr['fingerprint'] = ' '.join(stem.util.str_tools._split_by_length(fingerprint, 4)) attr['signing-key'] = signing_key.public_digest content = _descriptor_content(attr, exclude, base_header) + b'\nrouter-signature\n' return _append_router_signature(content, signing_key.private) else: return _descriptor_content(attr, exclude, base_header, ( ('router-sig-ed25519', None), ('router-signature', _random_crypto_blob('SIGNATURE')), ))
def _parse_superencrypted_line(descriptor, entries): _, block_type, block_contents = entries['superencrypted'][0] if not block_contents or block_type != 'MESSAGE': raise ValueError( "'superencrypted' should be followed by a MESSAGE block, but was a %s" % block_type) descriptor.superencrypted_encoded = block_contents try: descriptor.introduction_points_content = _bytes_for_block( block_contents) except TypeError: raise ValueError( "'introduction-points' isn't base64 encoded content:\n%s" % block_contents) descriptor.introduction_points_salt = descriptor.introduction_points_content[: 16] descriptor.introduction_points_encrypted = descriptor.introduction_points_content[ 16:-32] descriptor.introduction_points_mac = descriptor.introduction_points_content[ -32:]