From e7895235b29c1774da9e78790c10413e127396c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pascal=20Eng=C3=A9libert?= <tuxmain@zettascript.org>
Date: Fri, 7 Jun 2019 19:14:01 +0200
Subject: [PATCH] Peer validity tests

---
 server.py |  4 ++++
 utils.py  | 59 ++++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/server.py b/server.py
index e2ed925..75d1767 100644
--- a/server.py
+++ b/server.py
@@ -56,6 +56,7 @@ MIX_REQ_AGE_MAX = 604800 # maximum mix request age before return to sender
 PEER_INFO_INTERVAL = 600 # interval for renewing my peer document
 PEER_SIG_AGE_MAX = 604800 # max age of a peer document signature
 PEER_DETECT_INTERVAL = 120 # interval for fetching peer list
+IDTY_SIG_AGE_MAX = 2592000 # max age of a idty document signature
 CURRENCY = "g1"
 
 def send_response(client, code, resp, dataformat="ubjson"):
@@ -190,6 +191,7 @@ def read_config(cdir, conf_overwrite={}):
 	conf["server"].setdefault("peer_info_interval", PEER_INFO_INTERVAL)
 	conf["server"].setdefault("peer_sig_age_max", PEER_SIG_AGE_MAX)
 	conf["server"].setdefault("peer_detect_interval", PEER_DETECT_INTERVAL)
+	conf["server"].setdefault("idty_sig_age_max", IDTY_SIG_AGE_MAX)
 	conf.setdefault("client", {})
 	conf["client"].setdefault("bma_hosts", BMA_HOSTS)
 	conf["client"].setdefault("proxy", None)
@@ -985,6 +987,8 @@ if __name__ == "__main__":
 		
 		# Generate peer info
 		local_peer = utils.Peer.generate(conf, keys)
+		if local_peer == None:
+			exit()
 		
 		peer_file = open(os.path.expanduser(utils.getargv("-e", "peer_info.ubjson")), "wb")
 		peer_file.write(ubjson.dumpb([local_peer.raw]))
diff --git a/utils.py b/utils.py
index de4e5db..28b7deb 100644
--- a/utils.py
+++ b/utils.py
@@ -132,29 +132,62 @@ def run_async(coro):
 
 #-------- ÄžMixer
 
+def verify_idty_sig(conf, raw, idty_pubkey, peer_pubkey):
+	try:
+		raw = libnacl.sign.Verifier(PublicKey(idty_pubkey).hex_pk()).verify(raw)
+		data = ubjson.loadb(raw)
+		assert data["doctype"] == "gmixer/idtysig" , "Bad doctype"
+		assert data["docver"] == "1" , "Bad docver"
+		assert data["pubkey"] == peer_pubkey , "Bad pubkey"
+		t = time.time()
+		assert data["sigtime"] < t and data["sigtime"] + conf["server"]["idty_sig_age_max"] > t , "Bad sigtime"
+	except (ValueError, IndexError, ubjson.decoder.DecoderException, AssertionError) as e:
+		logprint("Bad idty sig: "+str(e), LOG_TRACE)
+		return False
+	return True
+
 class Peer:
 	VERSION = "1"
 	def __init__(self, conf:dict, raw:bytes):
 		self.rectime = time.time()
 		self.raw = raw
-		data = ubjson.loadb(raw)
+		try:
+			data = ubjson.loadb(raw)
+		except ubjson.decoder.DecoderException:
+			raise AssertionError("Bad wrapper encoding")
+		
+		assert "pubkey" in data and "raw" in data , "Missing values in wrapper"
 		pubkey = data["pubkey"]
-		raw = libnacl.sign.Verifier(PublicKey(pubkey).hex_pk()).verify(data["raw"])
-		data = ubjson.loadb(raw)
-		# TODO try except
+		try:
+			raw = libnacl.sign.Verifier(PublicKey(pubkey).hex_pk()).verify(data["raw"])
+		except ValueError:
+			raise AssertionError("Bad signature")
+		try:
+			data = ubjson.loadb(raw)
+		except ubjson.decoder.DecoderException:
+			raise AssertionError("Bad data encoding")
+		
+		assert "doctype" in data and "docver" in data and "currency" in data and "pubkey" in data and "sigtime" in data and "host" in data and "idty" in data and "idtysig" in data ,\
+		       "Missing values in data"
+		
+		assert data["doctype"] == "gmixer/peer" , "Bad doctype"
+		assert data["docver"] == Peer.VERSION , "Bad docver"
+		assert data["currency"] == conf["currency"] , "Different currency"
+		assert data["pubkey"] == pubkey , "Different pubkey"
+		assert isinstance(data["sigtime"], (int, float)) , "Bad sigtime"
+		assert data["sigtime"] < self.rectime , "Futuristic sigtime"
 		
-		# TODO tests
-		assert data["currency"] == conf["currency"] , "Not the same currency"
 		if conf["idty"]["needed"]:
-			assert run_async(check_idty(conf["client"]["bma_hosts"], data["idty"]))
+			assert run_async(check_idty(conf["client"]["bma_hosts"], data["idty"])) , "Idty is not member"
+			assert verify_idty_sig(conf, data["idtysig"], data["idty"], pubkey) , "Bad idty sig"
 		
 		self.doctype = data["doctype"]
 		self.docver = data["docver"]
 		self.pubkey = data["pubkey"]
-		self.sigtime = data["sigtime"] 
+		self.sigtime = data["sigtime"]
 		self.host = tuple(data["host"]) # socket cannot manage lists
 		self.idty = data["idty"]
-		self.idtysig = data["idtysig"]
+		self.idtysig = data["idtysig"]# TODO check
 		
 		self.hash = hashlib.sha512((self.pubkey+"@"+self.host[0]+":"+str(self.host[1])).encode()).digest()
 		self.keys = PublicKey(self.pubkey)
@@ -165,7 +198,7 @@ class Peer:
 	
 	def generate(conf:dict, keys:SigningKey) -> bytes:
 		data = {
-			"doctype": "peer",
+			"doctype": "gmixer/peer",
 			"docver": Peer.VERSION,
 			"currency": conf["currency"],
 			"pubkey": keys.pubkey,
@@ -182,7 +215,8 @@ class Peer:
 		raw = ubjson.dumpb(data)
 		try:
 			return Peer(conf, raw)
-		except AssertionError:
+		except AssertionError as e:
+			logprint("Gen peer: "+str(e), LOG_ERROR)
 			return None
 
 def load_peers(conf:dict, db_peers:plyvel.DB, peers:dict):
@@ -207,9 +241,6 @@ async def bma_client(bma_endpoints:list):
 			client = None
 	return client
 
-#async def check_idty(client:Client, pubkey:str):
-#	print( await client(bma.wot.lookup, pubkey))
-
 async def check_idty(bma_endpoints:list, pubkey:str):
 	client = await bma_client(bma_endpoints)
 	try:
-- 
GitLab