def testPromiscuousConnection(tdir, keysAndNames): # Simulating node to client connection alphaSighex, alphaPrikey, alphaVerhex, alphaPubkey, alphaName, betaSighex, \ betaPrikey, betaVerhex, betaPubkey, betaName = keysAndNames alpha = RoadStack(name=alphaName, ha=genHa(), sigkey=alphaSighex, prikey=hexlify(alphaPrikey), auto=AutoMode.always, basedirpath=tdir) beta = RoadStack(name=betaName, ha=genHa(), main=True, sigkey=betaSighex, prikey=hexlify(betaPrikey), auto=AutoMode.always, basedirpath=tdir) try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha) alpha.addRemote(betaRemote) alpha.join(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testRaetPreSharedKeysPromiscous(tdir): alphaSigner = NaclSigner() betaSigner = NaclSigner() logger.debug("Alpha's verkey {}".format(alphaSigner.verhex)) logger.debug("Beta's verkey {}".format(betaSigner.verhex)) alpha = RoadStack(name='alpha', ha=genHa(), sigkey=alphaSigner.keyhex, auto=AutoMode.always, basedirpath=tdir) beta = RoadStack(name='beta', ha=genHa(), sigkey=betaSigner.keyhex, main=True, auto=AutoMode.always, basedirpath=tdir) try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha, verkey=betaSigner.verhex) alpha.addRemote(betaRemote) alpha.allow(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testRaetPreSharedKeysPromiscous(tdir): alphaSigner = SimpleSigner() betaSigner = SimpleSigner() logger.debug("Alpha's verkey {}".format(alphaSigner.naclSigner.verhex)) logger.debug("Beta's verkey {}".format(betaSigner.naclSigner.verhex)) alpha = RoadStack(name='alpha', ha=genHa(), sigkey=alphaSigner.naclSigner.keyhex, auto=AutoMode.always, basedirpath=tdir) beta = RoadStack(name='beta', ha=genHa(), sigkey=betaSigner.naclSigner.keyhex, main=True, auto=AutoMode.always, basedirpath=tdir) try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha, verkey=betaSigner.naclSigner.verhex) alpha.addRemote(betaRemote) alpha.allow(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testRaetPreSharedKeysNonPromiscous(tdir): alphaSigner = SimpleSigner() betaSigner = SimpleSigner() alphaPrivateer = Privateer() betaPrivateer = Privateer() logger.debug("Alpha's verkey {}".format(alphaSigner.naclSigner.verhex)) logger.debug("Beta's verkey {}".format(betaSigner.naclSigner.verhex)) alpha = RoadStack(name='alpha', ha=genHa(), sigkey=alphaSigner.naclSigner.keyhex, prikey=alphaPrivateer.keyhex, auto=AutoMode.never, basedirpath=tdir) beta = RoadStack(name='beta', ha=genHa(), sigkey=betaSigner.naclSigner.keyhex, prikey=betaPrivateer.keyhex, main=True, auto=AutoMode.never, basedirpath=tdir) alpha.keep.dumpRemoteRoleData( { "acceptance": Acceptance.accepted.value, "verhex": betaSigner.naclSigner.verhex, "pubhex": betaPrivateer.pubhex }, "beta") beta.keep.dumpRemoteRoleData( { "acceptance": Acceptance.accepted.value, "verhex": alphaSigner.naclSigner.verhex, "pubhex": alphaPrivateer.pubhex }, "alpha") try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha) alpha.addRemote(betaRemote) alpha.allow(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testRaetPreSharedKeysNonPromiscous(tdir): alphaSigner = SimpleSigner() betaSigner = SimpleSigner() alphaPrivateer = Privateer() betaPrivateer = Privateer() logger.debug("Alpha's verkey {}".format(alphaSigner.verkey)) logger.debug("Beta's verkey {}".format(betaSigner.verkey)) alpha = RoadStack(name='alpha', ha=genHa(), sigkey=alphaSigner.naclSigner.keyhex, prikey=alphaPrivateer.keyhex, auto=AutoMode.never, basedirpath=tdir) beta = RoadStack(name='beta', ha=genHa(), sigkey=betaSigner.naclSigner.keyhex, prikey=betaPrivateer.keyhex, main=True, auto=AutoMode.never, basedirpath=tdir) alpha.keep.dumpRemoteRoleData({ "acceptance": Acceptance.accepted.value, "verhex": betaSigner.verkey, "pubhex": betaPrivateer.pubhex }, "beta") beta.keep.dumpRemoteRoleData({ "acceptance": Acceptance.accepted.value, "verhex": alphaSigner.verkey, "pubhex": alphaPrivateer.pubhex }, "alpha") try: betaRemote = raet.road.estating.RemoteEstate(stack=alpha, ha=beta.ha) alpha.addRemote(betaRemote) alpha.allow(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testNonPromiscousConnectionWithOneKey(tdir, keysAndNames): # Simulating node to node connection alphaSighex, alphaPrikey, alphaVerhex, alphaPubkey, alphaName, betaSighex,\ betaPrikey, betaVerhex, betaPubkey, betaName = keysAndNames alpha = RoadStack(name=alphaName, ha=genHa(), sigkey=alphaSighex, prikey=hexlify(alphaPrikey), auto=AutoMode.never, basedirpath=tdir) beta = RoadStack(name=betaName, ha=genHa(), sigkey=betaSighex, prikey=hexlify(betaPrikey), main=True, auto=AutoMode.never, basedirpath=tdir) alpha.keep.dumpRemoteRoleData( { "acceptance": Acceptance.accepted.value, "verhex": betaVerhex, "pubhex": hexlify(betaPubkey) }, betaName) beta.keep.dumpRemoteRoleData( { "acceptance": Acceptance.accepted.value, "verhex": alphaVerhex, "pubhex": hexlify(alphaPubkey) }, alphaName) try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha) alpha.addRemote(betaRemote) alpha.allow(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testNonPromiscousConnectionWithOneKey(tdir, keysAndNames): # Simulating node to node connection alphaSighex, alphaPrikey, alphaVerhex, alphaPubkey, alphaName, betaSighex,\ betaPrikey, betaVerhex, betaPubkey, betaName = keysAndNames alpha = RoadStack(name=alphaName, ha=genHa(), sigkey=alphaSighex, prikey=hexlify(alphaPrikey), auto=AutoMode.never, basedirpath=tdir) beta = RoadStack(name=betaName, ha=genHa(), sigkey=betaSighex, prikey=hexlify(betaPrikey), main=True, auto=AutoMode.never, basedirpath=tdir) alpha.keep.dumpRemoteRoleData({ "acceptance": Acceptance.accepted.value, "verhex": betaVerhex, "pubhex": hexlify(betaPubkey) }, betaName) beta.keep.dumpRemoteRoleData({ "acceptance": Acceptance.accepted.value, "verhex": alphaVerhex, "pubhex": hexlify(alphaPubkey) }, alphaName) try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha) alpha.addRemote(betaRemote) alpha.allow(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
def testPromiscuousConnection(tdir): alpha = RoadStack(name='alpha', ha=genHa(), auto=AutoMode.always, basedirpath=tdir) beta = RoadStack(name='beta', ha=genHa(), main=True, auto=AutoMode.always, basedirpath=tdir) try: betaRemote = RemoteEstate(stack=alpha, ha=beta.ha) alpha.addRemote(betaRemote) alpha.join(uid=betaRemote.uid, cascade=True) handshake(alpha, beta) sendMsgs(alpha, beta, betaRemote) finally: cleanup(alpha, beta)
class RStack(NetworkInterface): def __init__(self, *args, **kwargs): checkPortAvailable(kwargs['ha']) basedirpath = kwargs.get('basedirpath') authMode = kwargs.pop('auth_mode', None) kwargs['auto'] = self._getAuto(authMode) keep = RoadKeep(basedirpath=basedirpath, stackname=kwargs['name'], auto=kwargs.get('auto'), baseroledirpath=basedirpath) # type: RoadKeep kwargs['keep'] = keep localRoleData = keep.loadLocalRoleData() sighex = kwargs.pop('sighex', None) or localRoleData['sighex'] if not sighex: (sighex, _), (prihex, _) = getEd25519AndCurve25519Keys() else: prihex = ed25519SkToCurve25519(sighex, toHex=True) kwargs['sigkey'] = sighex kwargs['prikey'] = prihex self.msgHandler = kwargs.pop('msgHandler', None) # type: Callable # if no timeout is set then message will never timeout self.messageTimeout = kwargs.pop('messageTimeout', 0) self.raetStack = RoadStack(*args, **kwargs) if self.ha[1] != kwargs['ha'].port: error("the stack port number has changed, likely due to " "information in the keep. {} passed {}, actual {}".format( kwargs['name'], kwargs['ha'].port, self.ha[1])) self._created = time.perf_counter() self.coro = None self._conns = set() # type: Set[str] def _getAuto(self, authMode): if authMode == AuthMode.ALLOW_ANY.value: return AutoMode.always if authMode == AuthMode.RESTRICTED.value: return AutoMode.never return None def __repr__(self): return self.name @property def name(self): return self.raetStack.name @property def remotes(self): return self.raetStack.remotes @property def created(self): return self._created @property def rxMsgs(self): return self.raetStack.rxMsgs @staticmethod def isRemoteConnected(r) -> bool: """ A node is considered to be connected if it is joined, allowed and alived. :param r: the remote to check """ return r.joined and r.allowed and r.alived @staticmethod def initLocalKeys(name, baseDir, sigseed, override=False): """ Initialize RAET local keep. Write local role data to file. :param name: name of the node :param baseDir: base directory :param pkseed: seed to generate public and private key pair :param sigseed: seed to generate signing and verification key pair :param override: overwrite the local role.json file if already exists :return: tuple(public key, verification key) """ rolePath = os.path.join(baseDir, name, "role", "local", "role.json") if os.path.isfile(rolePath): if not override: raise FileExistsError( "Keys exists for local role {}".format(name)) if sigseed and not isinstance(sigseed, bytes): sigseed = sigseed.encode() signer = Signer(sigseed) keep = RoadKeep(stackname=name, baseroledirpath=baseDir) sigkey, verkey = signer.keyhex, signer.verhex prikey, pubkey = ed25519SkToCurve25519(sigkey, toHex=True), \ ed25519PkToCurve25519(verkey, toHex=True) data = OrderedDict([("role", name), ("prihex", prikey), ("sighex", sigkey)]) keep.dumpLocalRoleData(data) return pubkey.decode(), verkey.decode() @staticmethod def initRemoteKeys(name, remoteName, baseDir, verkey, override=False): """ Initialize RAET remote keep :param name: name of the node :param remoteName: name of the remote to store keys for :param baseDir: base directory :param pubkey: public key of the remote :param verkey: private key of the remote :param override: overwrite the role.remoteName.json file if it already exists. """ rolePath = os.path.join(baseDir, name, "role", "remote", "role.{}.json".format(remoteName)) if os.path.isfile(rolePath): if not override: raise FileExistsError( "Keys exists for remote role {}".format(remoteName)) keep = RoadKeep(stackname=name, baseroledirpath=baseDir) data = OrderedDict([('role', remoteName), ('acceptance', 1), ('pubhex', ed25519PkToCurve25519(verkey, toHex=True)), ('verhex', verkey)]) keep.dumpRemoteRoleData(data, role=remoteName) def onHostAddressChanged(self): logger.debug( "{} clearing local data in keep as host address changed".format( self.name)) self.raetStack.keep.clearLocalData() @staticmethod def areKeysSetup(name, baseDir): """ Check that the local RAET keep has the values of role, sighex and prihex populated for the given node :param name: the name of the node to check the keys for :param baseDir: base directory of Plenum :return: whether the keys are setup """ localRoleData = getLocalKeep(name=name, baseDir=baseDir) for key in ['role', 'sighex', 'prihex']: if localRoleData.get(key) is None: return False return True @staticmethod def learnKeysFromOthers(baseDir, name, others): pass @staticmethod def getHaFromLocal(name, basedirpath): localEstate = getLocalEstateData(name, basedirpath) if localEstate: return localEstate.get("ha") def tellKeysToOthers(self, others): pass def getRemote(self, name: str = None, ha: HA = None): """ Find the remote by name or ha. :param name: the name of the remote to find :param ha: host address pair the remote to find :raises: RemoteNotFound """ return self.findInRemotesByHA(ha) if ha else \ self.findInRemotesByName(name) def connect(self, name=None, remoteId=None, ha=None, verKeyRaw=None, publicKeyRaw=None): """ Connect to the node specified by name. :param name: name of the node to connect to :type name: str or (HA, tuple) :return: the uid of the remote estate, or None if a connect is not attempted """ # if not self.isKeySharing: # logger.debug("{} skipping join with {} because not key sharing". # format(self, name)) # return None if not remoteId and not ha: raise ValueError( 'Either Host Address or Remote ID must be provided to connect to a node in Raet stack' ) if remoteId: remote = self.remotes[remoteId] return self._doConnectRemote(remote, name) else: return self._doConnectByHA(ha, name) def _doConnectByHA(self, ha, name=None): remote = RemoteEstate(stack=self.raetStack, ha=ha) self.raetStack.addRemote(remote) return self._doConnectRemote(remote, name) def _doConnectRemote(self, remote, name=None): # updates the store time so the join timer is accurate self.updateStamp() self.raetStack.join(uid=remote.uid, cascade=True, timeout=30) logger.info("{} looking for {} at {}:{}".format( self, name or remote.name, *remote.ha), extra={ "cli": "PLAIN", "tags": ["node-looking"] }) return remote.uid def removeRemote(self, r): self.raetStack.removeRemote(r) def transmit(self, msg, uid, timeout=None): self.raetStack.transmit(msg, uid, timeout=timeout) @property def ha(self): return self.raetStack.ha def start(self): if not self.opened: self.open() logger.info("stack {} starting at {} in {} mode".format( self, self.ha, self.raetStack.keep.auto), extra={"cli": False}) # self.coro = self._raetcoro() self.coro = self._raetcoro def stop(self): if self.opened: self.close() self.coro = None logger.info("stack {} stopped".format(self.name), extra={"cli": False}) async def service(self, limit=None) -> int: """ Service `limit` number of received messages in this stack. :param limit: the maximum number of messages to be processed. If None, processes all of the messages in rxMsgs. :return: the number of messages processed. """ pracLimit = limit if limit else sys.maxsize if self.coro: # x = next(self.coro) x = await self.coro() if x > 0: for x in range(pracLimit): try: self.msgHandler(self.raetStack.rxMsgs.popleft()) except IndexError: break return x else: logger.debug("{} is stopped".format(self)) return 0 # def _raetcoro(self): # """ # Generator to service all messages. # Yields the length of rxMsgs queue of this stack. # """ # while True: # try: # self._serviceStack(self.age) # l = len(self.rxMsgs) # except Exception as ex: # if isinstance(ex, OSError) and \ # len(ex.args) > 0 and \ # ex.args[0] == 22: # logger.error("Error servicing stack {}: {}. This could be " # "due to binding to an internal network " # "and trying to route to an external one.". # format(self.name, ex), extra={'cli': 'WARNING'}) # else: # logger.error("Error servicing stack {}: {} {}". # format(self.name, ex, ex.args), # extra={'cli': 'WARNING'}) # # l = 0 # yield l async def _raetcoro(self): try: await self._serviceStack(self.age) l = len(self.raetStack.rxMsgs) except Exception as ex: if isinstance(ex, OSError) and \ len(ex.args) > 0 and \ ex.args[0] == 22: logger.error("Error servicing stack {}: {}. This could be " "due to binding to an internal network " "and trying to route to an external one.".format( self.name, ex), extra={'cli': 'WARNING'}) else: logger.error("Error servicing stack {}: {} {}".format( self.name, ex, ex.args), extra={'cli': 'WARNING'}) l = 0 return l async def _serviceStack(self, age): """ Update stacks clock and service all tx and rx messages. :param age: update timestamp of this RoadStack to this value """ self.updateStamp(age) self.raetStack.serviceAll() def updateStamp(self, age=None): """ Change the timestamp of this stack's test store. :param age: the timestamp will be set to this value """ self.raetStack.store.changeStamp(age if age else self.age) @property def opened(self): return self.raetStack.server.opened def open(self): """ Open the UDP socket of this stack's server. """ self.raetStack.server.open() # close the UDP socket def close(self): """ Close the UDP socket of this stack's server. """ self.raetStack.server.close() # close the UDP socket @property def isKeySharing(self): return self.raetStack.keep.auto != AutoMode.never @property def verhex(self): return self.raetStack.local.signer.verhex @property def keyhex(self): return self.raetStack.local.signer.keyhex @property def pubhex(self): return self.raetStack.local.priver.pubhex @property def prihex(self): return self.raetStack.local.priver.keyhex def send(self, msg: Any, remoteName: str, ha=None): """ Transmit the specified message to the remote specified by `remoteName`. :param msg: a message :param remoteName: the name of the remote """ rid = self.getRemote(remoteName, ha).uid # Setting timeout to never expire self.raetStack.transmit(msg, rid, timeout=self.messageTimeout)