Commit 7c3c5198 authored by Philipp Winter's avatar Philipp Winter
Browse files

Generate a password if the bridge operator didn't.

Generally, we require a password (the UniformDH shared secret) which is set by
the bridge operator using "ServerTransportOptions" in Tor's torrc.  Since some
bridge operators won't bother taking care of that, we want a fallback mechanism
which silently generates and publishes a password if ServerTransportOptions is
not used.  We (ab)use obfsproxy's get_public_server_options() which is meant to
sanitise parameters.  We, however, use it to add the password parameter if it's
not there.
parent 5e3fb32d
Loading
Loading
Loading
Loading
+44 −6
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ import obfsproxy.common.log as logging

import random
import base64
import yaml

import probdist
import mycrypto
@@ -101,6 +102,10 @@ class ScrambleSuitTransport( base.BaseTransport ):

    @classmethod
    def setup( cls, transportConfig ):
        """
        Called once when obfsproxy starts.
        """

        util.setStateLocation(transportConfig.getStateLocation())

        cls.weAreClient = transportConfig.weAreClient
@@ -111,14 +116,47 @@ class ScrambleSuitTransport( base.BaseTransport ):
        # shared secret from the server transport options.
        if cls.weAreServer and not cls.weAreExternal:
            cfg  = transportConfig.getServerTransportOptions()
            if "password" not in cfg:
                raise base.PluggableTransportError(
                    "Couldn't find 'password' in server transport options")

            if cfg and "password" in cfg:
                cls.uniformDHSecret = base64.b32decode(util.sanitiseBase32(
                        cfg["password"]))
                cls.uniformDHSecret = cls.uniformDHSecret.strip()

    @classmethod
    def get_public_server_options( cls, transportOptions ):
        """
        Generate and return a password if it's not in Tor's torrc.

        This method implements a fallback mechanism if the bridge operator did
        not specify `ServerTransportOptions'.  In that case, we silently
        generate and store a password.
        """

        log.debug("Tor's transport options: %s" % str(transportOptions))

        if not "password" in transportOptions:
            log.info("No password found in transport options.  " \
                     "Taking care of that.")

            # First, try to load the password from file.
            rawPassword = util.readFromFile(const.STATE_LOCATION +
                                            const.SERVER_PASSWORD_FILE)
            if rawPassword:
                password = yaml.safe_load(rawPassword)
                log.debug("Loaded password from file.")
            else:
                # ...if that fails, generate a new one and store it.
                log.debug("Generating new password and storing it in `%s'." %
                          (const.STATE_LOCATION + const.SERVER_PASSWORD_FILE))

                password = mycrypto.strongRandom(const.SHARED_SECRET_LENGTH)
                util.writeToFile(yaml.dump(password), const.STATE_LOCATION +
                                 const.SERVER_PASSWORD_FILE)

            transportOptions = {"password": base64.b32encode(password)}
            cls.uniformDHSecret = password

        return transportOptions

    def deriveSecrets( self, masterKey ):
        """
        Derive various session keys from the given `masterKey'.