diff options
| author | Philipp Winter <phw@nymity.ch> | 2019-04-12 11:46:28 -0700 |
|---|---|---|
| committer | Philipp Winter <phw@nymity.ch> | 2019-04-26 13:19:10 -0700 |
| commit | 3bc9c660e8df80fe89693c8e4fad38955011bf20 (patch) | |
| tree | bbab6207e275be5632d3d1f5af5fa454d2d2a811 | |
| parent | bad0bed11a9018f65555b3c6998b26e2cb06f5b5 (diff) | |
Allow creation of probing-vulnerable descriptors.
This patch makes it possible to determine the number of descriptors that
will expose transports that are vulnerable to active probing attacks,
i.e., vanilla, obfs2, and obfs3. This is necessary to keep BridgeDB's
unit tests working after our fix for bug 28655, in which we make active
probing-resistant bridges not give out transports that aren't resistant
to active probing: <https://bugs.torproject.org/28655>
| -rw-r--r-- | leekspin/extrainfo.py | 37 | ||||
| -rw-r--r-- | leekspin/generator.py | 44 | ||||
| -rw-r--r-- | leekspin/util.py | 4 | ||||
| -rwxr-xr-x | scripts/leekspin | 3 |
4 files changed, 58 insertions, 30 deletions
diff --git a/leekspin/extrainfo.py b/leekspin/extrainfo.py index 26aeb6c..ec1a1ba 100644 --- a/leekspin/extrainfo.py +++ b/leekspin/extrainfo.py @@ -13,7 +13,7 @@ from leekspin import const from leekspin import util -def generateExtraInfo(nickname, fingerprint, ts, ipv4, port, bridge=True): +def generateExtraInfo(nickname, fingerprint, ts, ipv4, port, bridge=None): """Create an OR extra-info document. See ยง2.2 "Extra-info documents" in dir-spec.txt_. @@ -51,22 +51,25 @@ def generateExtraInfo(nickname, fingerprint, ts, ipv4, port, bridge=True): extra.append(b"dirreq-v3-direct-dl complete=0,timeout=0,running=0") extra.append(b"dirreq-v3-tunneled-dl complete=12,timeout=0,running=0") - if bridge: - scramblesuitPassword = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' - - obfs4iatMode = bytes(random.getrandbits(1)) # 0 or 1 - # hexadecimal, 40 chars long: - obfs4nodeID = hashlib.sha1(bytes(random.getrandbits(8))).hexdigest() - # hexadecimal, 64 chars long: - obfs4publicKey = hashlib.sha256(bytes(random.getrandbits(8))).hexdigest() - - extra.append(b"transport obfs3 %s:%d" % (ipv4, port + 1)) - extra.append(b"transport obfs2 %s:%d" % (ipv4, port + 2)) - extra.append(b"transport scramblesuit %s:%d password=%s" % - (ipv4, port + 3, scramblesuitPassword)) - # PT args are comma-separated in the bridge-extrainfo descriptors: - extra.append(b"transport obfs4 %s:%d iat-mode=%s,node-id=%s,public-key=%s" % - (ipv4, port + 4, obfs4iatMode, obfs4nodeID, obfs4publicKey)) + if bridge is not None: + + if 'obfs3' in bridge: + extra.append(b"transport obfs3 %s:%d" % (ipv4, port + 1)) + if 'obfs2' in bridge: + extra.append(b"transport obfs2 %s:%d" % (ipv4, port + 2)) + if 'scramblesuit' in bridge: + scramblesuitPassword = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' + extra.append(b"transport scramblesuit %s:%d password=%s" % + (ipv4, port + 3, scramblesuitPassword)) + if 'obfs4' in bridge: + obfs4iatMode = bytes(random.getrandbits(1)) # 0 or 1 + # hexadecimal, 40 chars long: + obfs4nodeID = hashlib.sha1(bytes(random.getrandbits(8))).hexdigest() + # hexadecimal, 64 chars long: + obfs4publicKey = hashlib.sha256(bytes(random.getrandbits(8))).hexdigest() + # PT args are comma-separated in the bridge-extrainfo descriptors: + extra.append(b"transport obfs4 %s:%d iat-mode=%s,node-id=%s,public-key=%s" % + (ipv4, port + 4, obfs4iatMode, obfs4nodeID, obfs4publicKey)) extra.append(b"bridge-stats-end %s (86400 s)" % ts) extra.append(b"bridge-ips ca=8") extra.append(b"bridge-ip-versions v4=8,v6=0") diff --git a/leekspin/generator.py b/leekspin/generator.py index a28ef7e..95a7c48 100644 --- a/leekspin/generator.py +++ b/leekspin/generator.py @@ -44,11 +44,11 @@ from leekspin import util nacl = True if ntor.nacl else False -def generateDescriptors(bridge=True, withoutTAP=False, withoutNTOR=False): +def generateDescriptors(bridge=None, withoutTAP=False, withoutNTOR=False): """Create keys, certs, signatures, documents and descriptors for an OR. - :param bool bridge: If ``True``, generate Bridge descriptors; otherwise, - generate Relay descriptors. + :param list bridge: If not ``None``, generate Bridge descriptors with the + given transport types; otherwise, generate Relay descriptors. :param bool withoutTAP: If ``True``, generate descriptors without support for the TAP handshake, e.g. without RSA keys. :param bool withoutTAP: If ``True``, generate descriptors without @@ -106,12 +106,12 @@ def generateDescriptors(bridge=True, withoutTAP=False, withoutNTOR=False): vers, protocols, uptime, bandwidth, extrainfoDigest, onionKeyLine, signingKeyLine, - publicNTORKey, bridge=bridge) + publicNTORKey, bridge=bridge is not None) (serverDigestBinary, serverDigest, serverDigestPKCS1) = crypto.digestDescriptorContent(serverDoc) - if bridge: + if bridge is not None: serverDoc = b'@purpose bridge\n' + serverDoc serverDesc = crypto.signDescriptorContent(serverDoc, @@ -245,18 +245,24 @@ def createRelayOrBridgeDescriptors(count, bridge=True, **kwargs): :param bool bridge: If ``True``, generate Bridge descriptors; otherwise, generate Relay descriptors. """ - logging.info("Generating %d %s descriptors..." % - (int(count), 'bridge' if bridge else 'relay')) - logging.info("Generated router nicknames:") - withoutTAP = False withoutNTOR = False + numProbingVulnerable = 0 if kwargs: if "withoutTAP" in kwargs: withoutTAP = kwargs.get("withoutTAP") if "withoutNTOR" in kwargs: withoutNTOR = kwargs.get("withoutNTOR") + if "numProbingVulnerable" in kwargs: + numProbingVulnerable = kwargs.get("numProbingVulnerable") + + logging.info("Generating %d %s descriptors, among which %d only support " + "protocols vulnerable to active probing..." % + (int(count), 'bridge' if bridge else 'relay', + numProbingVulnerable)) + logging.info("Generated router nicknames:") + server_descriptors = list() netstatus_consensus = list() @@ -271,9 +277,21 @@ def createRelayOrBridgeDescriptors(count, bridge=True, **kwargs): for i in xrange(int(count)): try: + pt_names = ['obfs2', 'obfs3', 'obfs4', 'scramblesuit'] + # We facilitate the creation of descriptors that only advertise + # transports that are vulnerable to active probing attacks. + # This is necessary to keep BridgeDB's unit tests working after + # our fix for bug 28655, in which we make active + # probing-resistant bridges not give out transports that aren't + # resistant to active probing: + # <https://bugs.torproject.org/28655> + if numProbingVulnerable: + pt_names = ['obfs2', 'obfs3'] + numProbingVulnerable -= 1 + (extrainfo, server, - netstatus) = generateDescriptors(bridge=bridge, + netstatus) = generateDescriptors(bridge=pt_names, withoutTAP=withoutTAP, withoutNTOR=withoutNTOR) except Exception as error: @@ -328,7 +346,8 @@ def createRelayOrBridgeDescriptors(count, bridge=True, **kwargs): code = 0 sys.exit(code) -def create(count, descriptorType=None, withoutTAP=False, withoutNTOR=False): +def create(count, descriptorType=None, withoutTAP=False, withoutNTOR=False, + numProbingVulnerable=0): """Create **count** descriptors of type **descriptor_type**. :param int count: The number of descriptors to generate. @@ -346,6 +365,7 @@ def create(count, descriptorType=None, withoutTAP=False, withoutNTOR=False): bridge = bool(descriptorType == 'bridge') createRelayOrBridgeDescriptors(count, bridge=bridge, withoutTAP=withoutTAP, - withoutNTOR=withoutNTOR) + withoutNTOR=withoutNTOR, + numProbingVulnerable=numProbingVulnerable) elif descriptorType in ('hidden_service',): createHiddenServiceDescriptors(count) diff --git a/leekspin/util.py b/leekspin/util.py index 13c8d5a..bb6a432 100644 --- a/leekspin/util.py +++ b/leekspin/util.py @@ -62,6 +62,10 @@ def getArgParser(): descgroup2.add_argument("-xn", "--without-ntor", action="store_true", help=("generate descriptors without ntor support, " "e.g. without Ed25519 keys")) + descgroup2.add_argument("-xp", "--num-probing-vulnerable", default=0, type=int, + help="make <m> out of all <n> descriptors " + "vulnerable to active probing (i.e., obfs2, " + "obfs3, and vanilla.") descgroup2.set_defaults(without_tap=False, without_ntor=False) group = parser.add_argument_group() diff --git a/scripts/leekspin b/scripts/leekspin index abc2ddb..23d7aa3 100755 --- a/scripts/leekspin +++ b/scripts/leekspin @@ -63,7 +63,8 @@ if __name__ == "__main__": if options.descriptors and (options.descriptors > 0): generator.create(options.descriptors, descriptorType=descType, withoutTAP=options.without_tap, - withoutNTOR=options.without_ntor) + withoutNTOR=options.without_ntor, + numProbingVulnerable=options.num_probing_vulnerable) else: raise SystemExit(parser.format_help()) |
