def test_outer_layer_creation(self):
    """
    Outer layer creation.
    """

    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

    # minimal layer

    self.assertTrue(OuterLayer.content().startswith(b'desc-auth-type x25519\ndesc-auth-ephemeral-key '))
    self.assertEqual('x25519', OuterLayer.create().auth_type)

    # specify the parameters

    desc = OuterLayer.create({
      'desc-auth-type': 'foo',
      'desc-auth-ephemeral-key': 'bar',
      'auth-client': [
        'JNil86N07AA epkaL79NtajmgME/egi8oA qosYH4rXisxda3X7p9b6fw',
        '1D8VBAh9hdM 6K/uO3sRqBp6URrKC7GB6Q ElwRj5+6SN9kb8bRhiiQvA',
      ],
      'encrypted': '\n-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----',
    })

    self.assertEqual('foo', desc.auth_type)
    self.assertEqual('bar', desc.ephemeral_key)
    self.assertEqual('-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----', desc.encrypted)

    self.assertEqual({
      '1D8VBAh9hdM': AuthorizedClient(id = b'1D8VBAh9hdM', iv = b'6K/uO3sRqBp6URrKC7GB6Q', cookie = b'ElwRj5+6SN9kb8bRhiiQvA'),
      'JNil86N07AA': AuthorizedClient(id = b'JNil86N07AA', iv = b'epkaL79NtajmgME/egi8oA', cookie = b'qosYH4rXisxda3X7p9b6fw'),
    }, desc.clients)

    self.assertEqual(EXPECTED_OUTER_LAYER, str(desc))

    # create an inner layer then decrypt it

    revision_counter = 5
    blinded_key = stem.util._pubkey_bytes(Ed25519PrivateKey.generate())
    subcredential = HiddenServiceDescriptorV3._subcredential(Ed25519PrivateKey.generate(), blinded_key)

    outer_layer = OuterLayer.create(
      inner_layer = InnerLayer.create(
        introduction_points = [
          IntroductionPointV3.create_for_address('1.1.1.1', 9001),
        ]
      ),
      revision_counter = revision_counter,
      subcredential = subcredential,
      blinded_key = blinded_key,
    )

    inner_layer = InnerLayer._decrypt(outer_layer, revision_counter, subcredential, blinded_key)

    self.assertEqual(1, len(inner_layer.introduction_points))
    self.assertEqual('1.1.1.1', inner_layer.introduction_points[0].link_specifiers[0].address)
  def test_intro_point_crypto_without_prereq(self):
    """
    Fetch cryptographic materials when the module is unavailable.
    """

    intro_point = InnerLayer(INNER_LAYER_STR).introduction_points[0]
    self.assertRaisesWith(ImportError, 'cryptography module unavailable', intro_point.onion_key)
  def test_inner_layer(self):
    """
    Parse the inner layer of our test descriptor.
    """

    desc = InnerLayer(INNER_LAYER_STR)

    self.assertEqual([2], desc.formats)
    self.assertEqual(['ed25519'], desc.intro_auth)
    self.assertEqual(True, desc.is_single_service)
    self.assertEqual(4, len(desc.introduction_points))

    intro_point = desc.introduction_points[0]

    self.assertEqual(2, len(intro_point.link_specifiers))

    link_specifier = intro_point.link_specifiers[0]
    self.assertEqual(stem.client.datatype.LinkByFingerprint, type(link_specifier))
    self.assertEqual('CCCCCCCCCCCCCCCCCCCC', link_specifier.fingerprint)

    link_specifier = intro_point.link_specifiers[1]
    self.assertEqual(stem.client.datatype.LinkByIPv4, type(link_specifier))
    self.assertEqual('1.2.3.4', link_specifier.address)
    self.assertEqual(9001, link_specifier.port)

    self.assertEqual('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', intro_point.onion_key_raw)
    self.assertTrue('ID2l9EFNrp' in intro_point.auth_key_cert.to_base64())
    self.assertEqual('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', intro_point.enc_key_raw)
    self.assertTrue('ZvjPt5IfeQ', intro_point.enc_key_cert)
    self.assertEqual(None, intro_point.legacy_key_raw)
    self.assertEqual(None, intro_point.legacy_key_cert)
Beispiel #4
0
    def test_descriptor_creation(self):
        """
    HiddenServiceDescriptorV3 creation.
    """

        # minimal descriptor

        self.assertTrue(HiddenServiceDescriptorV3.content().startswith(
            b'hs-descriptor 3\ndescriptor-lifetime 180\n'))
        self.assertEqual(180, HiddenServiceDescriptorV3.create().lifetime)

        # specify the parameters

        desc = HiddenServiceDescriptorV3.create(
            {
                'hs-descriptor': '4',
                'descriptor-lifetime': '123',
                'descriptor-signing-key-cert':
                '\n-----BEGIN ED25519 CERT-----\nmalformed block\n-----END ED25519 CERT-----',
                'revision-counter': '5',
                'superencrypted':
                '\n-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----',
                'signature': 'abcde',
            },
            validate=False)

        self.assertEqual(4, desc.version)
        self.assertEqual(123, desc.lifetime)
        self.assertEqual(
            None, desc.signing_cert
        )  # malformed cert dropped because validation is disabled
        self.assertEqual(5, desc.revision_counter)
        self.assertEqual(
            '-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----',
            desc.superencrypted)
        self.assertEqual('abcde', desc.signature)

        # include introduction points

        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

        identity_key = Ed25519PrivateKey.generate()
        onion_address = HiddenServiceDescriptorV3.address_from_identity_key(
            identity_key)

        desc = HiddenServiceDescriptorV3.create(
            identity_key=identity_key,
            inner_layer=InnerLayer.create(introduction_points=[
                IntroductionPointV3.create_for_address('1.1.1.1', 9001),
                IntroductionPointV3.create_for_address('2.2.2.2', 9001),
                IntroductionPointV3.create_for_address('3.3.3.3', 9001),
            ]),
        )

        inner_layer = desc.decrypt(onion_address)
        self.assertEqual(3, len(inner_layer.introduction_points))
        self.assertEqual(
            '1.1.1.1',
            inner_layer.introduction_points[0].link_specifiers[0].address)
  def test_intro_point_crypto(self):
    """
    Retrieve IntroductionPointV3 cryptographic materials.
    """

    def base64_key(key):
      pubkey = stem.util._pubkey_bytes(key)
      pubkey_b64 = base64.b64encode(pubkey)
      return stem.util.str_tools._to_unicode(pubkey_b64)

    from cryptography.hazmat.backends.openssl.x25519 import X25519PublicKey

    intro_point = InnerLayer(INNER_LAYER_STR).introduction_points[0]

    self.assertEqual('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', intro_point.onion_key_raw)
    self.assertEqual('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', intro_point.enc_key_raw)

    self.assertTrue(isinstance(intro_point.onion_key(), X25519PublicKey))
    self.assertTrue(isinstance(intro_point.enc_key(), X25519PublicKey))

    self.assertEqual(intro_point.onion_key_raw, base64_key(intro_point.onion_key()))
    self.assertEqual(intro_point.enc_key_raw, base64_key(intro_point.enc_key()))

    self.assertEqual(None, intro_point.legacy_key_raw)
    self.assertEqual(None, intro_point.legacy_key())
Beispiel #6
0
    def test_inner_layer_creation(self):
        """
    Internal layer creation.
    """

        # minimal layer

        self.assertEqual(b'create2-formats 2', InnerLayer.content())
        self.assertEqual([2], InnerLayer.create().formats)

        # specify their only mandatory parameter (formats)

        self.assertEqual(b'create2-formats 1 2 3',
                         InnerLayer.content({'create2-formats': '1 2 3'}))
        self.assertEqual([1, 2, 3],
                         InnerLayer.create({
                             'create2-formats': '1 2 3'
                         }).formats)

        # include optional parameters

        desc = InnerLayer.create(
            collections.OrderedDict((
                ('intro-auth-required', 'ed25519'),
                ('single-onion-service', ''),
            )))

        self.assertEqual([2], desc.formats)
        self.assertEqual(['ed25519'], desc.intro_auth)
        self.assertEqual(True, desc.is_single_service)
        self.assertEqual([], desc.introduction_points)

        # include introduction points

        desc = InnerLayer.create(introduction_points=[
            IntroductionPointV3.create_for_address('1.1.1.1', 9001),
            IntroductionPointV3.create_for_address('2.2.2.2', 9001),
            IntroductionPointV3.create_for_address('3.3.3.3', 9001),
        ])

        self.assertEqual(3, len(desc.introduction_points))
        self.assertEqual(
            '1.1.1.1', desc.introduction_points[0].link_specifiers[0].address)

        self.assertTrue(
            InnerLayer.content(introduction_points=[
                IntroductionPointV3.create_for_address('1.1.1.1', 9001),
            ]).startswith(
                b'create2-formats 2\nintroduction-point AQAGAQEBASMp'))
Beispiel #7
0
    def __init__(self, onion_address, identity_priv_key, blinding_param,
                 intro_points, is_first_desc):
        # Timestamp of the last attempt to assemble this descriptor
        self.last_publish_attempt_ts = None
        # Timestamp we last uploaded this descriptor
        self.last_upload_ts = None
        # Set of responsible HSDirs for last time we uploaded this descriptor
        self.responsible_hsdirs = None

        # Start generating descriptor
        desc_signing_key = Ed25519PrivateKey.generate()

        # Get the intro points for this descriptor and recertify them!
        recertified_intro_points = []
        for ip in intro_points:
            recertified_intro_points.append(
                self._recertify_intro_point(ip, desc_signing_key))

        rev_counter = self._get_revision_counter(identity_priv_key,
                                                 is_first_desc)

        v3_desc_inner_layer = InnerLayer.create(
            introduction_points=recertified_intro_points)
        v3_desc = HiddenServiceDescriptorV3.create(
            blinding_nonce=blinding_param,
            identity_key=identity_priv_key,
            signing_key=desc_signing_key,
            inner_layer=v3_desc_inner_layer,
            revision_counter=int(rev_counter),
        )

        # TODO stem should probably initialize it itself so that it has balance
        # between descriptor creation (where this is not inted) and descriptor
        # parsing (where this is inited)
        v3_desc._inner_layer = v3_desc_inner_layer

        # Check max size is within range
        if len(str(v3_desc)) > params.MAX_DESCRIPTOR_SIZE:
            logger.error(
                "Created descriptor is too big (%d intros). Consider "
                "relaxing number of instances or intro points per instance "
                "(see N_INTROS_PER_INSTANCE)")
            raise BadDescriptor

        super().__init__(onion_address, v3_desc)