示例#1
0
def getDirectorySignature(directory, pkey):
    digest = mixminion.ServerInfo._getMultisignedDirectoryDigest(directory)
    signature = pk_sign(digest, pkey)
    encKey = formatBase64(pk_encode_public_key(pkey))
    encSig = formatBase64(signature)
    encDigest = formatBase64(digest)
    return ("[Signed-Directory]\nDirectory-Identity: %s\n"
            "Directory-Digest: %s\nDirectory-Signature: %s\n")%(
        encKey,encDigest,encSig)
示例#2
0
def getDirectorySignature(directory, pkey):
    digest = mixminion.ServerInfo._getMultisignedDirectoryDigest(directory)
    signature = pk_sign(digest, pkey)
    encKey = formatBase64(pk_encode_public_key(pkey))
    encSig = formatBase64(signature)
    encDigest = formatBase64(digest)
    return ("[Signed-Directory]\nDirectory-Identity: %s\n"
            "Directory-Digest: %s\nDirectory-Signature: %s\n")%(
        encKey,encDigest,encSig)
示例#3
0
def buildReplyBlock(path, exitType, exitInfo, userKey, expiryTime=None, secretRNG=None):
    """Construct a 'state-carrying' reply block that does not require the
       reply-message recipient to remember a list of secrets.
       Instead, all secrets are generated from an AES counter-mode
       stream, and the seed for the stream is stored in the 'tag'
       field of the final block's routing info.   (See the spec for more
       info).

               path: a list of ServerInfo objects
               exitType,exitInfo: The address to deliver the final message.
               userKey: a string used to encrypt the seed.

       NOTE: We used to allow another kind of 'non-state-carrying' reply
       block that stored its secrets on disk, and used an arbitrary tag to
       determine which set of secrets to use.
       """
    if secretRNG is None:
        secretRNG = Crypto.getCommonPRNG()

    # We need to pick the seed to generate our keys.  To make the decoding
    # step a little faster, we find a seed such that H(seed|userKey|"Validate")
    # ends with 0.  This way, we can detect whether we really have a reply
    # message with 99.6% probability.  (Otherwise, we'd need to repeatedly
    # lioness-decrypt the payload in order to see whether the message was
    # a reply.)
    while 1:
        seed = _getRandomTag(secretRNG)
        if Crypto.sha1(seed + userKey + "Validate")[-1] == "\x00":
            break

    prng = Crypto.AESCounterPRNG(Crypto.sha1(seed + userKey + "Generate")[:16])

    replyBlock, secrets, tag = _buildReplyBlockImpl(path, exitType, exitInfo, expiryTime, prng, seed)
    STATUS.log("GENERATED_SURB", formatBase64(tag))
    return replyBlock
示例#4
0
def _getDigestImpl(info, regex, digestField=None, sigField=None, rsa=None):
    """Helper method.  Calculates the correct digest of a server descriptor
       or directory
       (as provided in a string).  If rsa is provided, signs the digest and
       creates a new descriptor.  Otherwise just returns the digest.

       info -- the string to digest or sign.
       regex -- a compiled regex that matches the line containing the digest
          and the line containing the signature.
       digestField -- If not signing, None.  Otherwise, the name of the digest
          field.
       sigField -- If not signing, None.  Otherwise, the name of the signature
          field.
       rsa -- our public key
       """
    info = _cleanForDigest(info)

    def replaceFn(m):
        s = m.group(0)
        return s[:s.index(':') + 1]

    info = regex.sub(replaceFn, info, 2)
    digest = sha1(info)

    if rsa is None:
        return digest

    signature = pk_sign(digest, rsa)
    digest = formatBase64(digest)
    signature = formatBase64(signature)

    def replaceFn2(s,
                   digest=digest,
                   signature=signature,
                   digestField=digestField,
                   sigField=sigField):
        if s.group(0).startswith(digestField):
            return "%s: %s" % (digestField, digest)
        else:
            assert s.group(0).startswith(sigField)
            return "%s: %s" % (sigField, signature)

    info = regex.sub(replaceFn2, info, 2)
    return info
示例#5
0
def _getDigestImpl(info, regex, digestField=None, sigField=None, rsa=None):
    """Helper method.  Calculates the correct digest of a server descriptor
       or directory
       (as provided in a string).  If rsa is provided, signs the digest and
       creates a new descriptor.  Otherwise just returns the digest.

       info -- the string to digest or sign.
       regex -- a compiled regex that matches the line containing the digest
          and the line containing the signature.
       digestField -- If not signing, None.  Otherwise, the name of the digest
          field.
       sigField -- If not signing, None.  Otherwise, the name of the signature
          field.
       rsa -- our public key
       """
    info = _cleanForDigest(info)
    def replaceFn(m):
        s = m.group(0)
        return s[:s.index(':')+1]
    info = regex.sub(replaceFn, info, 2)
    digest = sha1(info)

    if rsa is None:
        return digest

    signature = pk_sign(digest,rsa)
    digest = formatBase64(digest)
    signature = formatBase64(signature)
    def replaceFn2(s, digest=digest, signature=signature,
                   digestField=digestField, sigField=sigField):
        if s.group(0).startswith(digestField):
            return "%s: %s" % (digestField, digest)
        else:
            assert s.group(0).startswith(sigField)
            return "%s: %s" % (sigField, signature)

    info = regex.sub(replaceFn2, info, 2)
    return info
示例#6
0
 def readPendingServers(self):
     """Scan all of the servers waiting in the incoming directory.  If
        any are bad, remove them.  Return a list of
           (filename, ServerInfo, server descriptor, ID Fingerprint)
        tuples for all the servers in the directory.
        """
     res = []
     for fname in os.listdir(self.incomingDir):
         path = os.path.join(self.incomingDir,fname)
         try:
             text, server = _readServer(path)
         except MixError, e:
             os.unlink(path)
             LOG.warn(
                 "Removed a bad server descriptor %s from incoming dir: %s",
                 fname, e)
             continue
         fp = formatBase64(getIDFingerprint(server))
         res.append((fname, server, text, fp))
示例#7
0
def buildReplyBlock(path, exitType, exitInfo, userKey,
                    expiryTime=None, secretRNG=None):
    """Construct a 'state-carrying' reply block that does not require the
       reply-message recipient to remember a list of secrets.
       Instead, all secrets are generated from an AES counter-mode
       stream, and the seed for the stream is stored in the 'tag'
       field of the final block's routing info.   (See the spec for more
       info).

               path: a list of ServerInfo objects
               exitType,exitInfo: The address to deliver the final message.
               userKey: a string used to encrypt the seed.

       NOTE: We used to allow another kind of 'non-state-carrying' reply
       block that stored its secrets on disk, and used an arbitrary tag to
       determine which set of secrets to use.
       """
    if secretRNG is None:
        secretRNG = Crypto.getCommonPRNG()

    # We need to pick the seed to generate our keys.  To make the decoding
    # step a little faster, we find a seed such that H(seed|userKey|"Validate")
    # ends with 0.  This way, we can detect whether we really have a reply
    # message with 99.6% probability.  (Otherwise, we'd need to repeatedly
    # lioness-decrypt the payload in order to see whether the message was
    # a reply.)
    while 1:
        seed = _getRandomTag(secretRNG)
        if Crypto.sha1(seed+userKey+"Validate")[-1] == '\x00':
            break

    prng = Crypto.AESCounterPRNG(Crypto.sha1(seed+userKey+"Generate")[:16])

    replyBlock, secrets, tag = _buildReplyBlockImpl(path, exitType, exitInfo,
                                                    expiryTime, prng, seed)
    STATUS.log("GENERATED_SURB", formatBase64(tag))
    return replyBlock
示例#8
0
 def _getKey(self, digest):
     k = formatBase64(digest).replace("/","-").replace("=","")
     assert len(k) == self.KEY_LENGTH
     return k
示例#9
0
 def __str__(self):
     return "%s:%s:%s" % (self.hostname, self.port,
                          formatBase64(self.keyinfo))
示例#10
0
    # Identities go in if they have a consistant nickname, and most voters
    # include them.
    identNickname = {}
    badIdents = {}
    identsByVoter = []
    digestsByIdent = {}
    for digestList in serversByDir.values():
        idents = {}
        for digest in digestList:
            s = serverMap[digest]
            n = s.getNickname()
            ident = s.getIdentityDigest()
            try:
                if n != identNickname[ident]:
                    log.warn("Multiple nicknames for %s",formatBase64(ident))
                    badIdents[ident] = 1
            except KeyError:
                identNickname[ident]=n

            idents[ident] = 1
            digestsByIdent.setdefault(ident,{})[digest]=1
        identsByVoter.append(idents.keys())

    includedIdentities = [ i for i in commonElements(identsByVoter, threshold)
                           if not badIdents.has_key(i) ]

    # okay -- for each identity, what servers do we include?
    includedServers = []
    for ident in includedIdentities:
        servers = [ serverMap[digest] for digest in digestsByIdent[ident].keys()]
示例#11
0
    def generateDirectory(self,
                          startAt,
                          endAt,
                          extraTime,
                          identityKey,
                          publicationTime=None,
                          badServers=(),
                          excludeServers=()):
        """Generate and sign a new directory, to be effective from <startAt>
           through <endAt>.  It includes all servers that are valid at
           any time between <startAt> and <endAt>+<extraTime>.  The directory
           is signed with <identityKey>.

           Any servers whose nicknames appear in 'badServers' are marked as
           not recommended; any servers whose nicknames appear in
           'excludeServers' are left off the directory entirely.
        """
        try:
            self._lock()
            self.clean()
            if publicationTime is None:
                publicationTime = time.time()
            if previousMidnight(startAt) >= previousMidnight(endAt):
                raise MixError("Validity range does not contain a full day.")

            excludeServers = [nickname.lower() for nickname in excludeServers]

            # First, sort all servers by nickname.
            includedByNickname = {}
            for fn, s in self.servers.items():
                nickname = s.getNickname().lower()
                if nickname in excludeServers: continue
                includedByNickname.setdefault(nickname, []).append((s, fn))

            # Second, find all servers that are valid for part of the period,
            # and that aren't superseded for the whole period.
            timeRange = IntervalSet([(previousMidnight(startAt),
                                      endAt + extraTime)])

            for nickname, ss in includedByNickname.items():
                # We prefer the most-recently-published descriptor.  If two
                # are published at the same time, we prefer the one that
                # expires last.
                ss = [(s['Server']['Published'], s['Server']['Valid-Until'], s,
                       fn) for s, fn in ss]
                ss.sort()
                ss.reverse()
                uncovered = timeRange.copy()
                included = []
                for _, _, s, fn in ss:
                    valid = s.getIntervalSet()
                    if (uncovered * valid):
                        included.append((s, fn))
                        uncovered -= valid
                includedByNickname[nickname] = included

            # Now sort the remaining servers by nickname, then by valid-after.
            included = []
            for ss in includedByNickname.values():
                for s, fn in ss:
                    nickname = s.getNickname()
                    validAfter = s['Server']['Valid-After']
                    included.append((nickname, validAfter, fn))
            included.sort()

            # FFFF We should probably not do all of this in RAM, but
            # FFFF what the hey.  It will only matter if we have many, many
            # FFFF servers in the system.
            contents = []
            for _, _, fn in included:
                txt = readFile(os.path.join(self.serverDir, fn))
                contents.append(txt)

            goodServers = [n for n, _, _ in included if n not in badServers]
            g = {}
            for n in goodServers:
                g[n] = 1
            goodServers = g.keys()
            goodServers.sort()
            goodServers = ", ".join(goodServers)

            clientVersions = self.config['Directory']['ClientVersions']
            serverVersions = self.config['Directory']['ServerVersions']

            #FFFF Support for multiple signatures
            header = """\
            [Directory]
            Version: 0.2
            Published: %s
            Valid-After: %s
            Valid-Until: %s
            Recommended-Servers: %s
            [Signature]
            DirectoryIdentity: %s
            DirectoryDigest:
            DirectorySignature:
            [Recommended-Software]
            MixminionClient: %s
            MixminionServer: %s
            """ % (formatTime(publicationTime), formatDate(startAt),
                   formatDate(endAt), goodServers,
                   formatBase64(pk_encode_public_key(identityKey)),
                   ", ".join(clientVersions), ", ".join(serverVersions))

            directory = header + "".join(contents)
            directory = _getDirectoryDigestImpl(directory, identityKey)

            # Make sure that the directory checks out
            # FFFF remove this once we are _very_ confident.
            if 1:
                parsed = ServerDirectory(string=directory)
                includedDigests = {}
                for _, _, fn in included:
                    includedDigests[self.servers[fn]['Server']['Digest']] = 1
                foundDigests = {}
                for s in parsed.getAllServers():
                    foundDigests[s['Server']['Digest']] = 1
                assert foundDigests == includedDigests

            writeFile(os.path.join(self.baseDir, "directory"),
                      directory,
                      mode=0644)

            f, _ = openUnique(
                os.path.join(self.dirArchiveDir, "dir-" + formatFnameTime()))
            f.write(directory)
            f.close()
        finally:
            self._unlock()
示例#12
0
 def _getKey(self, digest):
     k = formatBase64(digest).replace("/", "-").replace("=", "")
     assert len(k) == self.KEY_LENGTH
     return k
示例#13
0
def generateServerDescriptorAndKeys(config, identityKey, keydir, keyname,
                                    hashdir, validAt=None, now=None,
                                    useServerKeys=0, validUntil=None):
    """Generate and sign a new server descriptor, and generate all the keys to
       go with it.

          config -- Our ServerConfig object.
          identityKey -- This server's private identity key
          keydir -- The root directory for storing key sets.
          keyname -- The name of this new key set within keydir
          hashdir -- The root directory for storing hash logs.
          validAt -- The starting time (in seconds) for this key's lifetime.
          useServerKeys -- If true, try to read an existing keyset from
               (keydir,keyname,hashdir) rather than generating a fresh one.
          validUntil -- Time at which the generated descriptor should
               expire.
    """
    if useServerKeys:
        serverKeys = ServerKeyset(keydir, keyname, hashdir)
        serverKeys.load()
        packetKey = serverKeys.packetKey
    else:
        # First, we generate both of our short-term keys...
        packetKey = mixminion.Crypto.pk_generate(PACKET_KEY_BYTES*8)

        # ...and save them to disk, setting up our directory structure while
        # we're at it.
        serverKeys = ServerKeyset(keydir, keyname, hashdir)
        serverKeys.packetKey = packetKey
        serverKeys.save()

    # FFFF unused
    # allowIncoming = config['Incoming/MMTP'].get('Enabled', 0)

    # Now, we pull all the information we need from our configuration.
    nickname = config['Server']['Nickname']
    contact = config['Server']['Contact-Email']
    fingerprint = config['Server']['Contact-Fingerprint']
    comments = config['Server']['Comments']
    if not now:
        now = time.time()
    if not validAt:
        validAt = now

    insecurities = config.getInsecurities()
    if insecurities:
        secure = "no"
    else:
        secure = "yes"

    # Calculate descriptor and X509 certificate lifetimes.
    # (Round validAt to previous midnight.)
    validAt = mixminion.Common.previousMidnight(validAt+30)
    if not validUntil:
        keyLifetime = config['Server']['PublicKeyLifetime'].getSeconds()
        validUntil = previousMidnight(validAt + keyLifetime + 30)

    mmtpProtocolsIn = mixminion.server.MMTPServer.MMTPServerConnection \
                      .PROTOCOL_VERSIONS[:]
    mmtpProtocolsOut = mixminion.server.MMTPServer.MMTPClientConnection \
                       .PROTOCOL_VERSIONS[:]
    mmtpProtocolsIn.sort()
    mmtpProtocolsOut.sort()
    mmtpProtocolsIn = ",".join(mmtpProtocolsIn)
    mmtpProtocolsOut = ",".join(mmtpProtocolsOut)


    #XXXX009 remove: hasn't been checked since 007 or used since 005.
    identityKeyID = formatBase64(
                      mixminion.Crypto.sha1(
                          mixminion.Crypto.pk_encode_public_key(identityKey)))

    fields = {
        # XXXX009 remove: hasn't been checked since 007.
        "IP": config['Incoming/MMTP'].get('IP', "0.0.0.0"),
        "Hostname": config['Incoming/MMTP'].get('Hostname', None),
        "Port": config['Incoming/MMTP'].get('Port', 0),
        "Nickname": nickname,
        "Identity":
           formatBase64(mixminion.Crypto.pk_encode_public_key(identityKey)),
        "Published": formatTime(now),
        "ValidAfter": formatDate(validAt),
        "ValidUntil": formatDate(validUntil),
        "PacketKey":
           formatBase64(mixminion.Crypto.pk_encode_public_key(packetKey)),
        "KeyID": identityKeyID,
        "MMTPProtocolsIn" : mmtpProtocolsIn,
        "MMTPProtocolsOut" : mmtpProtocolsOut,
        "PacketVersion" : mixminion.Packet.PACKET_VERSION,
        "mm_version" : mixminion.__version__,
        "Secure" : secure,
        "Contact" : contact,
        }

    # If we don't know our IP address, try to guess
    if fields['IP'] == '0.0.0.0': #XXXX008 remove; not needed since 005.
        try:
            fields['IP'] = _guessLocalIP()
            LOG.warn("No IP configured; guessing %s",fields['IP'])
        except IPGuessError, e:
            LOG.error("Can't guess IP: %s", str(e))
            raise UIError("Can't guess IP: %s" % str(e))
示例#14
0
 def getAsciiTag(self):
     """Return a base64-representation of this message's decoding handle."""
     return formatBase64(self.tag)
示例#15
0
 def __str__(self):
     return "IP:%s:%s:%s"%(self.ip,self.port,formatBase64(self.keyinfo))
示例#16
0
 def __str__(self):
     return "%s:%s:%s"%(self.hostname,self.port,formatBase64(self.keyinfo))
示例#17
0
    def generateDirectory(self,
                          startAt, endAt, extraTime,
                          identityKey,
                          publicationTime=None,
                          badServers=(),
                          excludeServers=()):
        """Generate and sign a new directory, to be effective from <startAt>
           through <endAt>.  It includes all servers that are valid at
           any time between <startAt> and <endAt>+<extraTime>.  The directory
           is signed with <identityKey>.

           Any servers whose nicknames appear in 'badServers' are marked as
           not recommended; any servers whose nicknames appear in
           'excludeServers' are left off the directory entirely.
        """
        try:
            self._lock()
            self.clean()
            if publicationTime is None:
                publicationTime = time.time()
            if previousMidnight(startAt) >= previousMidnight(endAt):
                raise MixError("Validity range does not contain a full day.")

            excludeServers = [ nickname.lower() for nickname in excludeServers]

            # First, sort all servers by nickname.
            includedByNickname =  {}
            for fn, s in self.servers.items():
                nickname = s.getNickname().lower()
                if nickname in excludeServers: continue
                includedByNickname.setdefault(nickname, []).append((s, fn))

            # Second, find all servers that are valid for part of the period,
            # and that aren't superseded for the whole period.
            timeRange = IntervalSet([(previousMidnight(startAt),
                                      endAt+extraTime)])

            for nickname, ss in includedByNickname.items():
                # We prefer the most-recently-published descriptor.  If two
                # are published at the same time, we prefer the one that
                # expires last.
                ss = [ (s['Server']['Published'],
                        s['Server']['Valid-Until'],
                        s, fn) for s,fn in ss]
                ss.sort()
                ss.reverse()
                uncovered = timeRange.copy()
                included = []
                for _, _, s, fn in ss:
                    valid = s.getIntervalSet()
                    if (uncovered * valid):
                        included.append((s, fn))
                        uncovered -= valid
                includedByNickname[nickname] = included

            # Now sort the remaining servers by nickname, then by valid-after.
            included = []
            for ss in includedByNickname.values():
                for s,fn in ss:
                    nickname = s.getNickname()
                    validAfter = s['Server']['Valid-After']
                    included.append((nickname, validAfter, fn))
            included.sort()

            # FFFF We should probably not do all of this in RAM, but
            # FFFF what the hey.  It will only matter if we have many, many
            # FFFF servers in the system.
            contents = [ ]
            for _, _, fn in included:
                txt = readFile(os.path.join(self.serverDir, fn))
                contents.append(txt)

            goodServers = [n for n,_,_ in included if n not in badServers]
            g = {}
            for n in goodServers: g[n]=1
            goodServers = g.keys()
            goodServers.sort()
            goodServers = ", ".join(goodServers)

            clientVersions = self.config['Directory']['ClientVersions']
            serverVersions = self.config['Directory']['ServerVersions']

            #FFFF Support for multiple signatures
            header = """\
            [Directory]
            Version: 0.2
            Published: %s
            Valid-After: %s
            Valid-Until: %s
            Recommended-Servers: %s
            [Signature]
            DirectoryIdentity: %s
            DirectoryDigest:
            DirectorySignature:
            [Recommended-Software]
            MixminionClient: %s
            MixminionServer: %s
            """ % (formatTime(publicationTime),
                   formatDate(startAt),
                   formatDate(endAt),
                   goodServers,
                   formatBase64(pk_encode_public_key(identityKey)),
                   ", ".join(clientVersions),
                   ", ".join(serverVersions))

            directory = header+"".join(contents)
            directory = _getDirectoryDigestImpl(directory, identityKey)

            # Make sure that the directory checks out
            # FFFF remove this once we are _very_ confident.
            if 1:
                parsed = ServerDirectory(string=directory)
                includedDigests = {}
                for _, _, fn in included:
                    includedDigests[self.servers[fn]['Server']['Digest']] = 1
                foundDigests = {}
                for s in parsed.getAllServers():
                    foundDigests[s['Server']['Digest']] = 1
                assert foundDigests == includedDigests

            writeFile(os.path.join(self.baseDir, "directory"),
                      directory,
                      mode=0644)

            f, _ = openUnique(os.path.join(self.dirArchiveDir,
                                            "dir-"+formatFnameTime()))
            f.write(directory)
            f.close()
        finally:
            self._unlock()
示例#18
0
def generateServerDescriptorAndKeys(config,
                                    identityKey,
                                    keydir,
                                    keyname,
                                    hashdir,
                                    validAt=None,
                                    now=None,
                                    useServerKeys=0,
                                    validUntil=None):
    """Generate and sign a new server descriptor, and generate all the keys to
       go with it.

          config -- Our ServerConfig object.
          identityKey -- This server's private identity key
          keydir -- The root directory for storing key sets.
          keyname -- The name of this new key set within keydir
          hashdir -- The root directory for storing hash logs.
          validAt -- The starting time (in seconds) for this key's lifetime.
          useServerKeys -- If true, try to read an existing keyset from
               (keydir,keyname,hashdir) rather than generating a fresh one.
          validUntil -- Time at which the generated descriptor should
               expire.
    """
    if useServerKeys:
        serverKeys = ServerKeyset(keydir, keyname, hashdir)
        serverKeys.load()
        packetKey = serverKeys.packetKey
    else:
        # First, we generate both of our short-term keys...
        packetKey = mixminion.Crypto.pk_generate(PACKET_KEY_BYTES * 8)

        # ...and save them to disk, setting up our directory structure while
        # we're at it.
        serverKeys = ServerKeyset(keydir, keyname, hashdir)
        serverKeys.packetKey = packetKey
        serverKeys.save()

    # FFFF unused
    # allowIncoming = config['Incoming/MMTP'].get('Enabled', 0)

    # Now, we pull all the information we need from our configuration.
    nickname = config['Server']['Nickname']
    contact = config['Server']['Contact-Email']
    fingerprint = config['Server']['Contact-Fingerprint']
    comments = config['Server']['Comments']
    if not now:
        now = time.time()
    if not validAt:
        validAt = now

    insecurities = config.getInsecurities()
    if insecurities:
        secure = "no"
    else:
        secure = "yes"

    # Calculate descriptor and X509 certificate lifetimes.
    # (Round validAt to previous midnight.)
    validAt = mixminion.Common.previousMidnight(validAt + 30)
    if not validUntil:
        keyLifetime = config['Server']['PublicKeyLifetime'].getSeconds()
        validUntil = previousMidnight(validAt + keyLifetime + 30)

    mmtpProtocolsIn = mixminion.server.MMTPServer.MMTPServerConnection \
                      .PROTOCOL_VERSIONS[:]
    mmtpProtocolsOut = mixminion.server.MMTPServer.MMTPClientConnection \
                       .PROTOCOL_VERSIONS[:]
    mmtpProtocolsIn.sort()
    mmtpProtocolsOut.sort()
    mmtpProtocolsIn = ",".join(mmtpProtocolsIn)
    mmtpProtocolsOut = ",".join(mmtpProtocolsOut)

    #XXXX009 remove: hasn't been checked since 007 or used since 005.
    identityKeyID = formatBase64(
        mixminion.Crypto.sha1(
            mixminion.Crypto.pk_encode_public_key(identityKey)))

    fields = {
        # XXXX009 remove: hasn't been checked since 007.
        "IP":
        config['Incoming/MMTP'].get('IP', "0.0.0.0"),
        "Hostname":
        config['Incoming/MMTP'].get('Hostname', None),
        "Port":
        config['Incoming/MMTP'].get('Port', 0),
        "Nickname":
        nickname,
        "Identity":
        formatBase64(mixminion.Crypto.pk_encode_public_key(identityKey)),
        "Published":
        formatTime(now),
        "ValidAfter":
        formatDate(validAt),
        "ValidUntil":
        formatDate(validUntil),
        "PacketKey":
        formatBase64(mixminion.Crypto.pk_encode_public_key(packetKey)),
        "KeyID":
        identityKeyID,
        "MMTPProtocolsIn":
        mmtpProtocolsIn,
        "MMTPProtocolsOut":
        mmtpProtocolsOut,
        "PacketVersion":
        mixminion.Packet.PACKET_VERSION,
        "mm_version":
        mixminion.__version__,
        "Secure":
        secure,
        "Contact":
        contact,
    }

    # If we don't know our IP address, try to guess
    if fields['IP'] == '0.0.0.0':  #XXXX008 remove; not needed since 005.
        try:
            fields['IP'] = _guessLocalIP()
            LOG.warn("No IP configured; guessing %s", fields['IP'])
        except IPGuessError, e:
            LOG.error("Can't guess IP: %s", str(e))
            raise UIError("Can't guess IP: %s" % str(e))
示例#19
0
    # Identities go in if they have a consistant nickname, and most voters
    # include them.
    identNickname = {}
    badIdents = {}
    identsByVoter = []
    digestsByIdent = {}
    for digestList in serversByDir.values():
        idents = {}
        for digest in digestList:
            s = serverMap[digest]
            n = s.getNickname()
            ident = s.getIdentityDigest()
            try:
                if n != identNickname[ident]:
                    LOG.warn("Multiple nicknames for %s",formatBase64(ident))
                    badIdents[ident] = 1
            except KeyError:
                identNickname[ident]=n

            idents[ident] = 1
            digestsByIdent.setdefault(ident,{})[digest]=1
        identsByVoter.append(idents.keys())

    includedIdentities = [ i for i in commonElements(identsByVoter, threshold)
                           if not badIdents.has_key(i) ]

    # okay -- for each identity, what servers do we include?
    includedServers = []
    for ident in includedIdentities:
        servers = [ serverMap[digest] for digest in digestsByIdent[ident].keys()]
示例#20
0
def checkVoteDirectory(voters, validAfter, directory):
    # my (sorted, uniqd) list of voters, SignedDirectory instance, URL

    # Is there a single signature?
    sigs = directory.getSignatures()
    if len(sigs) == 0:
        raise BadVote("No signatures")
    elif len(sigs) > 1:
        raise BadVote("Too many signatures")
    sig = sigs[0]

    ident = sig['Signed-Directory']['Directory-Identity']
    keyid = mixminion.Crypto.pk_fingerprint(ident)

    # Do we recognize the signing key?
    for k,_ in voters:
        if k == keyid:
            break
    else:
        raise BadVote("Unknown identity key (%s)"%keyid)

    # Is the signature valid?
    if not sig.checkSignature():
        raise BadVote("Invalid signature")

    # Is the version valid?
    if (directory['Directory-Info']['Version'] !=
        mixminion.ServerInfo._DirectoryInfo.VERSION):
        raise BadVote("Unrecognized version (%s)")

    # Is the directory marked as a vote?
    if directory['Directory-Info']['Status'] != 'vote':
        raise BadVote("Not marked as vote")

    # Do we agree about the voters?
    if not _listIsSorted(directory.dirInfo.voters):
        raise BadVote("Voters not sorted")

    vkeys = {}
    for k,u in directory.dirInfo.voters:
        vkeys[k]=u
    mykeys = {}
    for k,u in voters: mykeys[k]=u

    for k,u in directory.dirInfo.voters:
        try:
            if mykeys[k] != u:
                raise BadVote("Mismatched URL for voter %s (%s vs %s)"%(
                    formatBase64(k), u, mykeys[k]))
        except KeyError:
            raise BadVote("Unkown voter %s at %s"%(k,u))
    for k, u in voters:
        if not vkeys.has_key(k):
            raise BadVote("Missing voter %s at %s"%(k,u))

    assert directory.dirInfo.voters == voters

    # Are the dates right?
    va = directory['Directory-Info']['Valid-After']
    vu = directory['Directory-Info']['Valid-Until']
    if va != validAfter:
        raise BadVote("Validity date is wrong (%s)"%formatDate(va))
    elif vu != previousMidnight(va+24*60*60+60):
        raise BadVote("Validity span is not 1 day long (ends at %s)"%
                      formatDate(vu))

    # Is everything sorted right?
    for vs in ['MixminionClient', 'MixminionServer']:
        versions = directory['Recommended-Software'][vs]
        if not versionListIsSorted(versions):
            raise BadVote("%s:%s is not in correct sorted order"%(vs,versions))
    if not serverListIsSorted(directory.getAllServers()):
        raise BadVote("Server descriptors are not in correct sorted order")
示例#21
0
def checkVoteDirectory(voters, validAfter, directory):
    # my (sorted, uniqd) list of voters, SignedDirectory instance, URL

    # Is there a single signature?
    sigs = directory.getSignatures()
    if len(sigs) == 0:
        raise BadVote("No signatures")
    elif len(sigs) > 1:
        raise BadVote("Too many signatures")
    sig = sigs[0]

    ident = sig['Signed-Directory']['Directory-Identity']
    keyid = mixminion.Crypto.pk_fingerprint(ident)

    # Do we recognize the signing key?
    for k,_ in voters:
        if k == keyid:
            break
    else:
        raise BadVote("Unknown identity key (%s)"%keyid)

    # Is the signature valid?
    if not sig.checkSignature():
        raise BadVote("Invalid signature")

    # Is the version valid?
    if (directory['Directory-Info']['Version'] !=
        mixminion.ServerInfo._DirectoryInfo.VERSION):
        raise BadVote("Unrecognized version (%s)")

    # Is the directory marked as a vote?
    if directory['Directory-Info']['Status'] != 'vote':
        raise BadVote("Not marked as vote")

    # Do we agree about the voters?
    if not _listIsSorted(directory.dirInfo.voters):
        raise BadVote("Voters not sorted")

    vkeys = {}
    for k,u in directory.dirInfo.voters:
        vkeys[k]=u
    mykeys = {}
    for k,u in voters: mykeys[k]=u

    for k,u in directory.dirInfo.voters:
        try:
            if mykeys[k] != u:
                raise BadVote("Mismatched URL for voter %s (%s vs %s)"%(
                    formatBase64(k), u, mykeys[k]))
        except KeyError:
            raise BadVote("Unkown voter %s at %s"%(k,u))
    for k, u in voters:
        if not vkeys.has_key(k):
            raise BadVote("Missing voter %s at %s"%(k,u))

    assert directory.dirInfo.voters == voters

    # Are the dates right?
    va = directory['Directory-Info']['Valid-After']
    vu = directory['Directory-Info']['Valid-Until']
    if va != validAfter:
        raise BadVote("Validity date is wrong (%s)"%formatDate(va))
    elif vu != previousMidnight(va+24*60*60+60):
        raise BadVote("Validity span is not 1 day long (ends at %s)"%
                      formatDate(vu))

    # Is everything sorted right?
    for vs in ['MixminionClient', 'MixminionServer']:
        versions = directory['Recommended-Software'][vs]
        if not versionListIsSorted(versions):
            raise BadVote("%s:%s is not in correct sorted order"%(vs,versions))
    if not serverListIsSorted(directory.getAllServers()):
        raise BadVote("Server descriptors are not in correct sorted order")
示例#22
0
 def getAsciiTag(self):
     """Return a base64-representation of this message's decoding handle."""
     return formatBase64(self.tag)
示例#23
0
 def __str__(self):
     return "IP:%s:%s:%s" % (self.ip, self.port, formatBase64(self.keyinfo))