From ca64b5927790eb13979a018835fadb13c5879c8b Mon Sep 17 00:00:00 2001 From: Salvatore Ingala <6681844+bigspider@users.noreply.github.com> Date: Fri, 18 Oct 2019 13:18:39 +0800 Subject: [PATCH] Added signature verification to pisa_cli --- apps/cli/__init__.py | 2 ++ apps/cli/pisa-cli.py | 39 +++++++++++++++++++++++++++++++++++++-- pisa/watcher.py | 4 ++-- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/apps/cli/__init__.py b/apps/cli/__init__.py index 20bb9fb..0be0f2a 100644 --- a/apps/cli/__init__.py +++ b/apps/cli/__init__.py @@ -11,6 +11,8 @@ CLIENT_LOG_FILE = 'pisa.log' SUPPORTED_HASH_FUNCTIONS = ["SHA256"] SUPPORTED_CIPHERS = ["AES-GCM-128"] +PUBLIC_KEY_FILE = "signing_key_pub.pem" + # Configure logging logging.basicConfig(format='%(message)s', level=logging.INFO, handlers=[ logging.FileHandler(CLIENT_LOG_FILE), diff --git a/apps/cli/pisa-cli.py b/apps/cli/pisa-cli.py index 8b181a1..beb7298 100644 --- a/apps/cli/pisa-cli.py +++ b/apps/cli/pisa-cli.py @@ -9,14 +9,25 @@ from binascii import unhexlify from getopt import getopt, GetoptError from requests import ConnectTimeout, ConnectionError +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.serialization import load_pem_public_key +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.exceptions import InvalidSignature + from pisa.logger import Logger from apps.cli.blob import Blob from apps.cli.help import help_add_appointment, help_get_appointment -from apps.cli import DEFAULT_PISA_API_SERVER, DEFAULT_PISA_API_PORT +from apps.cli import DEFAULT_PISA_API_SERVER, DEFAULT_PISA_API_PORT, PUBLIC_KEY_FILE +HTTP_OK = 200 logger = Logger("Client") +with open(PUBLIC_KEY_FILE, "r") as key_file: + pubkey_pem = key_file.read().encode("utf-8") + pisa_public_key = load_pem_public_key(pubkey_pem, backend=default_backend()) + # FIXME: TESTING ENDPOINT, WON'T BE THERE IN PRODUCTION def generate_dummy_appointment(): @@ -75,13 +86,37 @@ def add_appointment(args): try: r = requests.post(url=add_appointment_endpoint, json=json.dumps(appointment), timeout=5) - logger.info("{} (code: {}).".format(r.text, r.status_code)) + logger.info("{} (code: {}).".format(r.json(), r.status_code)) + + response_json = r.json() + + if r.status_code == HTTP_OK: + if 'signature' not in response_json: + logger.error("The response does not contain the signature of the appointment.") + else: + # verify that the returned signature is valid + signature = response_json['signature'] + pisa_public_key.verify(signature.encode("utf-8"), data, ec.ECDSA(hashes.SHA256())) + else: + if 'error' not in response_json: + logger.error("The server returned status code {}, but no error description." + .format(r.status_code)) + else: + error = r.json()['error'] + logger.error("The server returned status code {}, and the following error: {}." + .format(r.status_code)) + + except json.JSONDecodeError: + logger.error("The response was not valid JSON.") except ConnectTimeout: logger.error("Can't connect to pisa API. Connection timeout.") except ConnectionError: logger.error("Can't connect to pisa API. Server cannot be reached.") + + except InvalidSignature: + logger.error("The returned appointment's signature is invalid.") else: logger.error("The provided locator is not valid.") else: diff --git a/pisa/watcher.py b/pisa/watcher.py index eee3159..91a9cf0 100644 --- a/pisa/watcher.py +++ b/pisa/watcher.py @@ -31,8 +31,8 @@ class Watcher: raise ValueError("No signing key provided. Please fix your pisa.conf") else: with open(SIGNING_KEY_FILE, "r") as key_file: - pubkey_pem = key_file.read().encode("utf-8") - self.signing_key = load_pem_private_key(pubkey_pem, password=None, backend=default_backend()) + privkey_pem = key_file.read().encode("utf-8") + self.signing_key = load_pem_private_key(privkey_pem, password=None, backend=default_backend()) def add_appointment(self, appointment): # Rationale: