def _generateDirectory(identity, status, servers, goodServerNames, voters, validAfter, clientVersions, serverVersions): assert status in ("vote", "consensus") va = formatDate(previousMidnight(validAfter)) vu = formatDate(previousMidnight(validAfter)+24*60*60+5) rec = [ s.lower() for s in goodServerNames[:] ] rec.sort() rec = ", ".join(rec) v = [] voters.sort() for keyid, urlbase in voters: v.append("Voting-Server: %s %s\n" % (keyid, urlbase)) servers = sortServerList(servers) cvers = ", ".join(sortVersionList(clientVersions)) svers = ", ".join(sortVersionList(serverVersions)) dirInfo = ("[Directory-Info]\n" "Version: 0.3\n" "Status: %s\n" "Valid-After: %s\n" "Valid-Until: %s\n" "Recommended-Servers: %s\n%s" "[Recommended-Software]\n" "MixminionClient: %s\n" "MixminionServer: %s\n")%(status, va, vu, rec, "".join(v), cvers, svers) unsigned = "".join([dirInfo]+[s._originalContents for s in servers]) signature = getDirectorySignature(unsigned, identity) return signature+unsigned
def createKeys(self, num=1, startAt=None): """Generate 'num' public keys for this server. If startAt is provided, make the first key become valid at 'startAt'. Otherwise, make the first key become valid right after the last key we currently have expires. If we have no keys now, make the first key start now.""" # FFFF Use this. #password = None if startAt is None: if self.keySets: startAt = self.keySets[-1][1] + 60 if startAt < time.time(): startAt = time.time() + 60 else: startAt = time.time() + 60 startAt = previousMidnight(startAt) firstKey, lastKey = self.keyRange for _ in xrange(num): if firstKey == sys.maxint: keynum = firstKey = lastKey = 1 elif firstKey > 1: firstKey -= 1 keynum = firstKey else: lastKey += 1 keynum = lastKey keyname = "%04d" % keynum lifetime = self.config['Server']['PublicKeyLifetime'].getSeconds() nextStart = startAt + lifetime LOG.info("Generating key %s to run from %s through %s (GMT)", keyname, formatDate(startAt), formatDate(nextStart - 3600)) generateServerDescriptorAndKeys(config=self.config, identityKey=self.getIdentityKey(), keyname=keyname, keydir=self.keyDir, hashdir=self.hashDir, validAt=startAt) startAt = nextStart self.checkKeys()
def createKeys(self, num=1, startAt=None): """Generate 'num' public keys for this server. If startAt is provided, make the first key become valid at 'startAt'. Otherwise, make the first key become valid right after the last key we currently have expires. If we have no keys now, make the first key start now.""" # FFFF Use this. #password = None if startAt is None: if self.keySets: startAt = self.keySets[-1][1]+60 if startAt < time.time(): startAt = time.time()+60 else: startAt = time.time()+60 startAt = previousMidnight(startAt) firstKey, lastKey = self.keyRange for _ in xrange(num): if firstKey == sys.maxint: keynum = firstKey = lastKey = 1 elif firstKey > 1: firstKey -= 1 keynum = firstKey else: lastKey += 1 keynum = lastKey keyname = "%04d" % keynum lifetime = self.config['Server']['PublicKeyLifetime'].getSeconds() nextStart = startAt + lifetime LOG.info("Generating key %s to run from %s through %s (GMT)", keyname, formatDate(startAt), formatDate(nextStart-3600)) generateServerDescriptorAndKeys(config=self.config, identityKey=self.getIdentityKey(), keyname=keyname, keydir=self.keyDir, hashdir=self.hashDir, validAt=startAt) startAt = nextStart self.checkKeys()
def getDeadKeys(self, now=None): """Helper function: return a list of (informative-message, keyset object) for each expired keyset in the keystore. Does not rescan the keystore or remove dead keys. """ if now is None: now = time.time() expiryStr = " expired" else: expiryStr = "" cutoff = now - self.keyOverlap result = [] for va, vu, keyset in self.keySets: if vu >= cutoff: continue name = keyset.keyname message = "Removing%s key %s (valid from %s through %s)" % ( expiryStr, name, formatDate(va), formatDate(vu)) result.append((message, keyset)) return result
def getDeadKeys(self,now=None): """Helper function: return a list of (informative-message, keyset object) for each expired keyset in the keystore. Does not rescan the keystore or remove dead keys. """ if now is None: now = time.time() expiryStr = " expired" else: expiryStr = "" cutoff = now - self.keyOverlap result = [] for va, vu, keyset in self.keySets: if vu >= cutoff: continue name = keyset.keyname message ="Removing%s key %s (valid from %s through %s)"%( expiryStr, name, formatDate(va), formatDate(vu)) result.append((message, keyset)) return result
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")
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))
class ServerKeyring: """A ServerKeyring remembers current and future keys, descriptors, and hash logs for a mixminion server. It keeps track of key rotation schedules, and generates new keys as needed. """ ## Fields: # homeDir: server home directory # keyDir: server key directory # keyOverlap: How long after a new key begins do we accept the old one? # keySets: sorted list of (start, end, keyset) # nextUpdate: time_t when a new key should be added, or a current key # should be removed, or "None" for uncalculated. # keyRange: tuple of (firstKey, lastKey) to represent which key names # have keys on disk. # currentKeys: None, if we haven't checked for currently live keys, or # a list of currently live ServerKeyset objects. # dhFile: pathname to file holding diffie-helman parameters. # _lock: A lock to prevent concurrent key generation or rotation. def __init__(self, config): "Create a ServerKeyring from a config object" self._lock = threading.RLock() self.configure(config) def configure(self, config): "Set up a ServerKeyring from a config object" self.config = config self.homeDir = config.getBaseDir() self.keyDir = config.getKeyDir() self.hashDir = os.path.join(config.getWorkDir(), 'hashlogs') self.dhFile = os.path.join(config.getWorkDir(), 'tls', 'dhparam') self.certFile = os.path.join(config.getWorkDir(), "cert_chain") self.keyOverlap = config['Server']['PublicKeyOverlap'].getSeconds() self.nickname = config['Server']['Nickname'] #DOCDOC self.nextUpdate = None self.currentKeys = None self._tlsContext = None #DOCDOC self._tlsContextExpires = -1 #DOCDOC self.pingerSeed = None self.checkKeys() def checkKeys(self): """Internal method: read information about all this server's currently-prepared keys from disk. May raise ConfigError if any of the server descriptors on disk are invalid. """ self.keySets = [] badKeySets = [] firstKey = sys.maxint lastKey = 0 LOG.debug("Scanning server keystore at %s", self.keyDir) if not os.path.exists(self.keyDir): LOG.info("Creating server keystore at %s", self.keyDir) createPrivateDir(self.keyDir) # Iterate over the entires in HOME/keys for dirname in os.listdir(self.keyDir): # Skip any that aren't directories named "key_INT" if not os.path.isdir(os.path.join(self.keyDir, dirname)): continue if not dirname.startswith('key_'): LOG.warn("Unexpected directory %s under %s", dirname, self.keyDir) continue keysetname = dirname[4:] try: setNum = int(keysetname) # keep trace of the first and last used key number if setNum < firstKey: firstKey = setNum if setNum > lastKey: lastKey = setNum except ValueError: LOG.warn("Unexpected directory %s under %s", dirname, self.keyDir) continue # Find the server descriptor... keyset = ServerKeyset(self.keyDir, keysetname, self.hashDir) ok = 1 try: keyset.checkKeys() except MixError, e: LOG.warn("Error checking private keys in keyset %s: %s", keysetname, str(e)) ok = 0 try: if ok: keyset.getServerDescriptor() except (ConfigError, IOError), e: LOG.warn("Key set %s has invalid/missing descriptor: %s", keysetname, str(e)) ok = 0 if ok: t1, t2 = keyset.getLiveness() self.keySets.append((t1, t2, keyset)) LOG.trace("Found key %s (valid from %s to %s)", dirname, formatDate(t1), formatDate(t2)) else: badKeySets.append(keyset)
LOG.warn("Removing %s invalid keysets", len(badKeySets)) for b in badKeySets: b.delete() # Now, sort the key intervals by starting time. self.keySets.sort() self.keyRange = (firstKey, lastKey) # Now we try to see whether we have more or less than 1 key in effect # for a given time. for idx in xrange(len(self.keySets) - 1): end = self.keySets[idx][1] start = self.keySets[idx + 1][0] if start < end: LOG.warn("Multiple keys for %s. That's unsupported.", formatDate(end)) elif start > end: LOG.warn("Gap in key schedule: no key from %s to %s", formatDate(end), formatDate(start)) def checkDescriptorConsistency(self, regen=1): """Check whether the server descriptors in this keyring are consistent with the server's configuration. If 'regen' is true, inconsistent descriptors are regenerated.""" identity = None state = [] for _, _, ks in self.keySets: ok = ks.checkConsistency(self.config, 0) if ok == 'good': continue state.append((ok, ks))
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()
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()
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))
LOG.warn("Removing %s invalid keysets", len(badKeySets)) for b in badKeySets: b.delete() # Now, sort the key intervals by starting time. self.keySets.sort() self.keyRange = (firstKey, lastKey) # Now we try to see whether we have more or less than 1 key in effect # for a given time. for idx in xrange(len(self.keySets)-1): end = self.keySets[idx][1] start = self.keySets[idx+1][0] if start < end: LOG.warn("Multiple keys for %s. That's unsupported.", formatDate(end)) elif start > end: LOG.warn("Gap in key schedule: no key from %s to %s", formatDate(end), formatDate(start)) def checkDescriptorConsistency(self, regen=1): """Check whether the server descriptors in this keyring are consistent with the server's configuration. If 'regen' is true, inconsistent descriptors are regenerated.""" identity = None state = [] for _,_,ks in self.keySets: ok = ks.checkConsistency(self.config, 0) if ok == 'good': continue state.append((ok, ks))