summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Winter <phw@nymity.ch>2019-04-12 11:46:28 -0700
committerPhilipp Winter <phw@nymity.ch>2019-04-26 13:19:10 -0700
commit3bc9c660e8df80fe89693c8e4fad38955011bf20 (patch)
treebbab6207e275be5632d3d1f5af5fa454d2d2a811
parentbad0bed11a9018f65555b3c6998b26e2cb06f5b5 (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.py37
-rw-r--r--leekspin/generator.py44
-rw-r--r--leekspin/util.py4
-rwxr-xr-xscripts/leekspin3
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())