Exemplo n.º 1
0
 def __init__(self,
              string=None,
              fname=None,
              validatedDigests=None,
              _keepServerContents=0):
     """DOCDOC
        raises ConfigError.
     """
     if string:
         contents = string
     else:
         try:
             contents = readPossiblyGzippedFile(fname)
         except (IOError, zlib.error), e:
             raise ConfigError("Couldn't decompress %s: %s" % (fname, e))
Exemplo n.º 2
0
    def __init__(self, string=None, fname=None, validatedDigests=None):
        """Create a new ServerDirectory object, either from a literal <string>
           (if specified) or a filename [possibly gzipped].

           If validatedDigests is provided, it must be a dict whose keys
           are the digests of already-validated descriptors.  Any descriptor
           whose (calculated) digest matches doesn't need to be validated
           again.
        """
        if string:
            contents = string
        else:
            try:
                contents = readPossiblyGzippedFile(fname)
            except (IOError, zlib.error), e:
                raise ConfigError("Couldn't decompress %s: %s" % (fname, e))
Exemplo n.º 3
0
def parseDirectory(fname, validatedDigests=None):
    """DOCDOC"""
    try:
        s = readPossiblyGzippedFile(fname)
    except (IOError, zlib.error), e:
        raise ConfigError("Couldn't decompress %s: %s" % (fname, e))
Exemplo n.º 4
0
    def validate(self, lines, contents):
        ####
        # Check 'Server' section.
        server = self['Server']
        if server['Descriptor-Version'] != '0.2':
            raise ConfigError("Unrecognized descriptor version %r" %
                              server['Descriptor-Version'])

        ####
        # Check the digest of file
        digest = getServerInfoDigest(contents)
        if digest != server['Digest']:
            raise ConfigError("Invalid digest")

        # Have we already validated this particular ServerInfo?
        if (self._validatedDigests and self._validatedDigests.has_key(digest)):
            self._isValidated = 1
            return

        # Validate the rest of the server section.
        identityKey = server['Identity']
        identityBytes = identityKey.get_modulus_bytes()
        if not (MIN_IDENTITY_BYTES <= identityBytes <= MAX_IDENTITY_BYTES):
            raise ConfigError("Invalid length on identity key")
        if server['Published'] > time.time() + 600:
            raise ConfigError("Server published in the future")
        if server['Valid-Until'] <= server['Valid-After']:
            raise ConfigError("Server is never valid")
        if server['Contact'] and len(server['Contact']) > MAX_CONTACT:
            raise ConfigError("Contact too long")
        if server['Comments'] and len(server['Comments']) > MAX_COMMENTS:
            raise ConfigError("Comments too long")
        if server['Contact-Fingerprint'] and \
               len(server['Contact-Fingerprint']) > MAX_FINGERPRINT:
            raise ConfigError("Contact-Fingerprint too long")

        packetKeyBytes = server['Packet-Key'].get_modulus_bytes()
        if packetKeyBytes != PACKET_KEY_BYTES:
            raise ConfigError("Invalid length on packet key")

        ####
        # Check signature
        try:
            signedDigest = pk_check_signature(server['Signature'], identityKey)
        except CryptoError:
            raise ConfigError("Invalid signature")

        if digest != signedDigest:
            raise ConfigError("Signed digest is incorrect")

        ## Incoming/MMTP section
        inMMTP = self['Incoming/MMTP']
        if inMMTP:
            if inMMTP['Version'] != '0.1':
                raise ConfigError("Unrecognized MMTP descriptor version %s" %
                                  inMMTP['Version'])

        ## Outgoing/MMTP section
        outMMTP = self['Outgoing/MMTP']
        if outMMTP:
            if outMMTP['Version'] != '0.1':
                raise ConfigError("Unrecognized MMTP descriptor version %s" %
                                  inMMTP['Version'])

        # FFFF When a better client module system exists, check the
        # FFFF module descriptors.

        self._isValidated = 1
Exemplo n.º 5
0
    def validate(self, lines, contents):
        def _haveEntry(self, section, ent):
            entries = self._sectionEntries
            return len([e for e in entries[section] if e[0] == ent]) != 0

        # Preemptively configure the log before validation, so we don't
        # write to the terminal if we've been asked not to.
        if not self['Server'].get("EchoMessages", 0):
            LOG.handlers = []
            # ???? This can't be the best way to do this.

        # Now, validate the host section.
        mixminion.Config._validateHostSection(self['Host'])
        # Server section
        server = self['Server']
        bits = server['IdentityKeyBits']
        if not (2048 <= bits <= 4096):
            raise ConfigError("IdentityKeyBits must be between 2048 and 4096")
        if server['EncryptIdentityKey']:
            LOG.warn("Identity key encryption not yet implemented")
        if server['EncryptPrivateKey']:
            LOG.warn("Encrypted private keys not yet implemented")
        if server['PublicKeyLifetime'].getSeconds() < 24 * 60 * 60:
            raise ConfigError("PublicKeyLifetime must be at least 1 day.")
        if server['PublicKeyOverlap'].getSeconds() < 6 * 60 * 60:
            raise ConfigError("PublicKeyOverlap must be >= 6 hours")
        if server['PublicKeyOverlap'].getSeconds() > 72 * 60 * 60:
            raise ConfigError("PublicKeyOverlap must be <= 72 hours")

        if _haveEntry(self, 'Server', 'Mode'):
            LOG.warn("Mode specification is not yet supported.")

        mixInterval = server['MixInterval'].getSeconds()
        if mixInterval < 30 * 60:
            LOG.warn("Dangerously low MixInterval")
        if server['MixAlgorithm'] == 'TimedMixPool':
            if _haveEntry(self, 'Server', 'MixPoolRate'):
                LOG.warn("Option MixPoolRate is not used for Timed mixing.")
            if _haveEntry(self, 'Server', 'MixPoolMinSize'):
                LOG.warn("Option MixPoolMinSize is not used for Timed mixing.")
        else:
            rate = server['MixPoolRate']
            minSize = server['MixPoolMinSize']
            if rate < 0.05:
                LOG.warn("Unusually low MixPoolRate %s", rate)
            if minSize < 0:
                raise ConfigError("MixPoolMinSize %s must be nonnegative.")

        if not self['Incoming/MMTP'].get('Enabled'):
            LOG.warn("Disabling incoming MMTP is not yet supported.")
        if [
                e for e in self._sectionEntries['Incoming/MMTP']
                if e[0] in ('Allow', 'Deny')
        ]:
            LOG.warn("Allow/deny are not yet supported")

        if not self['Outgoing/MMTP'].get('Enabled'):
            LOG.warn("Disabling outgoing MMTP is not yet supported.")
        if [
                e for e in self._sectionEntries['Outgoing/MMTP']
                if e[0] in ('Allow', 'Deny')
        ]:
            LOG.warn("Allow/deny are not yet supported")
        mc = self['Outgoing/MMTP'].get('MaxConnections')
        if mc is not None and mc < 1:
            raise ConfigError("MaxConnections must be at least 1.")
        bw = self['Outgoing/MMTP'].get('MaxBandwidth')
        if bw is not None and bw < 4096:
            #XXXX007 this is completely arbitrary. :P
            raise ConfigError("MaxBandwidth must be at least 4KB.")

        self.validateRetrySchedule("Outgoing/MMTP")

        self.moduleManager.validate(self, lines, contents)