Пример #1
0
  def test_make_router_status_entry_with_live_descriptor(self):
    """
    Tests creation of router status entries with a live server descriptor.
    """

    with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = True)).make_router_status_entry()

    self.assertEqual(stem.descriptor.router_status_entry.RouterStatusEntryV3, type(desc))
    self.assertEqual('destiny', desc.nickname)
    self.assertEqual('F65E0196C94DFFF48AFBF2F5F9E3E19AAE583FD0', desc.fingerprint)
    self.assertEqual(datetime.datetime(2015, 8, 22, 15, 21, 45), desc.published)
    self.assertEqual('94.242.246.23', desc.address)
    self.assertEqual(9001, desc.or_port)
    self.assertEqual(443, desc.dir_port)
    self.assertEqual(['Fast', 'Named', 'Running', 'Stable', 'Valid'], desc.flags)
    self.assertEqual(stem.version.Version('0.2.7.2-alpha-dev'), desc.version)
    self.assertEqual('Tor 0.2.7.2-alpha-dev', desc.version_line)

    self.assertEqual([('2a01:608:ffff:ff07::1:23', 9003, True)], desc.or_addresses)
    self.assertEqual('ed25519', desc.identifier_type)
    self.assertEqual('pbYagEQPUiNjcDp/oY2oESXkDzd8PZlr26kaR7nUkao', desc.identifier)
    self.assertEqual('B5E441051D139CCD84BC765D130B01E44DAC29AD', desc.digest)
    self.assertEqual(149715200, desc.bandwidth)
    self.assertEqual(None, desc.measured)
    self.assertEqual(False, desc.is_unmeasured)
    self.assertEqual([], desc.unrecognized_bandwidth_entries)
    self.assertEqual(stem.exit_policy.MicroExitPolicy('reject 25,465,587,10000,14464'), desc.exit_policy)
    self.assertEqual([], desc.microdescriptor_hashes)
Пример #2
0
  def test_bridge_descriptor(self):
    """
    Parses a bridge descriptor.
    """

    with open(get_resource('bridge_descriptor'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, 'bridge-server-descriptor 1.0', validate = True))

    self.assertEqual('Unnamed', desc.nickname)
    self.assertEqual('4ED573582B16ACDAF6E42AA044A038F83A7F6333', desc.fingerprint)
    self.assertEqual('10.18.111.71', desc.address)
    self.assertEqual(9001, desc.or_port)
    self.assertEqual(None, desc.socks_port)
    self.assertEqual(None, desc.dir_port)
    self.assertEqual(b'Tor 0.2.0.26-rc (r14597) on Linux i686', desc.platform)
    self.assertEqual(stem.version.Version('0.2.0.26-rc'), desc.tor_version)
    self.assertEqual('Linux i686', desc.operating_system)
    self.assertEqual(204, desc.uptime)
    self.assertEqual(datetime.datetime(2008, 5, 20, 19, 45, 0), desc.published)
    self.assertEqual(None, desc.contact)
    self.assertEqual(['1', '2'], desc.link_protocols)
    self.assertEqual(['1'], desc.circuit_protocols)
    self.assertEqual(False, desc.hibernating)
    self.assertEqual(False, desc.allow_single_hop_exits)
    self.assertEqual(True, desc.extra_info_cache)
    self.assertEqual('BB1F13AA431421BEA29B840A2E33BB1C31C2990B', desc.extra_info_digest)
    self.assertEqual(None, desc.hidden_service_dir)
    self.assertEqual(set(), desc.family)
    self.assertEqual(3220480, desc.average_bandwidth)
    self.assertEqual(6441984, desc.burst_bandwidth)
    self.assertEqual(59408, desc.observed_bandwidth)
    self.assertEqual(stem.exit_policy.ExitPolicy('reject *:*'), desc.exit_policy)
    self.assertEqual('00F1CD29AD308A59A9AB5A88B49ECB46E0F215FD', desc.digest())
    self.assertEqual([], desc.get_unrecognized_lines())
Пример #3
0
  def test_metrics_bridge_descriptor(self):
    """
    Parses and checks our results against an extrainfo bridge descriptor from
    metrics.
    """

    descriptor_file = open(get_resource('extrainfo_bridge_descriptor'), 'rb')

    expected_dir_v2_responses = {
      DirResponse.OK: 0,
      DirResponse.UNAVAILABLE: 0,
      DirResponse.NOT_FOUND: 0,
      DirResponse.NOT_MODIFIED: 0,
      DirResponse.BUSY: 0,
    }

    expected_dir_v3_responses = {
      DirResponse.OK: 72,
      DirResponse.NOT_ENOUGH_SIGS: 0,
      DirResponse.UNAVAILABLE: 0,
      DirResponse.NOT_FOUND: 0,
      DirResponse.NOT_MODIFIED: 0,
      DirResponse.BUSY: 0,
    }

    desc = next(stem.descriptor.parse_file(descriptor_file, 'bridge-extra-info 1.0'))
    self.assertEqual('ec2bridgereaac65a3', desc.nickname)
    self.assertEqual('1EC248422B57D9C0BD751892FE787585407479A4', desc.fingerprint)
    self.assertEqual(datetime.datetime(2012, 6, 8, 2, 21, 27), desc.published)
    self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.read_history_end)
    self.assertEqual(900, desc.read_history_interval)
    self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.write_history_end)
    self.assertEqual(900, desc.write_history_interval)
    self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.dir_read_history_end)
    self.assertEqual(900, desc.dir_read_history_interval)
    self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.dir_write_history_end)
    self.assertEqual(900, desc.dir_write_history_interval)
    self.assertEqual('00A2AECCEAD3FEE033CFE29893387143146728EC', desc.digest())
    self.assertEqual([], desc.get_unrecognized_lines())

    read_values_start = [337920, 437248, 3995648, 48726016]
    self.assertEqual(read_values_start, desc.read_history_values[:4])

    write_values_start = [343040, 991232, 5649408, 49548288]
    self.assertEqual(write_values_start, desc.write_history_values[:4])

    dir_read_values_start = [0, 71680, 99328, 25600]
    self.assertEqual(dir_read_values_start, desc.dir_read_history_values[:4])

    dir_write_values_start = [5120, 664576, 2419712, 578560]
    self.assertEqual(dir_write_values_start, desc.dir_write_history_values[:4])

    self.assertEqual({}, desc.dir_v2_requests)
    self.assertEqual({}, desc.dir_v3_requests)

    self.assertEqual(expected_dir_v2_responses, desc.dir_v2_responses)
    self.assertEqual(expected_dir_v3_responses, desc.dir_v3_responses)

    self.assertEqual({}, desc.dir_v2_responses_unknown)
    self.assertEqual({}, desc.dir_v2_responses_unknown)
Пример #4
0
  def test_with_ed25519_expired_cert(self):
    """
    Parses a server descriptor with an expired ed25519 certificate
    """

    desc_text = open(get_resource('bridge_descriptor_with_ed25519'), 'rb').read()
    desc_iter = stem.descriptor.server_descriptor._parse_file(io.BytesIO(desc_text), validate = True)
    self.assertRaises(ValueError, list, desc_iter)
Пример #5
0
  def test_for_duckduckgo_without_validation(self):
    """
    Parse duckduckgo's descriptor
    """

    descriptor_file = open(get_resource('hidden_service_duckduckgo'), 'rb')
    desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor 1.0', validate = False))
    self._assert_matches_duckduckgo(desc)
Пример #6
0
  def test_nonascii_v3_reqs(self):
    """
    Malformed descriptor with non-ascii content for the 'dirreq-v3-reqs' line.
    """

    with open(get_resource('unparseable/extrainfo_nonascii_v3_reqs'), 'rb') as descriptor_file:
      desc_generator = stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True)
      exc_msg = "'dirreq-v3-reqs' line had non-ascii content: S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,??=4026591624,6?=4026537520,6?=4026537520,6?=4026537520,us=8"
      self.assertRaisesRegexp(ValueError, re.escape(exc_msg), next, desc_generator)
Пример #7
0
  def test_validation_with_invalid_descriptor(self):
    """
    Validate a descriptor without a valid signature.
    """

    with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = False))

    cert = Ed25519Certificate.parse(certificate())
    self.assertRaisesRegexp(ValueError, re.escape('Ed25519KeyCertificate signing key is invalid (Signature was forged or corrupt)'), cert.validate, desc)
Пример #8
0
  def test_validation_with_descriptor_key(self):
    """
    Validate a descriptor signature using the ed25519 master key within the
    descriptor.
    """

    with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = False))

    desc.certificate.validate(desc)
Пример #9
0
  def test_with_tarfile_path(self):
    """
    Fetch server descriptors via parse_file() for a tarfile path.
    """

    descriptors = list(stem.descriptor.parse_file(get_resource('descriptor_archive.tar')))
    self.assertEqual(3, len(descriptors))

    fingerprints = set([desc.fingerprint for desc in descriptors])
    self.assertEqual(TARFILE_FINGERPRINTS, fingerprints)
Пример #10
0
  def test_nonascii_v3_reqs(self):
    """
    Malformed descriptor with non-ascii content for the 'dirreq-v3-reqs' line.
    """

    with open(get_resource('extrainfo_nonascii_v3_reqs'), 'rb') as descriptor_file:
      try:
        next(stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True))
        self.fail("validation should've raised an exception")
      except ValueError as exc:
        expected = "'dirreq-v3-reqs' line had non-ascii content: S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,??=4026591624,6?=4026537520,6?=4026537520,6?=4026537520,us=8"
        self.assertEqual(expected, str(exc))
Пример #11
0
  def test_with_ed25519(self):
    """
    Parses a descriptor with a ed25519 identity key, as added by proposal 228
    (cross certification onionkeys).
    """

    with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = True))

    family = set([
      '$379FB450010D17078B3766C2273303C358C3A442',
      '$3EB46C1D8D8B1C0BBCB6E4F08301EF68B7F5308D',
      '$B0279A521375F3CB2AE210BDBFC645FDD2E1973A',
      '$EC116BCB80565A408CE67F8EC3FE3B0B02C3A065',
    ])

    self.assertEqual('destiny', desc.nickname)
    self.assertEqual('F65E0196C94DFFF48AFBF2F5F9E3E19AAE583FD0', desc.fingerprint)
    self.assertEqual('94.242.246.23', desc.address)
    self.assertEqual(9001, desc.or_port)
    self.assertEqual(None, desc.socks_port)
    self.assertEqual(443, desc.dir_port)
    self.assertTrue('bWPo2fIzo3uOywfoM' in desc.ed25519_certificate)
    self.assertEqual('Z6a1UabSK+N21j6NnyM6N7jssH6DK68qa6W5uB4QpGQ', desc.ed25519_master_key)
    self.assertEqual('w+cKNZTlL7vz/4WgYdFUblzJy3VdTw0mfFK4N3SPFCt20fNKt9SgiZ5V/2ai3kgGsc6oCsyUesSiYtPcTXMLCw', desc.ed25519_signature)
    self.assertEqual(b'Tor 0.2.7.2-alpha-dev on Linux', desc.platform)
    self.assertEqual(stem.version.Version('0.2.7.2-alpha-dev'), desc.tor_version)
    self.assertEqual('Linux', desc.operating_system)
    self.assertEqual(1362680, desc.uptime)
    self.assertEqual(datetime.datetime(2015, 8, 22, 15, 21, 45), desc.published)
    self.assertEqual(b'0x02225522 Frenn vun der Enn (FVDE) <info AT enn DOT lu>', desc.contact)
    self.assertEqual(['1', '2'], desc.link_protocols)
    self.assertEqual(['1'], desc.circuit_protocols)
    self.assertEqual(False, desc.hibernating)
    self.assertEqual(False, desc.allow_single_hop_exits)
    self.assertEqual(False, desc.extra_info_cache)
    self.assertEqual('44E9B679AF0B4EB09296985BAF4066AE9CA5BB93', desc.extra_info_digest)
    self.assertEqual(['2'], desc.hidden_service_dir)
    self.assertEqual(family, desc.family)
    self.assertEqual(149715200, desc.average_bandwidth)
    self.assertEqual(1048576000, desc.burst_bandwidth)
    self.assertEqual(51867731, desc.observed_bandwidth)
    self.assertTrue(desc.exit_policy is not None)
    self.assertEqual(stem.exit_policy.MicroExitPolicy('reject 25,465,587,10000,14464'), desc.exit_policy_v6)
    self.assertTrue('MIGJAoGBAKpPOe' in desc.onion_key)
    self.assertTrue('iW8BqwH5VKqZai' in desc.onion_key_crosscert)
    self.assertTrue('AQoABhtwAWemtV' in desc.ntor_onion_key_crosscert)
    self.assertEqual('0', desc.ntor_onion_key_crosscert_sign)
    self.assertTrue('MIGJAoGBAOUS7x' in desc.signing_key)
    self.assertTrue('y72z1dZOYxVQVL' in desc.signature)
    self.assertEqual('B5E441051D139CCD84BC765D130B01E44DAC29AD', desc.digest())
    self.assertEqual([], desc.get_unrecognized_lines())
Пример #12
0
  def test_for_facebook(self):
    """
    Parse facebook's descriptor.
    """

    descriptor_file = open(get_resource('hidden_service_facebook'), 'rb')

    desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor 1.0', validate = True))
    self.assertEqual('utjk4arxqg6s6zzo7n6cjnq6ot34udhr', desc.descriptor_id)
    self.assertEqual(2, desc.version)
    self.assertEqual('6355jaerje3bqozopwq2qmpf4iviizdn', desc.secret_id_part)
    self.assertEqual(datetime.datetime(2014, 10, 31, 23, 0, 0), desc.published)
    self.assertEqual([2, 3], desc.protocol_versions)
Пример #13
0
  def test_with_ed25519(self):
    """
    Parses a descriptor with a ed25519 identity key.
    """

    with open(get_resource('extrainfo_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = True))

    self.assertEqual('silverfoxden', desc.nickname)
    self.assertEqual('4970B1DC3DBC8D82D7F1E43FF44B28DBF4765A4E', desc.fingerprint)
    self.assertTrue('AQQABhz0AQFcf5tGWLvPvr' in desc.ed25519_certificate)
    self.assertEqual('g6Zg7Er8K7C1etmt7p20INE1ExIvMRPvhwt6sjbLqEK+EtQq8hT+86hQ1xu7cnz6bHee+Zhhmcc4JamV4eiMAw', desc.ed25519_signature)
    self.assertEqual([], desc.get_unrecognized_lines())
Пример #14
0
  def test_bridge_with_ed25519(self):
    """
    Parses a bridge descriptor with a ed25519 identity key.
    """

    with open(get_resource('bridge_extrainfo_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = True))

    self.assertEqual('Unnamed', desc.nickname)
    self.assertEqual('B8AB331047F1C1637EFE07FB1B94CCC0FE0ABFFA', desc.fingerprint)
    self.assertFalse(hasattr(desc, 'ed25519_certificate'))
    self.assertEqual('VigmhxML9uw8CT1XeGqZ8KLMhKk6AOKnChQt24usBbI', desc.ed25519_certificate_hash)
    self.assertEqual('7DSOQz9eGgjDX6GT7qcrVViK8yqJD4aoEnuhdAgYtgA', desc.router_digest_sha256)
    self.assertEqual([], desc.get_unrecognized_lines())
Пример #15
0
  def test_with_carriage_returns(self):
    """
    Read a descriptor file with windows newlines (CRLF).
    """

    descriptor_path = get_resource('unparseable/cached-microdesc-consensus_with_carriage_returns')

    with open(descriptor_path, 'rb') as descriptor_file:
      descriptors = stem.descriptor.parse_file(descriptor_file, 'network-status-microdesc-consensus-3 1.0', normalize_newlines = True)

      # if we didn't strip \r then it would be part of the last flag

      router = next(descriptors)
      self.assertEqual([Flag.FAST, Flag.RUNNING, Flag.STABLE, Flag.VALID], router.flags)
Пример #16
0
  def test_metrics_descriptor_multiple(self):
    """
    Parses and checks our results against a server descriptor from metrics.
    """

    with open(get_resource('metrics_server_desc_multiple'), 'rb') as descriptor_file:
      descriptors = list(stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0'))

      self.assertEqual(2, len(descriptors))

      self.assertEqual('anonion', descriptors[0].nickname)
      self.assertEqual('9A5EC5BB866517E53962AF4D3E776536694B069E', descriptors[0].fingerprint)

      self.assertEqual('Unnamed', descriptors[1].nickname)
      self.assertEqual('5366F1D198759F8894EA6E5FF768C667F59AFD24', descriptors[1].fingerprint)
Пример #17
0
  def test_multiple_metrics_bridge_descriptors(self):
    """
    Check that we can read bridge descriptors when there's multiple in a file.
    """

    descriptor_file = open(get_resource('extrainfo_bridge_descriptor_multiple'), 'rb')
    desc_list = list(stem.descriptor.parse_file(descriptor_file))

    self.assertEqual(6, len(desc_list))
    self.assertEqual('909B07DB17E21D263C55794AB815BF1DB195FDD9', desc_list[0].fingerprint)
    self.assertEqual('7F7798A3CBB0F643B1CFCE3FD4F2B7C553764498', desc_list[1].fingerprint)
    self.assertEqual('B4869206C1EEA4A090FE614155BD6942701F80F1', desc_list[2].fingerprint)
    self.assertEqual('C18896EB6274DC8123491FAE1DD17E1769C54C4F', desc_list[3].fingerprint)
    self.assertEqual('478B4CB438302981DE9AAF246F48DBE57F69050A', desc_list[4].fingerprint)
    self.assertEqual('25D9D52A0350B42E69C8AB7CE945DB1CA38DA0CF', desc_list[5].fingerprint)
Пример #18
0
  def test_bridge_with_ed25519(self):
    """
    Parses a bridge descriptor with ed25519.
    """

    with open(get_resource('bridge_descriptor_with_ed25519'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, validate = True))

    self.assertEqual('ChandlerObfs11', desc.nickname)
    self.assertEqual('678912ABD7398DF8EFC8FA2BC7DEF610710360C4', desc.fingerprint)
    self.assertEqual('10.162.85.172', desc.address)
    self.assertFalse(hasattr(desc, 'ed25519_certificate'))
    self.assertEqual('lgIuiAJCoXPRwWoHgG4ZAoKtmrv47aPr4AsbmESj8AA', desc.ed25519_certificate_hash)
    self.assertEqual('OB/fqLD8lYmjti09R+xXH/D4S2qlizxdZqtudnsunxE', desc.router_digest_sha256)
    self.assertEqual([], desc.get_unrecognized_lines())
Пример #19
0
  def test_with_tarfile_object(self):
    """
    Fetch server descriptors via parse_file() for a tarfile object.
    """

    # TODO: When dropping python 2.6 support we can go back to using the 'with'
    # keyword here.

    tar_file = tarfile.open(get_resource('descriptor_archive.tar'))
    descriptors = list(stem.descriptor.parse_file(tar_file))
    self.assertEqual(3, len(descriptors))

    fingerprints = set([desc.fingerprint for desc in descriptors])
    self.assertEqual(TARFILE_FINGERPRINTS, fingerprints)
    tar_file.close()
  def test_with_basic_auth(self):
    """
    Parse a descriptor with introduction-points encrypted with basic auth.
    """

    if not stem.prereq.is_crypto_available():
      return test.runner.skip(self, 'requires pycrypto')

    descriptor_file = open(get_resource('hidden_service_basic_auth'), 'rb')

    desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor 1.0', validate = True))
    self.assertEqual('yfmvdrkdbyquyqk5vygyeylgj2qmrvrd', desc.descriptor_id)
    self.assertEqual(2, desc.version)
    self.assertEqual('fluw7z3s5cghuuirq3imh5jjj5ljips6', desc.secret_id_part)
    self.assertEqual(datetime.datetime(2015, 2, 24, 20, 0, 0), desc.published)
    self.assertEqual([2, 3], desc.protocol_versions)
    self.assertEqual(EXPECTED_BASIC_AUTH_INTRODUCTION_POINTS_ENCODED, desc.introduction_points_encoded)
    self.assertEqual([], desc.introduction_points_auth)

    self.assertRaises(DecryptionFailure, desc.introduction_points)
    self.assertRaises(DecryptionFailure, desc.introduction_points, 'aCmx3qIvArbil8A0KM4KgQ==')

    introduction_points = desc.introduction_points('dCmx3qIvArbil8A0KM4KgQ==')
    self.assertEqual(3, len(introduction_points))

    point = introduction_points[0]
    self.assertEqual('hmtvoobwglmmec26alnvl7x7mgmmr7xv', point.identifier)
    self.assertEqual('195.154.82.88', point.address)
    self.assertEqual(443, point.port)
    self.assertTrue('MIGJAoGBANbPRD07T' in point.onion_key)
    self.assertTrue('MIGJAoGBAN+LAdZP/' in point.service_key)
    self.assertEqual([], point.intro_authentication)

    point = introduction_points[1]
    self.assertEqual('q5w6l2f4g5zw4rkr56fkyovbkkrnzcj5', point.identifier)
    self.assertEqual('37.252.190.133', point.address)
    self.assertEqual(9001, point.port)
    self.assertTrue('MIGJAoGBAKmsbKrtt' in point.onion_key)
    self.assertTrue('MIGJAoGBANwczLtzR' in point.service_key)
    self.assertEqual([], point.intro_authentication)

    point = introduction_points[2]
    self.assertEqual('qcvprvmvnjb4dfyqjtxskugniliwlrx3', point.identifier)
    self.assertEqual('193.11.114.45', point.address)
    self.assertEqual(9002, point.port)
    self.assertTrue('MIGJAoGBAM1ILL+7P' in point.onion_key)
    self.assertTrue('MIGJAoGBAM7B/cymp' in point.service_key)
    self.assertEqual([], point.intro_authentication)
Пример #21
0
  def test_metrics_bridge_consensus(self):
    """
    Checks if the bridge documents from Metrics are parsed properly.
    """

    consensus_path = get_resource('bridge_network_status')

    with open(consensus_path, 'rb') as descriptor_file:
      router = next(stem.descriptor.parse_file(descriptor_file))
      self.assertEqual('Unnamed', router.nickname)
      self.assertEqual('0014A2055278DB3EB0E59EA701741416AF185558', router.fingerprint)
      self.assertEqual('148EF8685B8D259650AE0967D1FF8E6A870C7743', router.digest)
      self.assertEqual(datetime.datetime(2012, 5, 31, 15, 57, 0), router.published)
      self.assertEqual('10.97.236.247', router.address)
      self.assertEqual(443, router.or_port)
      self.assertEqual(None, router.dir_port)
Пример #22
0
  def test_pickleability(self):
    """
    Checks that we can unpickle lazy loaded server descriptors.
    """

    with open(get_resource('example_descriptor'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0'))

      encoded_desc = pickle.dumps(desc)
      restored_desc = pickle.loads(encoded_desc)

      self.assertEqual('caerSidi', restored_desc.nickname)
      self.assertEqual('A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB', restored_desc.fingerprint)
      self.assertEqual('71.35.133.197', restored_desc.address)
      self.assertEqual(9001, restored_desc.or_port)
      self.assertEqual(None, restored_desc.socks_port)
Пример #23
0
  def test_old_descriptor(self):
    """
    Parses a relay server descriptor from 2005.
    """

    with open(get_resource('old_descriptor'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0', validate = True))

    self.assertEqual('krypton', desc.nickname)
    self.assertEqual('3E2F63E2356F52318B536A12B6445373808A5D6C', desc.fingerprint)
    self.assertEqual('212.37.39.59', desc.address)
    self.assertEqual(8000, desc.or_port)
    self.assertEqual(None, desc.socks_port)
    self.assertEqual(None, desc.dir_port)
    self.assertEqual(b'Tor 0.1.0.14 on FreeBSD i386', desc.platform)
    self.assertEqual(stem.version.Version('0.1.0.14'), desc.tor_version)
    self.assertEqual('FreeBSD i386', desc.operating_system)
    self.assertEqual(64820, desc.uptime)
    self.assertEqual(datetime.datetime(2005, 12, 16, 18, 1, 3), desc.published)
    self.assertEqual(None, desc.contact)
    self.assertEqual(None, desc.link_protocols)
    self.assertEqual(None, desc.circuit_protocols)
    self.assertEqual(True, desc.hibernating)
    self.assertEqual(False, desc.allow_single_hop_exits)
    self.assertEqual(False, desc.allow_tunneled_dir_requests)
    self.assertEqual(False, desc.extra_info_cache)
    self.assertEqual(None, desc.extra_info_digest)
    self.assertEqual(None, desc.extra_info_sha256_digest)
    self.assertEqual(None, desc.hidden_service_dir)
    self.assertEqual(set(), desc.family)
    self.assertEqual(102400, desc.average_bandwidth)
    self.assertEqual(10485760, desc.burst_bandwidth)
    self.assertEqual(0, desc.observed_bandwidth)
    self.assertEqual(datetime.datetime(2005, 12, 16, 18, 0, 48), desc.read_history_end)
    self.assertEqual(900, desc.read_history_interval)
    self.assertEqual(datetime.datetime(2005, 12, 16, 18, 0, 48), desc.write_history_end)
    self.assertEqual(900, desc.write_history_interval)
    self.assertEqual([], desc.get_unrecognized_lines())

    # The read-history and write-history lines are pretty long so just checking
    # the initial contents for the line and parsed values.

    read_values_start = [20774, 489973, 510022, 511163, 20949]
    self.assertEqual(read_values_start, desc.read_history_values[:5])

    write_values_start = [81, 8848, 8927, 8927, 83, 8848, 8931, 8929, 81, 8846]
    self.assertEqual(write_values_start, desc.write_history_values[:10])
  def test_with_stealth_auth(self):
    """
    Parse a descriptor with introduction-points encrypted with stealth auth.
    """

    if not stem.prereq.is_crypto_available():
      return test.runner.skip(self, 'requires pycrypto')

    descriptor_file = open(get_resource('hidden_service_stealth_auth'), 'rb')

    desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor 1.0', validate = True))
    self.assertEqual('ubf3xeibzlfil6s4larq6y5peup2z3oj', desc.descriptor_id)
    self.assertEqual(2, desc.version)
    self.assertEqual('jczvydhzetbpdiylj3d5nsnjvaigs7xm', desc.secret_id_part)
    self.assertEqual(datetime.datetime(2015, 2, 24, 20, 0, 0), desc.published)
    self.assertEqual([2, 3], desc.protocol_versions)
    self.assertEqual([], desc.introduction_points_auth)

    self.assertRaises(DecryptionFailure, desc.introduction_points)
    self.assertRaises(DecryptionFailure, desc.introduction_points, 'aCmx3qIvArbil8A0KM4KgQ==')

    introduction_points = desc.introduction_points('dCmx3qIvArbil8A0KM4KgQ==')
    self.assertEqual(3, len(introduction_points))

    point = introduction_points[0]
    self.assertEqual('6h4bkedts3yz2exl3vu4lsyiwkjrx5ff', point.identifier)
    self.assertEqual('95.85.60.23', point.address)
    self.assertEqual(443, point.port)
    self.assertTrue('MIGJAoGBAMX5hO5hQ' in point.onion_key)
    self.assertTrue('MIGJAoGBAMNSjfydv' in point.service_key)
    self.assertEqual([], point.intro_authentication)

    point = introduction_points[1]
    self.assertEqual('4ghasjftsdfbbycafvlfx7czln3hrk53', point.identifier)
    self.assertEqual('178.254.55.101', point.address)
    self.assertEqual(9901, point.port)
    self.assertTrue('MIGJAoGBAL2v/KNEY' in point.onion_key)
    self.assertTrue('MIGJAoGBAOXiuIgBr' in point.service_key)
    self.assertEqual([], point.intro_authentication)

    point = introduction_points[2]
    self.assertEqual('76tsxvudxqx47gedk3tl5qpesdzrh6yh', point.identifier)
    self.assertEqual('193.11.164.243', point.address)
    self.assertEqual(9001, point.port)
    self.assertTrue('MIGJAoGBALca3zEoS' in point.onion_key)
    self.assertTrue('MIGJAoGBAL3rWIAQ6' in point.service_key)
    self.assertEqual([], point.intro_authentication)
Пример #25
0
  def test_metrics_certificate(self):
    """
    Checks if consensus documents from Metrics are parsed properly.
    """

    expected_identity_key = """-----BEGIN RSA PUBLIC KEY-----
MIIBigKCAYEA7cZXvDRxfjDYtr9/9UsQ852+6cmHMr8VVh8GkLwbq3RzqjkULwQ2
R9mFvG4FnqMcMKXi62rYYA3fZL1afhT804cpvyp/D3dPM8QxW88fafFAgIFP4LiD
0JYjnF8cva5qZ0nzlWnMXLb32IXSvsGSE2FRyAV0YN9a6k967LSgCfUnZ+IKMezW
1vhL9YK4QIfsDowgtVsavg63GzGmA7JvZmn77+/J5wKz11vGr7Wttf8XABbH2taX
O9j/KGBOX2OKhoF3mXfZSmUO2dV9NMwtkJ7zD///Ny6sfApWV6kVP4O9TdG3bAsl
+fHCoCKgF/jAAWzh6VckQTOPzQZaH5aMWfXrDlzFWg17MjonI+bBTD2Ex2pHczzJ
bN7coDMRH2SuOXv8wFf27KdUxZ/GcrXSRGzlRLygxqlripUanjVGN2JvrVQVr0kz
pjNjiZl2z8ZyZ5d4zQuBi074JPGgx62xAstP37v1mPw14sIWfLgY16ewYuS5bCxV
lyS28jsPht9VAgMBAAE=
-----END RSA PUBLIC KEY-----"""

    expected_signing_key = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOeE3Qr1Km97gTgiB3io0EU0fqHW2ESMXVHeQuNDtCWBa0XSCEG6gx4B
ZkkHjfVWqGQ7TmmzjYP9L9uCgtoKfhSvJA2w9NUMtMl8sgZmF4lcGpXXvGY9a566
Bn+3wP0lMhb/I8CPVPX+NWEjgl1noZxo1C59SO/iALGQOpxRYgmbAgMBAAE=
-----END RSA PUBLIC KEY-----"""

    expected_key_cert = """-----BEGIN SIGNATURE-----
asvWwaMq34OfHoWUhAwh4+JDOuEUZJVIHQnedOYfQH8asS2QvW3Ma93OhrwVOC6b
FyKmTJmJsl0MJGiC7tcEOlL6knsKE4CsuIw/PEcu2Rnm+R9zWxQuMYiHvGQMoDxl
giOhLLs4LlzAAJlbfbd3hjF4STVAtTwmxYuIjb1Mq/JfAsx/wH3TLXgVZwj32w9s
zUd9KZwwLzFiiHpC+U7zh6+wRsZfo2tlpmcaP1dTSINgVbdzPJ/DOUlx9nwTCBsE
AQpUx2DpAikwrpw0zDqpQvYulcQlNLWFN/y/PkmiK8mIJk0OBMiQA7JgqWamnnk4
PwqaGv483LkBF+25JFGJmnUVve3RMc+s61+2kBcjfUMed4QaHkeCMHqlRqpfQVkk
RY22NXCwrJvSMEwiy7acC8FGysqwHRyE356+Rw6TB43g3Tno9KaHEK7MHXjSHwNs
GM9hAsAMRX9Ogqhq5UjDNqEsvDKuyVeyh7unSZEOip9Zr6K/+7VsVPNb8vfBRBjo
-----END SIGNATURE-----"""

    with open(get_resource('metrics_cert'), 'rb') as cert_file:
      cert = next(stem.descriptor.parse_file(cert_file))
      self.assertEqual(3, cert.version)
      self.assertEqual(None, cert.address)
      self.assertEqual(None, cert.dir_port)
      self.assertEqual('14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4', cert.fingerprint)
      self.assertEqual(expected_identity_key, cert.identity_key)
      self.assertEqual(datetime.datetime(2008, 5, 9, 21, 13, 26), cert.published)
      self.assertEqual(datetime.datetime(2009, 5, 9, 21, 13, 26), cert.expires)
      self.assertEqual(expected_signing_key, cert.signing_key)
      self.assertEqual(None, cert.crosscert)
      self.assertEqual(expected_key_cert, cert.certification)
      self.assertEqual([], cert.get_unrecognized_lines())
Пример #26
0
  def test_negative_uptime(self):
    """
    Parses a descriptor where we are tolerant of a negative uptime, and another
    where we shouldn't be.
    """

    with open(get_resource('negative_uptime'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0', validate = True))

    self.assertEqual('TipTor', desc.nickname)
    self.assertEqual('137962D4931DBF08A24E843288B8A155D6D2AEDD', desc.fingerprint)
    self.assertEqual('62.99.247.83', desc.address)

    # modify the relay version so it's after when the negative uptime bug
    # should appear

    descriptor_contents = desc.get_bytes().replace(b'Tor 0.1.1.25', b'Tor 0.1.2.7')
    self.assertRaises(ValueError, stem.descriptor.server_descriptor.RelayDescriptor, descriptor_contents, True)
Пример #27
0
  def test_metrics_vote(self):
    """
    Checks if vote documents from Metrics are parsed properly.
    """

    vote_path = get_resource('metrics_vote')

    with open(vote_path, 'rb') as descriptor_file:
      descriptors = stem.descriptor.parse_file(descriptor_file)

      router = next(descriptors)
      self.assertEqual('sumkledi', router.nickname)
      self.assertEqual('0013D22389CD50D0B784A3E4061CB31E8CE8CEB5', router.fingerprint)
      self.assertEqual('0799F806200B005F01E40A9A7F1A21C988AE8FB1', router.digest)
      self.assertEqual(datetime.datetime(2012, 7, 11, 4, 22, 53), router.published)
      self.assertEqual('178.218.213.229', router.address)
      self.assertEqual(80, router.or_port)
      self.assertEqual(None, router.dir_port)
Пример #28
0
  def test_metrics_relay_descriptor(self):
    """
    Parses and checks our results against an extrainfo descriptor from metrics.
    """

    descriptor_file = open(get_resource('extrainfo_relay_descriptor'), 'rb')

    expected_signature = """-----BEGIN SIGNATURE-----
K5FSywk7qvw/boA4DQcqkls6Ize5vcBYfhQ8JnOeRQC9+uDxbnpm3qaYN9jZ8myj
k0d2aofcVbHr4fPQOSST0LXDrhFl5Fqo5um296zpJGvRUeO6S44U/EfJAGShtqWw
7LZqklu+gVvhMKREpchVqlAwXkWR44VENm24Hs+mT3M=
-----END SIGNATURE-----"""

    desc = next(stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0'))
    self.assertEqual('NINJA', desc.nickname)
    self.assertEqual('B2289C3EAB83ECD6EB916A2F481A02E6B76A0A48', desc.fingerprint)
    self.assertEqual(datetime.datetime(2012, 5, 5, 17, 3, 50), desc.published)
    self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.read_history_end)
    self.assertEqual(900, desc.read_history_interval)
    self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.write_history_end)
    self.assertEqual(900, desc.write_history_interval)
    self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.dir_read_history_end)
    self.assertEqual(900, desc.dir_read_history_interval)
    self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.dir_write_history_end)
    self.assertEqual(900, desc.dir_write_history_interval)
    self.assertEqual(expected_signature, desc.signature)
    self.assertEqual('00A57A9AAB5EA113898E2DD02A755E31AFC27227', desc.digest())
    self.assertEqual([], desc.get_unrecognized_lines())

    # The read-history, write-history, dirreq-read-history, and
    # dirreq-write-history lines are pretty long so just checking
    # the initial contents for the line and parsed values.

    read_values_start = [3309568, 9216, 41984, 27648, 123904]
    self.assertEqual(read_values_start, desc.read_history_values[:5])

    write_values_start = [1082368, 19456, 50176, 272384, 485376]
    self.assertEqual(write_values_start, desc.write_history_values[:5])

    dir_read_values_start = [0, 0, 0, 0, 33792, 27648, 48128]
    self.assertEqual(dir_read_values_start, desc.dir_read_history_values[:7])

    dir_write_values_start = [0, 0, 0, 227328, 349184, 382976, 738304]
    self.assertEqual(dir_write_values_start, desc.dir_write_history_values[:7])
Пример #29
0
  def test_non_ascii_descriptor(self):
    """
    Parses a descriptor with non-ascii content.
    """

    with open(get_resource('non-ascii_descriptor'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0', validate = True))

    self.assertEqual('Coruscant', desc.nickname)
    self.assertEqual('0B9821545C48E496AEED9ECC0DB506C49FF8158D', desc.fingerprint)
    self.assertEqual('88.182.161.122', desc.address)
    self.assertEqual(9001, desc.or_port)
    self.assertEqual(None, desc.socks_port)
    self.assertEqual(9030, desc.dir_port)
    self.assertEqual(b'Tor 0.2.3.25 on Linux', desc.platform)
    self.assertEqual(stem.version.Version('0.2.3.25'), desc.tor_version)
    self.assertEqual('Linux', desc.operating_system)
    self.assertEqual(259738, desc.uptime)
    self.assertEqual(datetime.datetime(2013, 5, 18, 11, 16, 19), desc.published)
    self.assertEqual(b'1024D/04D2E818 L\xc3\xa9na\xc3\xafc Huard <lenaic dot huard AT laposte dot net>', desc.contact)
    self.assertEqual(['1', '2'], desc.link_protocols)
    self.assertEqual(['1'], desc.circuit_protocols)
    self.assertEqual(False, desc.hibernating)
    self.assertEqual(False, desc.allow_single_hop_exits)
    self.assertEqual(False, desc.allow_tunneled_dir_requests)
    self.assertEqual(False, desc.extra_info_cache)
    self.assertEqual('56403D838DE152421CD401B8E57DAD4483A3D56B', desc.extra_info_digest)
    self.assertEqual(None, desc.extra_info_sha256_digest)
    self.assertEqual(['2'], desc.hidden_service_dir)
    self.assertEqual(set(), desc.family)
    self.assertEqual(102400, desc.average_bandwidth)
    self.assertEqual(204800, desc.burst_bandwidth)
    self.assertEqual(122818, desc.observed_bandwidth)
    self.assertEqual(stem.exit_policy.ExitPolicy('reject *:*'), desc.exit_policy)
    self.assertEqual([], desc.get_unrecognized_lines())

    # Make sure that we can get a string representation for this descriptor
    # (having non-unicode content risks a UnicodeEncodeError)...
    #
    # https://trac.torproject.org/8265

    self.assertTrue(isinstance(str(desc), str))
Пример #30
0
  def test_cr_in_contact_line(self):
    """
    Parses a descriptor with a huge contact line containing anomalous carriage
    returns ('\r' entries).
    """

    with open(get_resource('cr_in_contact_line'), 'rb') as descriptor_file:
      desc = next(stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0', validate = True))

    self.assertEqual('pogonip', desc.nickname)
    self.assertEqual('6DABD62BC65D4E6FE620293157FC76968DAB9C9B', desc.fingerprint)
    self.assertEqual('75.5.248.48', desc.address)

    # the contact info block is huge so just checking the start and end,
    # including some of the embedded carriage returns

    contact_start = b'jie1 at pacbell dot net -----BEGIN PGP PUBLIC KEY BLOCK-----\rVersion:'
    contact_end = b'YFRk3NhCY=\r=Xaw3\r-----END PGP PUBLIC KEY BLOCK-----'

    self.assertTrue(desc.contact.startswith(contact_start))
    self.assertTrue(desc.contact.endswith(contact_end))
Пример #31
0
    def test_with_ed25519(self):
        """
    Parses a descriptor with a ed25519 identity key, as added by proposal 228
    (cross certification onionkeys).
    """

        with open(get_resource('server_descriptor_with_ed25519'),
                  'rb') as descriptor_file:
            desc = next(
                stem.descriptor.parse_file(descriptor_file, validate=True))

        family = set([
            '$379FB450010D17078B3766C2273303C358C3A442',
            '$3EB46C1D8D8B1C0BBCB6E4F08301EF68B7F5308D',
            '$B0279A521375F3CB2AE210BDBFC645FDD2E1973A',
            '$EC116BCB80565A408CE67F8EC3FE3B0B02C3A065',
        ])

        self.assertEqual(1, desc.certificate.version)
        self.assertEqual(CertType.SIGNING, desc.certificate.type)
        self.assertEqual(datetime.datetime(2015, 8, 28, 17, 0, 0),
                         desc.certificate.expiration)
        self.assertEqual(1, desc.certificate.key_type)
        self.assertTrue(
            desc.certificate.key.startswith(b'\xa5\xb6\x1a\x80D\x0f'))
        self.assertTrue(
            desc.certificate.signature.startswith(b'\xc6\x8e\xd3\xae\x0b'))
        self.assertEqual(1, len(desc.certificate.extensions))
        self.assertTrue('bWPo2fIzo3uOywfoM' in desc.certificate.encoded)

        extension = desc.certificate.extensions[0]
        self.assertEqual(ExtensionType.HAS_SIGNING_KEY, extension.type)
        self.assertEqual([], extension.flags)
        self.assertEqual(0, extension.flag_int)
        self.assertTrue(extension.data.startswith(b'g\xa6\xb5Q\xa6\xd2'))

        self.assertEqual('destiny', desc.nickname)
        self.assertEqual('F65E0196C94DFFF48AFBF2F5F9E3E19AAE583FD0',
                         desc.fingerprint)
        self.assertEqual('94.242.246.23', desc.address)
        self.assertEqual(9001, desc.or_port)
        self.assertEqual(None, desc.socks_port)
        self.assertEqual(443, desc.dir_port)
        self.assertTrue('bWPo2fIzo3uOywfoM' in desc.ed25519_certificate)
        self.assertEqual('Z6a1UabSK+N21j6NnyM6N7jssH6DK68qa6W5uB4QpGQ',
                         desc.ed25519_master_key)
        self.assertEqual(
            'w+cKNZTlL7vz/4WgYdFUblzJy3VdTw0mfFK4N3SPFCt20fNKt9SgiZ5V/2ai3kgGsc6oCsyUesSiYtPcTXMLCw',
            desc.ed25519_signature)
        self.assertEqual(b'Tor 0.2.7.2-alpha-dev on Linux', desc.platform)
        self.assertEqual(stem.version.Version('0.2.7.2-alpha-dev'),
                         desc.tor_version)
        self.assertEqual('Linux', desc.operating_system)
        self.assertEqual(1362680, desc.uptime)
        self.assertEqual(datetime.datetime(2015, 8, 22, 15, 21, 45),
                         desc.published)
        self.assertEqual(
            b'0x02225522 Frenn vun der Enn (FVDE) <info AT enn DOT lu>',
            desc.contact)
        self.assertEqual(['1', '2'], desc.link_protocols)
        self.assertEqual(['1'], desc.circuit_protocols)
        self.assertEqual(False, desc.hibernating)
        self.assertEqual(False, desc.allow_single_hop_exits)
        self.assertEqual(False, desc.allow_tunneled_dir_requests)
        self.assertEqual(False, desc.extra_info_cache)
        self.assertEqual('44E9B679AF0B4EB09296985BAF4066AE9CA5BB93',
                         desc.extra_info_digest)
        self.assertEqual('r+roMxhsjd1GPpn5knQoBvtE9Rhsv8zQHCqiYL6u2CA',
                         desc.extra_info_sha256_digest)
        self.assertEqual(['2'], desc.hidden_service_dir)
        self.assertEqual(family, desc.family)
        self.assertEqual(149715200, desc.average_bandwidth)
        self.assertEqual(1048576000, desc.burst_bandwidth)
        self.assertEqual(51867731, desc.observed_bandwidth)
        self.assertTrue(desc.exit_policy is not None)
        self.assertEqual(
            stem.exit_policy.MicroExitPolicy('reject 25,465,587,10000,14464'),
            desc.exit_policy_v6)
        self.assertTrue('MIGJAoGBAKpPOe' in desc.onion_key)
        self.assertTrue('iW8BqwH5VKqZai' in desc.onion_key_crosscert)
        self.assertTrue('AQoABhtwAWemtV' in desc.ntor_onion_key_crosscert)
        self.assertEqual('0', desc.ntor_onion_key_crosscert_sign)
        self.assertTrue('MIGJAoGBAOUS7x' in desc.signing_key)
        self.assertTrue('y72z1dZOYxVQVL' in desc.signature)
        self.assertEqual('B5E441051D139CCD84BC765D130B01E44DAC29AD',
                         desc.digest())
        self.assertEqual([], desc.get_unrecognized_lines())
Пример #32
0
  def test_consensus_v2(self):
    """
    Checks that version 2 consensus documents are properly parsed.
    """

    expected_signing_key = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOcrht/y5rkaahfX7sMe2qnpqoPibsjTSJaDvsUtaNP/Bq0MgNDGOR48
rtwfqTRff275Edkp/UYw3G3vSgKCJr76/bqOHCmkiZrnPV1zxNfrK18gNw2Cxre0
nTA+fD8JQqpPtb8b0SnG9kwy75eS//sRu7TErie2PzGMxrf9LH0LAgMBAAE=
-----END RSA PUBLIC KEY-----"""

    expected_signature = """-----BEGIN SIGNATURE-----
2nXCxVje3wzn6HrIFRNMc0nc48AhMVpHZyPwRKGXkuYfTQG55uvwQDaFgJHud4RT
27QhWltau3K1evhnzhKcpbTXwkVv1TBYJSzL6rEeAn8cQ7ZiCyqf4EJCaNcem3d2
TpQQk3nNQF8z6UIvdlvP+DnJV4izWVkQEZgUZgIVM0E=
-----END SIGNATURE-----"""

    with open(get_resource('cached-consensus-v2'), 'rb') as descriptor_file:
      descriptor_file.readline()  # strip header
      document = NetworkStatusDocumentV2(descriptor_file.read())

      self.assertEqual(2, document.version)
      self.assertEqual('18.244.0.114', document.hostname)
      self.assertEqual('18.244.0.114', document.address)
      self.assertEqual(80, document.dir_port)
      self.assertEqual('719BE45DE224B607C53707D0E2143E2D423E74CF', document.fingerprint)
      self.assertEqual('arma at mit dot edu', document.contact)
      self.assertEqual(expected_signing_key, document.signing_key)

      self.assertEqual(67, len(document.client_versions))
      self.assertEqual('0.0.9rc2', document.client_versions[0])
      self.assertEqual('0.1.1.10-alpha-cvs', document.client_versions[-1])

      self.assertEqual(67, len(document.server_versions))
      self.assertEqual('0.0.9rc2', document.server_versions[0])
      self.assertEqual('0.1.1.10-alpha-cvs', document.server_versions[-1])

      self.assertEqual(datetime.datetime(2005, 12, 16, 0, 13, 46), document.published)
      self.assertEqual(['Names', 'Versions'], document.options)
      self.assertEqual('moria2', document.signing_authority)
      self.assertEqual(expected_signature, document.signature)
      self.assertEqual([], document.get_unrecognized_lines())

      self.assertEqual(3, len(document.routers))
      self.assertEqual('@type network-status-2 1.0', str(document.type_annotation()))

      router1 = document.routers['719BE45DE224B607C53707D0E2143E2D423E74CF']
      self.assertEqual('moria2', router1.nickname)
      self.assertEqual('719BE45DE224B607C53707D0E2143E2D423E74CF', router1.fingerprint)
      self.assertEqual('B7F3F0975B87889DD1285FD57A1B1BB617F65432', router1.digest)
      self.assertEqual(datetime.datetime(2005, 12, 15, 6, 57, 18), router1.published)
      self.assertEqual('18.244.0.114', router1.address)
      self.assertEqual(443, router1.or_port)
      self.assertEqual(80, router1.dir_port)
      self.assertEqual(set(['Authority', 'Fast', 'Named', 'Running', 'Valid', 'V2Dir']), set(router1.flags))

      router2 = document.routers['0928BA467056C4A689FEE4EF5D71482B6289C3D5']
      self.assertEqual('stnv', router2.nickname)
      self.assertEqual('0928BA467056C4A689FEE4EF5D71482B6289C3D5', router2.fingerprint)
      self.assertEqual('22D1A7ED4199BDA7ED6C416EECD769C18E1F2A5A', router2.digest)
      self.assertEqual(datetime.datetime(2005, 12, 15, 16, 24, 42), router2.published)
      self.assertEqual('84.16.236.173', router2.address)
      self.assertEqual(9001, router2.or_port)
      self.assertEqual(None, router2.dir_port)
      self.assertEqual(set(['Named', 'Valid']), set(router2.flags))

      router3 = document.routers['09E8582FF0E6F85E2B8E41C0DC0B9C9DC46E6968']
      self.assertEqual('nggrplz', router3.nickname)
      self.assertEqual('09E8582FF0E6F85E2B8E41C0DC0B9C9DC46E6968', router3.fingerprint)
      self.assertEqual('B302C2B01C94F398E3EF38939526B0651F824DD6', router3.digest)
      self.assertEqual(datetime.datetime(2005, 12, 15, 23, 25, 50), router3.published)
      self.assertEqual('194.109.109.109', router3.address)
      self.assertEqual(9001, router3.or_port)
      self.assertEqual(None, router3.dir_port)
      self.assertEqual(set(['Fast', 'Stable', 'Running', 'Valid']), set(router3.flags))
Пример #33
0
    def test_metrics_descriptor(self):
        """
    Parses and checks our results against a server descriptor from metrics.
    """

        descriptor_file = open(get_resource('example_descriptor'), 'rb')

        expected_family = set([
            '$0CE3CFB1E9CC47B63EA8869813BF6FAB7D4540C1',
            '$1FD187E8F69A9B74C9202DC16A25B9E7744AB9F6',
            '$74FB5EFA6A46DE4060431D515DC9A790E6AD9A7C',
            '$77001D8DA9BF445B0F81AA427A675F570D222E6A',
            '$B6D83EC2D9E18B0A7A33428F8CFA9C536769E209',
            '$D2F37F46182C23AB747787FD657E680B34EAF892',
            '$E0BD57A11F00041A9789577C53A1B784473669E4',
            '$E5E3E9A472EAF7BE9682B86E92305DB4C71048EF',
        ])

        expected_onion_key = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAJv5IIWQ+WDWYUdyA/0L8qbIkEVH/cwryZWoIaPAzINfrw1WfNZGtBmg
skFtXhOHHqTRN4GPPrZsAIUOQGzQtGb66IQgT4tO/pj+P6QmSCCdTfhvGfgTCsC+
WPi4Fl2qryzTb3QO5r5x7T8OsG2IBUET1bLQzmtbC560SYR49IvVAgMBAAE=
-----END RSA PUBLIC KEY-----"""

        expected_signing_key = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKwvOXyztVKnuYvpTKt+nS3XIKeO8dVungi8qGoeS+6gkR6lDtGfBTjd
uE9UIkdAl9zi8/1Ic2wsUNHE9jiS0VgeupITGZY8YOyMJJ/xtV1cqgiWhq1dUYaq
51TOtUogtAPgXPh4J+V8HbFFIcCzIh3qCO/xXo+DSHhv7SSif1VpAgMBAAE=
-----END RSA PUBLIC KEY-----"""

        expected_signature = """-----BEGIN SIGNATURE-----
dskLSPz8beUW7bzwDjR6EVNGpyoZde83Ejvau+5F2c6cGnlu91fiZN3suE88iE6e
758b9ldq5eh5mapb8vuuV3uO+0Xsud7IEOqfxdkmk0GKnUX8ouru7DSIUzUL0zqq
Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
-----END SIGNATURE-----"""

        desc = next(
            stem.descriptor.parse_file(descriptor_file,
                                       'server-descriptor 1.0'))
        self.assertEqual('caerSidi', desc.nickname)
        self.assertEqual('A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB',
                         desc.fingerprint)
        self.assertEqual('71.35.133.197', desc.address)
        self.assertEqual(9001, desc.or_port)
        self.assertEqual(None, desc.socks_port)
        self.assertEqual(None, desc.dir_port)
        self.assertEqual(b'Tor 0.2.1.30 on Linux x86_64', desc.platform)
        self.assertEqual(stem.version.Version('0.2.1.30'), desc.tor_version)
        self.assertEqual('Linux x86_64', desc.operating_system)
        self.assertEqual(588217, desc.uptime)
        self.assertEqual(datetime.datetime(2012, 3, 1, 17, 15, 27),
                         desc.published)
        self.assertEqual(b'www.atagar.com/contact', desc.contact)
        self.assertEqual(['1', '2'], desc.link_protocols)
        self.assertEqual(['1'], desc.circuit_protocols)
        self.assertEqual(False, desc.hibernating)
        self.assertEqual(False, desc.allow_single_hop_exits)
        self.assertEqual(False, desc.extra_info_cache)
        self.assertEqual('D225B728768D7EA4B5587C13A7A9D22EBBEE6E66',
                         desc.extra_info_digest)
        self.assertEqual(['2'], desc.hidden_service_dir)
        self.assertEqual(expected_family, desc.family)
        self.assertEqual(153600, desc.average_bandwidth)
        self.assertEqual(256000, desc.burst_bandwidth)
        self.assertEqual(104590, desc.observed_bandwidth)
        self.assertEqual(stem.exit_policy.ExitPolicy('reject *:*'),
                         desc.exit_policy)
        self.assertEqual(expected_onion_key, desc.onion_key)
        self.assertEqual(expected_signing_key, desc.signing_key)
        self.assertEqual(expected_signature, desc.signature)
        self.assertEqual([], desc.get_unrecognized_lines())
        self.assertEqual('2C7B27BEAB04B4E2459D89CA6D5CD1CC5F95A689',
                         desc.digest())
Пример #34
0
    def test_metrics_relay_descriptor(self):
        """
    Parses and checks our results against an extrainfo descriptor from metrics.
    """

        descriptor_file = open(get_resource('extrainfo_relay_descriptor'),
                               'rb')

        expected_signature = """-----BEGIN SIGNATURE-----
K5FSywk7qvw/boA4DQcqkls6Ize5vcBYfhQ8JnOeRQC9+uDxbnpm3qaYN9jZ8myj
k0d2aofcVbHr4fPQOSST0LXDrhFl5Fqo5um296zpJGvRUeO6S44U/EfJAGShtqWw
7LZqklu+gVvhMKREpchVqlAwXkWR44VENm24Hs+mT3M=
-----END SIGNATURE-----"""

        desc = next(
            stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0'))
        self.assertEqual('NINJA', desc.nickname)
        self.assertEqual('B2289C3EAB83ECD6EB916A2F481A02E6B76A0A48',
                         desc.fingerprint)
        self.assertEqual(datetime.datetime(2012, 5, 5, 17, 3, 50),
                         desc.published)
        self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45),
                         desc.read_history_end)
        self.assertEqual(900, desc.read_history_interval)
        self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45),
                         desc.write_history_end)
        self.assertEqual(900, desc.write_history_interval)
        self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45),
                         desc.dir_read_history_end)
        self.assertEqual(900, desc.dir_read_history_interval)
        self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45),
                         desc.dir_write_history_end)
        self.assertEqual(900, desc.dir_write_history_interval)
        self.assertEqual(expected_signature, desc.signature)
        self.assertEqual('00A57A9AAB5EA113898E2DD02A755E31AFC27227',
                         desc.digest(stem.descriptor.DigestHash.SHA1))
        self.assertEqual(
            'n2+wh6uM+lbKnhbkOog2jv9X5tPytlrFdO+I+auSmME',
            desc.digest(stem.descriptor.DigestHash.SHA256,
                        stem.descriptor.DigestEncoding.BASE64))
        self.assertEqual([], desc.get_unrecognized_lines())

        # The read-history, write-history, dirreq-read-history, and
        # dirreq-write-history lines are pretty long so just checking
        # the initial contents for the line and parsed values.

        read_values_start = [3309568, 9216, 41984, 27648, 123904]
        self.assertEqual(read_values_start, desc.read_history_values[:5])

        write_values_start = [1082368, 19456, 50176, 272384, 485376]
        self.assertEqual(write_values_start, desc.write_history_values[:5])

        dir_read_values_start = [0, 0, 0, 0, 33792, 27648, 48128]
        self.assertEqual(dir_read_values_start,
                         desc.dir_read_history_values[:7])

        dir_write_values_start = [0, 0, 0, 227328, 349184, 382976, 738304]
        self.assertEqual(dir_write_values_start,
                         desc.dir_write_history_values[:7])

        self.assertEqual('@type extra-info 1.0', str(desc.type_annotation()))
Пример #35
0
    def test_old_descriptor(self):
        """
    Parses a relay server descriptor from 2005.
    """

        with open(get_resource('old_descriptor'), 'rb') as descriptor_file:
            desc = next(
                stem.descriptor.parse_file(
                    descriptor_file,
                    'server-descriptor 1.0',
                    validate=True,
                    skip_crypto_validation=not test.require.
                    CRYPTOGRAPHY_AVAILABLE,
                ))

        self.assertEqual('krypton', desc.nickname)
        self.assertEqual('3E2F63E2356F52318B536A12B6445373808A5D6C',
                         desc.fingerprint)
        self.assertEqual('212.37.39.59', desc.address)
        self.assertEqual(8000, desc.or_port)
        self.assertEqual(None, desc.socks_port)
        self.assertEqual(None, desc.dir_port)
        self.assertEqual(b'Tor 0.1.0.14 on FreeBSD i386', desc.platform)
        self.assertEqual(stem.version.Version('0.1.0.14'), desc.tor_version)
        self.assertEqual('FreeBSD i386', desc.operating_system)
        self.assertEqual(64820, desc.uptime)
        self.assertEqual(datetime.datetime(2005, 12, 16, 18, 1, 3),
                         desc.published)
        self.assertEqual(None, desc.contact)
        self.assertEqual(None, desc.link_protocols)
        self.assertEqual(None, desc.circuit_protocols)
        self.assertEqual(False, desc.is_hidden_service_dir)
        self.assertEqual(True, desc.hibernating)
        self.assertEqual(False, desc.allow_single_hop_exits)
        self.assertEqual(False, desc.allow_tunneled_dir_requests)
        self.assertEqual(False, desc.extra_info_cache)
        self.assertEqual(None, desc.extra_info_digest)
        self.assertEqual(None, desc.extra_info_sha256_digest)
        self.assertEqual(BridgeDistribution.ANY, desc.bridge_distribution)
        self.assertEqual(set(), desc.family)
        self.assertEqual(102400, desc.average_bandwidth)
        self.assertEqual(10485760, desc.burst_bandwidth)
        self.assertEqual(0, desc.observed_bandwidth)
        self.assertEqual(datetime.datetime(2005, 12, 16, 18, 0, 48),
                         desc.read_history_end)
        self.assertEqual(900, desc.read_history_interval)
        self.assertEqual(datetime.datetime(2005, 12, 16, 18, 0, 48),
                         desc.write_history_end)
        self.assertEqual(900, desc.write_history_interval)
        self.assertEqual([], desc.get_unrecognized_lines())

        # The read-history and write-history lines are pretty long so just checking
        # the initial contents for the line and parsed values.

        read_values_start = [20774, 489973, 510022, 511163, 20949]
        self.assertEqual(read_values_start, desc.read_history_values[:5])

        write_values_start = [
            81, 8848, 8927, 8927, 83, 8848, 8931, 8929, 81, 8846
        ]
        self.assertEqual(write_values_start, desc.write_history_values[:10])
Пример #36
0
    def test_metrics_bridge_descriptor(self):
        """
    Parses and checks our results against an extrainfo bridge descriptor from
    metrics.
    """

        descriptor_file = open(get_resource('extrainfo_bridge_descriptor'),
                               'rb')

        expected_dir_v2_responses = {
            DirResponse.OK: 0,
            DirResponse.UNAVAILABLE: 0,
            DirResponse.NOT_FOUND: 0,
            DirResponse.NOT_MODIFIED: 0,
            DirResponse.BUSY: 0,
        }

        expected_dir_v3_responses = {
            DirResponse.OK: 72,
            DirResponse.NOT_ENOUGH_SIGS: 0,
            DirResponse.UNAVAILABLE: 0,
            DirResponse.NOT_FOUND: 0,
            DirResponse.NOT_MODIFIED: 0,
            DirResponse.BUSY: 0,
        }

        desc = next(
            stem.descriptor.parse_file(descriptor_file,
                                       'bridge-extra-info 1.0'))
        self.assertEqual('ec2bridgereaac65a3', desc.nickname)
        self.assertEqual('1EC248422B57D9C0BD751892FE787585407479A4',
                         desc.fingerprint)
        self.assertEqual(datetime.datetime(2012, 6, 8, 2, 21, 27),
                         desc.published)
        self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38),
                         desc.read_history_end)
        self.assertEqual(900, desc.read_history_interval)
        self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38),
                         desc.write_history_end)
        self.assertEqual(900, desc.write_history_interval)
        self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38),
                         desc.dir_read_history_end)
        self.assertEqual(900, desc.dir_read_history_interval)
        self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38),
                         desc.dir_write_history_end)
        self.assertEqual(900, desc.dir_write_history_interval)
        self.assertEqual('00A2AECCEAD3FEE033CFE29893387143146728EC',
                         desc.digest())
        self.assertEqual([], desc.get_unrecognized_lines())

        read_values_start = [337920, 437248, 3995648, 48726016]
        self.assertEqual(read_values_start, desc.read_history_values[:4])

        write_values_start = [343040, 991232, 5649408, 49548288]
        self.assertEqual(write_values_start, desc.write_history_values[:4])

        dir_read_values_start = [0, 71680, 99328, 25600]
        self.assertEqual(dir_read_values_start,
                         desc.dir_read_history_values[:4])

        dir_write_values_start = [5120, 664576, 2419712, 578560]
        self.assertEqual(dir_write_values_start,
                         desc.dir_write_history_values[:4])

        self.assertEqual({}, desc.dir_v2_requests)
        self.assertEqual({}, desc.dir_v3_requests)

        self.assertEqual(expected_dir_v2_responses, desc.dir_v2_responses)
        self.assertEqual(expected_dir_v3_responses, desc.dir_v3_responses)

        self.assertEqual({}, desc.dir_v2_responses_unknown)
        self.assertEqual({}, desc.dir_v2_responses_unknown)

        self.assertEqual('@type bridge-extra-info 1.0',
                         str(desc.type_annotation()))
Пример #37
0
"""

import datetime
import io
import unittest

import stem.descriptor.collector

from unittest.mock import Mock, patch

from stem.descriptor import Compression, DocumentHandler
from stem.descriptor.collector import CollecTor, File
from test.unit.descriptor import get_resource
from test.unit.descriptor.data.collector.index import EXAMPLE_INDEX

with open(get_resource('collector/index.json'), 'rb') as index_file:
    EXAMPLE_INDEX_JSON = index_file.read()


class TestCollector(unittest.TestCase):
    # tests for the File class

    def test_file_guess_compression(self):
        test_values = {
            'archive/relay-descriptors/microdescs/microdescs-2014-01.tar.xz':
            Compression.LZMA,
            'archive/webstats/webstats-2015-03.tar':
            Compression.PLAINTEXT,
            'recent/relay-descriptors/extra-infos/2019-07-03-02-05-00-extra-infos':
            Compression.PLAINTEXT,
        }
Пример #38
0
BDwQZ8rhp05oCqhhY3oFHqG9KS7HGzv9g2v1/PrVJMbkfpwu1YK4b3zIZAk=
-----END ED25519 CERT-----\
"""

EXPECTED_OUTER_LAYER = """\
desc-auth-type foo
desc-auth-ephemeral-key bar
auth-client JNil86N07AA epkaL79NtajmgME/egi8oA qosYH4rXisxda3X7p9b6fw
auth-client 1D8VBAh9hdM 6K/uO3sRqBp6URrKC7GB6Q ElwRj5+6SN9kb8bRhiiQvA
encrypted
-----BEGIN MESSAGE-----
malformed block
-----END MESSAGE-----\
"""

with open(get_resource('hidden_service_v3')) as descriptor_file:
    HS_DESC_STR = descriptor_file.read()

with open(get_resource('hidden_service_v3_outer_layer')) as outer_layer_file:
    OUTER_LAYER_STR = outer_layer_file.read()

with open(get_resource('hidden_service_v3_inner_layer')) as inner_layer_file:
    INNER_LAYER_STR = inner_layer_file.read()

with open(get_resource('hidden_service_v3_intro_point')) as intro_point_file:
    INTRO_POINT_STR = intro_point_file.read()


class TestHiddenServiceDescriptorV3(unittest.TestCase):
    def test_real_descriptor(self):
        """
Пример #39
0
    def test_real_certificates(self):
        """
    Checks that key certificates from chutney can be properly parsed.
    """

        expected_identity_key = """\
-----BEGIN RSA PUBLIC KEY-----
MIIBigKCAYEAxfTHG1b3Sxe8n3JQ/nIk4+1/chj7+jAyLLK+WrEBiP1vnDxTXMuo
x26ntWEjOaxjtKB12k5wMQW94/KvE754Gn98uQRFBHqLkrS4hUnn4/MqiBQVd2y3
UtE6KDSRhJZ5LfFH+dCKwu5+695PyJp/pfCUSOyPj0HQbFOnAOqdHPok8dtdfsy0
LaI7ycpzqAalzgrlwFP5KwwLtL+VapUGN4QOZlIXgL4W5e7OAG42lZhHt0b7/zdt
oIegZM1y8tK2l75ijqsvbetddQcFlnVaYzNwlQAUIZuxJOGfnPfTo+WrjCgrK2ur
ed5NiQMrEbZn5uCUscs+xLlKl4uKW0XXo1EIL45yBrVbmlP6V3/9diTHk64W9+m8
2G4ToDyH8J7LvnYPsmD0cCaQEceebxYVlmmwgqdORH/ixbeGF7JalTwtWBQYo2r0
VZAqjRwxR9dri6m1MIpzmzWmrbXghZ1IzJEL1rpB0okA/bE8AUGRx61eKnbI415O
PmO06JMpvkxxAgMBAAE=
-----END RSA PUBLIC KEY-----"""

        expected_signing_key = """\
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAvzugxJl1gc7BgXarBO5IWejNZC30U1xVjZ/myQTzxtiKkPU0agQh
sPqn4vVsaW6ZnWjJ2pSOq0/jg8WgFyGHGQ9cG8tv2TlpObeb/tI7iANxWx+MXJAh
/CnFDBQ1ifKntJrs2IcRKMivfobqaHAL3Pz93noLWOTQunWjZ8D6kovYvUXe+yUQ
tZEROrmXJx7ZIIJF6BNKYBTc+iEkYtkWlJVs0my7yP/bbS075QyBsr6CfT+O2yU4
mgIg43QuqcFRbjyUvGI/gap06QNlB6yj8pqeE5rWo++5EpEvMK76fK6ymYuTN2SN
Oil+Fo7qgG8UP/fv0GelSz6Tk7pBoeHJlQIDAQAB
-----END RSA PUBLIC KEY-----"""

        expected_crosscert = """\
-----BEGIN ID SIGNATURE-----
Oz+rvXDzlxLgQSb3nS5/4hrHVWgGCy0OnuNmFsyw8bi2eBst5Yj79dQ+D25giZke
81FRGIFU4eS6dshB+pJ+z0hc9ozlRTYh/qevY6l6o0amvuhHyk/cQXrh8oYU9Ihe
XQ1yVItvxC24HENsoGIGbr5uxc85FOcNs+R9qTLYA/56TjvAU4WUje3nTZE1awml
lj/Y6DM7ruMF6UoYJZPTklukZ+XHZg4Z2eE55e/oIaD7bfU/lFWU/alMyTV/J5oT
sxaD2XBLBScYiKypUmgrZ50W4ZqsXaYk76ClrudZnDbce+FuugVxok+jKYGjMu75
2es2ucuik7iuO7QPdPIXfg==
-----END ID SIGNATURE-----"""

        expected_key_cert = """\
-----BEGIN SIGNATURE-----
I86FTQ5ZyCZUzm19HVAQWByrrRgUmddoRBfNiCj0iTGN3kdIq9OfuNLhWAqz71xP
8Nn0Vun8Uj3/vBq/odIFpnngL3mKI6OEKcNDr0D5hEV9Yjrxe8msMoaUZT+LHzUW
1q3pzxfMx6EmlSilMhuzSsa4YEbXMZzMqASKANSJHo2fzUkzQOpPw2SlWSTIgyqw
wAOB6QOvFfP3c0NTwxXrYE/iT+r90wZBuzS+v7r9B94alNAkE1KZQKnq2QTTIznP
iF9LWMsZcMHCjoTxszK4jF4MRMN/S4Xl8yQo0/z6FoqBz4RIXzFtJoG/rbXdKfkE
nJK9iEhaZbS1IN0o+uIGtvOm2rQSu9gS8merurr5GDSK3szjesPVJuF00mCNgOx4
hAYPN9N8HAL4zGE/l1UM7BGg3L84A0RMpDxnpXePd9mlHLhl4UV2lrkkf8S9Z6fX
PPc3r7zKlL/jEGHwz+C7kE88HIvkVnKLLn//40b6HxitHSOCkZ1vtp8YyXae6xnU
-----END SIGNATURE-----"""

        with open(get_resource('cached-certs'), 'rb') as cert_file:
            cert = next(
                stem.descriptor.parse_file(cert_file,
                                           'dir-key-certificate-3 1.0'))
            self.assertEqual(3, cert.version)
            self.assertEqual('127.0.0.1', cert.address)
            self.assertEqual(7000, cert.dir_port)
            self.assertEqual('BCB380A633592C218757BEE11E630511A485658A',
                             cert.fingerprint)
            self.assertEqual(expected_identity_key, cert.identity_key)
            self.assertEqual(datetime.datetime(2017, 5, 25, 4, 45, 52),
                             cert.published)
            self.assertEqual(datetime.datetime(2018, 5, 25, 4, 45, 52),
                             cert.expires)
            self.assertEqual(expected_signing_key, cert.signing_key)
            self.assertEqual(expected_crosscert, cert.crosscert)
            self.assertEqual(expected_key_cert, cert.certification)
            self.assertEqual('@type dir-key-certificate-3 1.0',
                             str(cert.type_annotation()))
            self.assertEqual([], cert.get_unrecognized_lines())