Skip to content
Snippets Groups Projects
Commit 3bc9c660 authored by Philipp Winter's avatar Philipp Winter
Browse files

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>
parent bad0bed1
Branches
Tags
No related merge requests found
......@@ -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,19 +51,22 @@ 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'
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()
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))
......
......@@ -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)
......@@ -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()
......
......@@ -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())
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment